package org.apache.fop.render.afp;
+ import java.awt.Dimension;
+import java.awt.Rectangle;
import java.awt.image.ColorModel;
import java.awt.image.RenderedImage;
import java.io.IOException;
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.ImageInfo;
+ import org.apache.xmlgraphics.image.loader.ImageSize;
import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
import org.apache.xmlgraphics.ps.ImageEncodingHelper;
import org.apache.xmlgraphics.util.MimeConstants;
import org.apache.fop.afp.AFPImageObjectInfo;
import org.apache.fop.afp.AFPObjectAreaInfo;
import org.apache.fop.afp.AFPPaintingState;
- import org.apache.fop.util.BitmapImageUtil;
+import org.apache.fop.render.ImageHandler;
+import org.apache.fop.render.RenderingContext;
+ import org.apache.fop.util.bitmap.BitmapImageUtil;
/**
* PDFImageHandler implementation which handles RenderedImage instances.
= (AFPRendererContext)rendererImageInfo.getRendererContext();
AFPInfo afpInfo = rendererContext.getInfo();
AFPPaintingState paintingState = afpInfo.getPaintingState();
- updateDataObjectInfo(imageObjectInfo, paintingState, imageRendered);
+ ImageRendered imageRendered = (ImageRendered) rendererImageInfo.img;
++ Dimension targetSize = new Dimension(afpInfo.getWidth(), afpInfo.getHeight());
+
- AFPPaintingState paintingState, ImageRendered imageRendered)
++ updateDataObjectInfo(imageObjectInfo, paintingState, imageRendered, targetSize);
+ return imageObjectInfo;
+ }
+
+ private AFPDataObjectInfo updateDataObjectInfo(AFPImageObjectInfo imageObjectInfo,
++ AFPPaintingState paintingState, ImageRendered imageRendered, Dimension targetSize)
+ throws IOException {
+
int resolution = paintingState.getResolution();
- ImageRendered imageRendered = (ImageRendered) rendererImageInfo.img;
+ int maxPixelSize = paintingState.getBitsPerPixel();
+ if (paintingState.isColorImages()) {
+ maxPixelSize *= 3; //RGB only at the moment
+ }
+ RenderedImage renderedImage = imageRendered.getRenderedImage();
- imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS45);
- imageObjectInfo.setDataHeightRes(resolution);
- imageObjectInfo.setDataWidthRes(resolution);
- ImageInfo imageInfo = rendererImageInfo.getImageInfo();
++ ImageInfo imageInfo = imageRendered.getInfo();
+ ImageSize intrinsicSize = imageInfo.getSize();
+
+ boolean useFS10 = (maxPixelSize == 1) || BitmapImageUtil.isMonochromeImage(renderedImage);
- boolean usePageSegments = useFS10 && !imageObjectInfo.getResourceInfo().getLevel().isInline();
++ boolean usePageSegments = useFS10
++ && !imageObjectInfo.getResourceInfo().getLevel().isInline();
+
+ ImageSize effIntrinsicSize = intrinsicSize;
+ if (usePageSegments) {
+ //Resize, optionally resample and convert image
+ Dimension resampledDim = new Dimension(
- (int)Math.ceil(UnitConv.mpt2px(afpInfo.getWidth(), resolution)),
- (int)Math.ceil(UnitConv.mpt2px(afpInfo.getHeight(), resolution)));
++ (int)Math.ceil(UnitConv.mpt2px(targetSize.getWidth(), resolution)),
++ (int)Math.ceil(UnitConv.mpt2px(targetSize.getHeight(), resolution)));
+
+ imageObjectInfo.setCreatePageSegment(true);
+ imageObjectInfo.getResourceInfo().setImageDimension(resampledDim);
+
+ //Only resample/downsample if image is smaller than its intrinsic size
+ //to make print file smaller
+ boolean resample = resampledDim.width < renderedImage.getWidth()
+ && resampledDim.height < renderedImage.getHeight();
+ if (resample) {
+ if (log.isDebugEnabled()) {
+ log.debug("Resample from " + intrinsicSize.getDimensionPx()
+ + " to " + resampledDim);
+ }
+ renderedImage = BitmapImageUtil.convertToMonochrome(renderedImage, resampledDim);
- effIntrinsicSize = new ImageSize(resampledDim.width, resampledDim.height, resolution);
++ effIntrinsicSize = new ImageSize(
++ resampledDim.width, resampledDim.height, resolution);
+ }
+ }
+ if (useFS10) {
+ imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS10);
+ } else {
+ imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS11);
+ }
- RenderedImage renderedImage = imageRendered.getRenderedImage();
+ imageObjectInfo.setDataHeightRes((int)Math.round(
+ effIntrinsicSize.getDpiHorizontal() * 10));
+ imageObjectInfo.setDataWidthRes((int)Math.round(
+ effIntrinsicSize.getDpiVertical() * 10));
int dataHeight = renderedImage.getHeight();
imageObjectInfo.setDataHeight(dataHeight);
int dataWidth = renderedImage.getWidth();
imageObjectInfo.setDataWidth(dataWidth);
-
- int maxPixelSize = paintingState.getBitsPerPixel();
- if (paintingState.isColorImages()) {
- maxPixelSize *= 3; //RGB only at the moment
- }
-
+ //TODO To reduce AFP file size, investigate using a compression scheme.
+ //Currently, all image data is uncompressed.
ColorModel cm = renderedImage.getColorModel();
if (log.isTraceEnabled()) {
log.trace("ColorModel: " + cm);
return FLAVORS;
}
- updateDataObjectInfo(imageObjectInfo, afpContext.getPaintingState(), imageRend);
+ /** {@inheritDoc} */
+ public void handleImage(RenderingContext context, Image image, Rectangle pos)
+ throws IOException {
+ AFPRenderingContext afpContext = (AFPRenderingContext)context;
+
+ AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)createDataObjectInfo();
+
+ // set resource information
+ setResourceInformation(imageObjectInfo,
+ image.getInfo().getOriginalURI(),
+ afpContext.getForeignAttributes());
+
+ // Positioning
+ imageObjectInfo.setObjectAreaInfo(createObjectAreaInfo(afpContext.getPaintingState(), pos));
++ Dimension targetSize = pos.getSize();
+
+ // Image content
+ ImageRendered imageRend = (ImageRendered)image;
++ updateDataObjectInfo(imageObjectInfo, afpContext.getPaintingState(), imageRend, targetSize);
+
+ // Create image
+ afpContext.getResourceManager().createObject(imageObjectInfo);
+ }
+
+ /** {@inheritDoc} */
+ public boolean isCompatible(RenderingContext targetContext, Image image) {
+ return (image == null || image instanceof ImageRendered)
+ && targetContext instanceof AFPRenderingContext;
+ }
+
}
return BitmapImageUtil.isGrayscaleImage(img);
}
- String clName = "org.apache.fop.render.pcl.JAIMonochromeBitmapConverter";
+ private static int jaiAvailable = -1; //no synchronization necessary, not critical
+
+ /**
+ * Indicates whether JAI is available. JAI has shown to be reliable when dithering a
+ * grayscale or color image to monochrome bitmaps (1-bit).
+ * @return true if JAI is available
+ */
+ public static boolean isJAIAvailable() {
+ if (jaiAvailable < 0) {
+ try {
- private MonochromeBitmapConverter createMonochromeBitmapConverter() {
- MonochromeBitmapConverter converter = null;
- try {
- String clName = "org.apache.fop.render.pcl.JAIMonochromeBitmapConverter";
- Class clazz = Class.forName(clName);
- converter = (MonochromeBitmapConverter)clazz.newInstance();
- } catch (ClassNotFoundException cnfe) {
- // Class was not compiled so is not available. Simply ignore.
- } catch (LinkageError le) {
- // This can happen if fop was build with support for a
- // particular provider (e.g. a binary fop distribution)
- // but the required support files (i.e. JAI) are not
- // available in the current runtime environment.
- // Simply continue with the backup implementation.
- } catch (InstantiationException e) {
- // Problem instantiating the class, simply continue with the backup implementation
- } catch (IllegalAccessException e) {
- // Problem instantiating the class, simply continue with the backup implementation
- }
- if (converter == null) {
- converter = new DefaultMonochromeBitmapConverter();
- }
- return converter;
- }
-
++ String clName = "javax.media.jai.JAI";
+ Class.forName(clName);
+ jaiAvailable = 1;
+ } catch (ClassNotFoundException cnfe) {
+ jaiAvailable = 0;
+ }
+ }
+ return (jaiAvailable > 0);
+ }
+
private int calculatePCLResolution(int resolution) {
return calculatePCLResolution(resolution, false);
}
}
if (src == null) {
src = BitmapImageUtil.convertToGrayscale(img, effDim);
- }
+ }
- MonochromeBitmapConverter converter = createMonochromeBitmapConverter();
+ MonochromeBitmapConverter converter
+ = BitmapImageUtil.createDefaultMonochromeBitmapConverter();
converter.setHint("quality", "false");
- BufferedImage buf = (BufferedImage)converter.convertToMonochrome(src);
-
- RenderedImage red = buf;
+ RenderedImage red = converter.convertToMonochrome(src);
selectCurrentPattern(0, 0); //Solid black
setTransparencyMode(sourceTransparency || mask != null, true);
paintMonochromeBitmap(red, effResolution);