/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id$ */

package org.apache.fop.render.afp;

import java.awt.Rectangle;
import java.awt.color.ColorSpace;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.ImageSize;
import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
import org.apache.xmlgraphics.image.loader.impl.JPEGConstants;
import org.apache.xmlgraphics.util.MimeConstants;

import org.apache.fop.afp.AFPDataObjectInfo;
import org.apache.fop.afp.AFPImageObjectInfo;
import org.apache.fop.afp.AFPObjectAreaInfo;
import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.AFPResourceInfo;
import org.apache.fop.afp.AFPResourceManager;
import org.apache.fop.afp.ioca.ImageContent;
import org.apache.fop.afp.modca.ResourceObject;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RenderingContext;

ImageHandler implementation which handles ImageRawJPEG instances. JPEG data is embedded directly (not decoded) into IOCA images (FS11 or FS45).
/** * {@link ImageHandler} implementation which handles ImageRawJPEG instances. JPEG data is * embedded directly (not decoded) into IOCA images (FS11 or FS45). */
public class AFPImageHandlerRawJPEG extends AFPImageHandler implements ImageHandler {
logging instance
/** logging instance */
private final Log log = LogFactory.getLog(AFPImageHandlerRawJPEG.class); private void setDefaultResourceLevel(AFPImageObjectInfo imageObjectInfo, AFPResourceManager resourceManager) { AFPResourceInfo resourceInfo = imageObjectInfo.getResourceInfo(); if (!resourceInfo.levelChanged()) { resourceInfo.setLevel(resourceManager.getResourceLevelDefaults() .getDefaultResourceLevel(ResourceObject.TYPE_IMAGE)); } }
{@inheritDoc}
/** {@inheritDoc} */
@Override protected AFPDataObjectInfo createDataObjectInfo() { return new AFPImageObjectInfo(); }
{@inheritDoc}
/** {@inheritDoc} */
public int getPriority() { return 150; }
{@inheritDoc}
/** {@inheritDoc} */
public Class<?> getSupportedImageClass() { return ImageRawJPEG.class; }
{@inheritDoc}
/** {@inheritDoc} */
public ImageFlavor[] getSupportedImageFlavors() { return new ImageFlavor[] {ImageFlavor.RAW_JPEG}; }
{@inheritDoc}
/** {@inheritDoc} */
public void handleImage(RenderingContext context, Image image, Rectangle pos) throws IOException { AFPRenderingContext afpContext = (AFPRenderingContext)context; AFPDataObjectInfo info = createDataObjectInfo(); assert (info instanceof AFPImageObjectInfo); AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo) info; AFPPaintingState paintingState = afpContext.getPaintingState(); // set resource information imageObjectInfo.setResourceInfo(createResourceInformation( image.getInfo().getOriginalURI(), afpContext.getForeignAttributes())); setDefaultResourceLevel(imageObjectInfo, afpContext.getResourceManager()); // Positioning imageObjectInfo.setObjectAreaInfo(createObjectAreaInfo(paintingState, pos)); updateIntrinsicSize(imageObjectInfo, paintingState, image.getSize()); // Image content ImageRawJPEG jpeg = (ImageRawJPEG)image; imageObjectInfo.setCompression(ImageContent.COMPID_JPEG); ColorSpace cs = jpeg.getColorSpace(); switch (cs.getType()) { case ColorSpace.TYPE_GRAY: imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS11); imageObjectInfo.setColor(false); imageObjectInfo.setBitsPerPixel(8); break; case ColorSpace.TYPE_RGB: imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS11); imageObjectInfo.setColor(true); imageObjectInfo.setBitsPerPixel(24); break; case ColorSpace.TYPE_CMYK: imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS45); imageObjectInfo.setColor(true); imageObjectInfo.setBitsPerPixel(32); break; default: throw new IllegalStateException( "Color space of JPEG image not supported: " + cs); } boolean included = afpContext.getResourceManager().tryIncludeObject(imageObjectInfo); if (!included) { log.debug("Embedding undecoded JPEG as IOCA image..."); InputStream inputStream = jpeg.createInputStream(); try { imageObjectInfo.setData(IOUtils.toByteArray(inputStream)); } finally { IOUtils.closeQuietly(inputStream); } // Create image afpContext.getResourceManager().createObject(imageObjectInfo); } } private void updateIntrinsicSize(AFPImageObjectInfo imageObjectInfo, AFPPaintingState paintingState, ImageSize targetSize) { //Update image object info imageObjectInfo.setDataHeightRes((int)Math.round( targetSize.getDpiHorizontal() * 10)); imageObjectInfo.setDataWidthRes((int)Math.round( targetSize.getDpiVertical() * 10)); imageObjectInfo.setDataHeight(targetSize.getHeightPx()); imageObjectInfo.setDataWidth(targetSize.getWidthPx()); // set object area info int resolution = paintingState.getResolution(); AFPObjectAreaInfo objectAreaInfo = imageObjectInfo.getObjectAreaInfo(); objectAreaInfo.setResolution(resolution); }
{@inheritDoc}
/** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) { if (!(targetContext instanceof AFPRenderingContext)) { return false; //AFP-specific image handler } AFPRenderingContext context = (AFPRenderingContext)targetContext; AFPPaintingState paintingState = context.getPaintingState(); if (!paintingState.canEmbedJpeg()) { return false; } if (paintingState.getBitsPerPixel() < 8) { return false; //This would stand in the way of dithering and cause exceptions } if (image == null) { return true; //Don't know the image format, yet } if (image instanceof ImageRawJPEG) { ImageRawJPEG jpeg = (ImageRawJPEG)image; ColorSpace cs = jpeg.getColorSpace(); switch (cs.getType()) { case ColorSpace.TYPE_GRAY: case ColorSpace.TYPE_RGB: //ok break; case ColorSpace.TYPE_CMYK: if (!paintingState.isCMYKImagesSupported()) { return false; //CMYK is disabled //Note: you may need to disable this image handler through configuration //if you want to paint a CMYK JPEG on 24bit and less configurations. } break; default: return false; //not supported } if (jpeg.getSOFType() != JPEGConstants.SOF0) { return false; //We'll let only baseline DCT through. } return true; } return false; } }