blob: e5f6f64cb2dc3b2152b986d5692afb8cc01f0fa8 [file] [log] [blame]
/*
* 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;
/**
* {@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 */
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} */
@Override
protected AFPDataObjectInfo createDataObjectInfo() {
return new AFPImageObjectInfo();
}
/** {@inheritDoc} */
public int getPriority() {
return 150;
}
/** {@inheritDoc} */
public Class<?> getSupportedImageClass() {
return ImageRawJPEG.class;
}
/** {@inheritDoc} */
public ImageFlavor[] getSupportedImageFlavors() {
return new ImageFlavor[] {ImageFlavor.RAW_JPEG};
}
/** {@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} */
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;
}
}