diff options
Diffstat (limited to 'src/java/org')
23 files changed, 480 insertions, 135 deletions
diff --git a/src/java/org/apache/fop/afp/AFPDataObjectFactory.java b/src/java/org/apache/fop/afp/AFPDataObjectFactory.java index 615c22b17..17114ebbe 100644 --- a/src/java/org/apache/fop/afp/AFPDataObjectFactory.java +++ b/src/java/org/apache/fop/afp/AFPDataObjectFactory.java @@ -108,6 +108,9 @@ public class AFPDataObjectFactory { case TIFFImage.COMP_FAX_G4_2D: imageObj.setEncoding(ImageContent.COMPID_G3_MMR); break; + case ImageContent.COMPID_JPEG: + imageObj.setEncoding((byte)compression); + break; default: throw new IllegalStateException( "Invalid compression scheme: " + compression); diff --git a/src/java/org/apache/fop/afp/AFPDitheredRectanglePainter.java b/src/java/org/apache/fop/afp/AFPDitheredRectanglePainter.java index 79e4979fd..d1c693afb 100644 --- a/src/java/org/apache/fop/afp/AFPDitheredRectanglePainter.java +++ b/src/java/org/apache/fop/afp/AFPDitheredRectanglePainter.java @@ -90,22 +90,18 @@ public class AFPDitheredRectanglePainter extends AbstractAFPPainter { imageObjectInfo.setData(dither); //Positioning - AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(); int rotation = paintingState.getRotation(); AffineTransform at = paintingState.getData().getTransform(); Point2D origin = at.transform(new Point2D.Float( rectanglePaintInfo.getX() * 1000, rectanglePaintInfo.getY() * 1000), null); - objectAreaInfo.setX((int)Math.round(origin.getX())); - objectAreaInfo.setY((int)Math.round(origin.getY())); AFPUnitConverter unitConv = paintingState.getUnitConverter(); float width = unitConv.pt2units(rectanglePaintInfo.getWidth()); float height = unitConv.pt2units(rectanglePaintInfo.getHeight()); - objectAreaInfo.setWidth(Math.round(width)); - objectAreaInfo.setHeight(Math.round(height)); - objectAreaInfo.setHeightRes(resolution); - objectAreaInfo.setWidthRes(resolution); - objectAreaInfo.setRotation(rotation); + AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo( + (int) Math.round(origin.getX()), + (int) Math.round(origin.getY()), + Math.round(width), Math.round(height), resolution, rotation); imageObjectInfo.setObjectAreaInfo(objectAreaInfo); //Create rectangle diff --git a/src/java/org/apache/fop/afp/AFPImageObjectInfo.java b/src/java/org/apache/fop/afp/AFPImageObjectInfo.java index 7aee3cda8..0dca97513 100644 --- a/src/java/org/apache/fop/afp/AFPImageObjectInfo.java +++ b/src/java/org/apache/fop/afp/AFPImageObjectInfo.java @@ -85,7 +85,7 @@ public class AFPImageObjectInfo extends AFPDataObjectInfo { * @return true if this image uses compression */ public boolean hasCompression() { - return compression > -1; + return compression != -1; } /** @@ -123,6 +123,7 @@ public class AFPImageObjectInfo extends AFPDataObjectInfo { } /** {@inheritDoc} */ + @Override public String toString() { return "AFPImageObjectInfo{" + super.toString() + ", compression=" + compression diff --git a/src/java/org/apache/fop/afp/AFPObjectAreaInfo.java b/src/java/org/apache/fop/afp/AFPObjectAreaInfo.java index 963424470..1ecffc2df 100644 --- a/src/java/org/apache/fop/afp/AFPObjectAreaInfo.java +++ b/src/java/org/apache/fop/afp/AFPObjectAreaInfo.java @@ -24,66 +24,60 @@ package org.apache.fop.afp; * dimensions and resolutions of data objects. */ public class AFPObjectAreaInfo { - private int x; - private int y; - private int width; - private int height; + private final int x; + private final int y; + private final int width; + private final int height; private int widthRes; private int heightRes; - private int rotation = 0; + private final int rotation; /** - * Sets the x position of the data object + * Constructor * - * @param x the x position of the data object + * @param x the x coordinate + * @param y the y coordinate + * @param width the width + * @param height the height + * @param resolution the resolution (sets both width and height resolutions) + * @param rotation the rotation angle */ - public void setX(int x) { + public AFPObjectAreaInfo(int x, int y, int width, int height, int resolution, int rotation) { this.x = x; - } - - /** - * Sets the y position of the data object - * - * @param y the y position of the data object - */ - public void setY(int y) { this.y = y; - } - - /** - * Sets the data object width - * - * @param width the width of the data object - */ - public void setWidth(int width) { this.width = width; + this.height = height; + this.rotation = rotation; + this.widthRes = resolution; + this.heightRes = resolution; } /** - * Sets the data object height + * Sets both the width and the height resolutions. * - * @param height the height of the data object + * @param resolution the resolution */ - public void setHeight(int height) { - this.height = height; + public void setResolution(int resolution) { + this.widthRes = resolution; + this.heightRes = resolution; } /** - * Sets the width resolution + * Sets the width resolution. * - * @param widthRes the width resolution + * @param resolution the resolution */ - public void setWidthRes(int widthRes) { - this.widthRes = widthRes; + public void setWidthRes(int resolution) { + this.widthRes = resolution; } /** - * Sets the height resolution + * Sets the height resolution. * - * @param heightRes the height resolution + * @param resolution the resolution */ - public void setHeightRes(int heightRes) { - this.heightRes = heightRes; + public void setHeightRes(int resolution) { + this.heightRes = resolution; } /** @@ -125,7 +119,7 @@ public class AFPObjectAreaInfo { /** * Returns the width resolution of this data object * - * @return the width resolution of this data object + * @return the resolution of this data object */ public int getWidthRes() { return widthRes; @@ -134,7 +128,7 @@ public class AFPObjectAreaInfo { /** * Returns the height resolution of this data object * - * @return the height resolution of this data object + * @return the resolution of this data object */ public int getHeightRes() { return heightRes; @@ -149,24 +143,15 @@ public class AFPObjectAreaInfo { return rotation; } - /** - * Sets the data object rotation - * - * @param rotation the data object rotation - */ - public void setRotation(int rotation) { - this.rotation = rotation; - } - /** {@inheritDoc} */ public String toString() { return "x=" + x - + ", y=" + y - + ", width=" + width - + ", height=" + height - + ", widthRes=" + widthRes - + ", heightRes=" + heightRes - + ", rotation=" + rotation; + + ", y=" + y + + ", width=" + width + + ", height=" + height + + ", widthRes=" + widthRes + + ", heigtRes=" + heightRes + + ", rotation=" + rotation; } } diff --git a/src/java/org/apache/fop/afp/AFPPaintingState.java b/src/java/org/apache/fop/afp/AFPPaintingState.java index 2be3a85ac..60ad157f0 100644 --- a/src/java/org/apache/fop/afp/AFPPaintingState.java +++ b/src/java/org/apache/fop/afp/AFPPaintingState.java @@ -53,6 +53,9 @@ public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState /** dithering quality setting (0.0f..1.0f) */ private float ditheringQuality; + /** image encoding quality setting (0.0f..1.0f) */ + private float bitmapEncodingQuality; + /** color image handler */ private ColorConverter colorConverter = GrayScaleColorConverter.getInstance(); @@ -61,6 +64,9 @@ public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState * format. */ private boolean nativeImagesSupported = false; + + private boolean canEmbedJpeg = false; + /** * true if CMYK images (requires IOCA FS45 suppport on the target platform) * may be generated @@ -220,6 +226,24 @@ public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState } /** + * Set whether or not JPEG images can be embedded within an AFP document. + * + * @param canEmbed true if the JPEG image can be embedded + */ + public void setCanEmbedJpeg(boolean canEmbed) { + canEmbedJpeg = canEmbed; + } + + /** + * Returns true if JPEGs can be embedded in an AFP document. + * + * @return true if JPEG embedding is allowed + */ + public boolean canEmbedJpeg() { + return canEmbedJpeg; + } + + /** * Controls whether CMYK images (IOCA FS45) are enabled. By default, support * is disabled for wider compatibility. When disabled, any CMYK image is * converted to the selected color format. @@ -260,6 +284,25 @@ public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState } /** + * Gets the image encoding quality setting to use when encoding bitmap images. + * @return the encoding quality (a value between 0.0f and 1.0f, 1.0 meaning loss-less) + */ + public float getBitmapEncodingQuality() { + return this.bitmapEncodingQuality; + } + + /** + * Sets the image encoding quality setting to use when encoding bitmap images. + * @param quality Defines the desired quality level for the conversion. + * Valid values: a value between 0.0f (lowest) and 1.0f (best, loss-less) + */ + public void setBitmapEncodingQuality(float quality) { + quality = Math.max(quality, 0.0f); + quality = Math.min(quality, 1.0f); + this.bitmapEncodingQuality = quality; + } + + /** * Sets the output/device resolution * * @param resolution diff --git a/src/java/org/apache/fop/afp/AFPResourceManager.java b/src/java/org/apache/fop/afp/AFPResourceManager.java index 5371ee373..89341588c 100644 --- a/src/java/org/apache/fop/afp/AFPResourceManager.java +++ b/src/java/org/apache/fop/afp/AFPResourceManager.java @@ -242,8 +242,7 @@ public class AFPResourceManager { private void includeObject(AFPDataObjectInfo dataObjectInfo, String objectName) { - IncludeObject includeObject - = dataObjectFactory.createInclude(objectName, dataObjectInfo); + IncludeObject includeObject = dataObjectFactory.createInclude(objectName, dataObjectInfo); dataStream.getCurrentPage().addObject(includeObject); } diff --git a/src/java/org/apache/fop/afp/fonts/AFPFontInfo.java b/src/java/org/apache/fop/afp/fonts/AFPFontInfo.java index 02e542419..8e865d4e5 100644 --- a/src/java/org/apache/fop/afp/fonts/AFPFontInfo.java +++ b/src/java/org/apache/fop/afp/fonts/AFPFontInfo.java @@ -21,6 +21,8 @@ package org.apache.fop.afp.fonts; import java.util.List; +import org.apache.fop.fonts.FontTriplet; + /** * FontInfo contains meta information on fonts @@ -28,7 +30,7 @@ import java.util.List; public class AFPFontInfo { private AFPFont font; - private List/*<FontTriplet>*/ tripletList; + private List<FontTriplet> tripletList; /** * Main constructor @@ -36,7 +38,7 @@ public class AFPFontInfo { * @param afpFont The AFP Font * @param tripletList List of font triplets to associate with this font */ - public AFPFontInfo(AFPFont afpFont, List/*<FontTriplet>*/ tripletList) { + public AFPFontInfo(AFPFont afpFont, List<FontTriplet> tripletList) { this.font = afpFont; this.tripletList = tripletList; } @@ -55,7 +57,7 @@ public class AFPFontInfo { * * @return List of font triplets */ - public List/*<FontTriplet>*/ getFontTriplets() { + public List<FontTriplet> getFontTriplets() { return tripletList; } diff --git a/src/java/org/apache/fop/afp/ioca/ImageContent.java b/src/java/org/apache/fop/afp/ioca/ImageContent.java index 9c06589e0..81b260bd4 100644 --- a/src/java/org/apache/fop/afp/ioca/ImageContent.java +++ b/src/java/org/apache/fop/afp/ioca/ImageContent.java @@ -53,6 +53,9 @@ public class ImageContent extends AbstractStructuredObject { */ public static final byte COMPID_G3_MMR = (byte)0x82; + /** JPEG algorithms (usually baseline DCT). */ + public static final byte COMPID_JPEG = (byte)0x83; + /** the image size parameter */ private ImageSizeParameter imageSizeParameter = null; @@ -66,7 +69,7 @@ public class ImageContent extends AbstractStructuredObject { private byte ideSize = 1; /** the image compression */ - private byte compression = (byte)0xC0; + private byte compression = (byte)0xC0; //Baseline DCT in case of JPEG compression /** the image data */ private byte[] data; @@ -147,6 +150,7 @@ public class ImageContent extends AbstractStructuredObject { * @param color the IDE color model. * @deprecated use {@link #setIDEStructureParameter(IDEStructureParameter)} instead */ + @Deprecated public void setImageIDEColorModel(byte color) { needIDEStructureParameter().setColorModel(color); } @@ -156,6 +160,7 @@ public class ImageContent extends AbstractStructuredObject { * @param subtractive true for subtractive mode, false for additive mode * @deprecated use {@link #setIDEStructureParameter(IDEStructureParameter)} instead */ + @Deprecated public void setSubtractive(boolean subtractive) { needIDEStructureParameter().setSubtractive(subtractive); } @@ -172,6 +177,7 @@ public class ImageContent extends AbstractStructuredObject { private static final int MAX_DATA_LEN = 65535; /** {@inheritDoc} */ + @Override protected void writeContent(OutputStream os) throws IOException { if (imageSizeParameter != null) { imageSizeParameter.writeToStream(os); @@ -206,6 +212,7 @@ public class ImageContent extends AbstractStructuredObject { } /** {@inheritDoc} */ + @Override protected void writeStart(OutputStream os) throws IOException { final byte[] startData = new byte[] { (byte)0x91, // ID @@ -216,6 +223,7 @@ public class ImageContent extends AbstractStructuredObject { } /** {@inheritDoc} */ + @Override protected void writeEnd(OutputStream os) throws IOException { final byte[] endData = new byte[] { (byte)0x93, // ID @@ -234,7 +242,7 @@ public class ImageContent extends AbstractStructuredObject { (byte)0x95, // ID 0x02, // Length encoding, - 0x01, // RECID + (byte)(encoding == COMPID_JPEG ? 0xFE : 0x01), // RECID }; return encodingData; } @@ -245,17 +253,17 @@ public class ImageContent extends AbstractStructuredObject { * @return byte[] The data stream. */ private byte[] getExternalAlgorithmParameter() { - if (encoding == (byte)0x83 && compression != 0) { + if (encoding == COMPID_JPEG && compression != 0) { final byte[] extAlgData = new byte[] { - (byte)0x95, // ID + (byte)0x9F, // ID 0x00, // Length 0x10, // ALGTYPE = Compression Algorithm 0x00, // Reserved - (byte)0x83, // COMPRID = JPEG + COMPID_JPEG, // COMPRID = JPEG 0x00, // Reserved 0x00, // Reserved 0x00, // Reserved - compression, // MARKER + compression, // MARKER 0x00, // Reserved 0x00, // Reserved 0x00, // Reserved diff --git a/src/java/org/apache/fop/afp/modca/AbstractDataObject.java b/src/java/org/apache/fop/afp/modca/AbstractDataObject.java index d76de9259..a8bf09998 100644 --- a/src/java/org/apache/fop/afp/modca/AbstractDataObject.java +++ b/src/java/org/apache/fop/afp/modca/AbstractDataObject.java @@ -74,8 +74,8 @@ public abstract class AbstractDataObject extends AbstractNamedAFPObject int height = objectAreaInfo.getHeight(); int widthRes = objectAreaInfo.getWidthRes(); int heightRes = objectAreaInfo.getHeightRes(); - ObjectAreaDescriptor objectAreaDescriptor - = factory.createObjectAreaDescriptor(width, height, widthRes, heightRes); + ObjectAreaDescriptor objectAreaDescriptor = factory.createObjectAreaDescriptor(width, + height, widthRes, heightRes); getObjectEnvironmentGroup().setObjectAreaDescriptor(objectAreaDescriptor); // object area position diff --git a/src/java/org/apache/fop/afp/modca/GraphicsObject.java b/src/java/org/apache/fop/afp/modca/GraphicsObject.java index cf732c77a..6b2907807 100644 --- a/src/java/org/apache/fop/afp/modca/GraphicsObject.java +++ b/src/java/org/apache/fop/afp/modca/GraphicsObject.java @@ -96,7 +96,7 @@ public class GraphicsObject extends AbstractDataObject { final int leftEdge = 0; final int topEdge = 0; GraphicsDataDescriptor graphicsDataDescriptor = factory.createGraphicsDataDescriptor( - leftEdge, width, topEdge, height, widthRes, heightRes); + leftEdge, width, topEdge, height, widthRes, heightRes); getObjectEnvironmentGroup().setDataDescriptor(graphicsDataDescriptor); } diff --git a/src/java/org/apache/fop/afp/modca/ObjectContainer.java b/src/java/org/apache/fop/afp/modca/ObjectContainer.java index 9bc8dc594..50aabb03b 100644 --- a/src/java/org/apache/fop/afp/modca/ObjectContainer.java +++ b/src/java/org/apache/fop/afp/modca/ObjectContainer.java @@ -107,7 +107,7 @@ public class ObjectContainer extends AbstractDataObject { ContainerDataDescriptor containerDataDescriptor = factory.createContainerDataDescriptor( - dataWidth, dataHeight, widthRes, heightRes); + dataWidth, dataHeight, widthRes, heightRes); getObjectEnvironmentGroup().setDataDescriptor(containerDataDescriptor); } } diff --git a/src/java/org/apache/fop/afp/modca/Registry.java b/src/java/org/apache/fop/afp/modca/Registry.java index eade967ec..64afce3b5 100644 --- a/src/java/org/apache/fop/afp/modca/Registry.java +++ b/src/java/org/apache/fop/afp/modca/Registry.java @@ -20,6 +20,7 @@ package org.apache.fop.afp.modca; import java.util.Collections; +import java.util.HashMap; import org.apache.xmlgraphics.util.MimeConstants; @@ -43,9 +44,8 @@ public final class Registry { private static final byte COMPID_TRUETYPE_OPENTYPE_FONT_COLLECTION_RESOURCE_OBJECT = 53; /** mime type entry mapping */ - private final java.util.Map/*<String, ObjectType>*/ mimeObjectTypeMap - = Collections.synchronizedMap( - new java.util.HashMap/*<String, ObjectType>*/()); + private final java.util.Map<String, ObjectType> mimeObjectTypeMap + = Collections.synchronizedMap(new HashMap<String, ObjectType>()); /** singleton instance */ private static Registry instance = null; @@ -203,7 +203,7 @@ public final class Registry { * @return the MOD:CA object type */ public ObjectType getObjectType(String mimeType) { - return (ObjectType)mimeObjectTypeMap.get(mimeType); + return mimeObjectTypeMap.get(mimeType); } /** diff --git a/src/java/org/apache/fop/render/ImageHandlerRegistry.java b/src/java/org/apache/fop/render/ImageHandlerRegistry.java index 02a26265c..18e5b1272 100644 --- a/src/java/org/apache/fop/render/ImageHandlerRegistry.java +++ b/src/java/org/apache/fop/render/ImageHandlerRegistry.java @@ -42,18 +42,20 @@ public class ImageHandlerRegistry { /** the logger */ private static Log log = LogFactory.getLog(ImageHandlerRegistry.class); - private static final Comparator HANDLER_COMPARATOR = new Comparator() { - public int compare(Object o1, Object o2) { - ImageHandler h1 = (ImageHandler)o1; - ImageHandler h2 = (ImageHandler)o2; + private static final Comparator<ImageHandler> HANDLER_COMPARATOR + = new Comparator<ImageHandler>() { + public int compare(ImageHandler o1, ImageHandler o2) { + ImageHandler h1 = o1; + ImageHandler h2 = o2; return h1.getPriority() - h2.getPriority(); } }; /** Map containing image handlers for various {@link Image} subclasses. */ - private Map handlers = new java.util.HashMap(); + private Map<Class<? extends Image>, ImageHandler> handlers + = new java.util.HashMap<Class<? extends Image>, ImageHandler>(); /** List containing the same handlers as above but ordered by priority */ - private List handlerList = new java.util.LinkedList(); + private List<ImageHandler> handlerList = new java.util.LinkedList<ImageHandler>(); private int handlerRegistrations; @@ -94,14 +96,14 @@ public class ImageHandlerRegistry { * @param handler the ImageHandler instance */ public synchronized void addHandler(ImageHandler handler) { - Class imageClass = handler.getSupportedImageClass(); + Class<? extends Image> imageClass = handler.getSupportedImageClass(); //List this.handlers.put(imageClass, handler); //Sorted insert (sort by priority) - ListIterator iter = this.handlerList.listIterator(); + ListIterator<ImageHandler> iter = this.handlerList.listIterator(); while (iter.hasNext()) { - ImageHandler h = (ImageHandler)iter.next(); + ImageHandler h = iter.next(); if (HANDLER_COMPARATOR.compare(handler, h) < 0) { iter.previous(); break; @@ -119,9 +121,7 @@ public class ImageHandlerRegistry { * @return the image handler responsible for handling the image or null if none is available */ public ImageHandler getHandler(RenderingContext targetContext, Image image) { - ListIterator iter = this.handlerList.listIterator(); - while (iter.hasNext()) { - ImageHandler h = (ImageHandler)iter.next(); + for (ImageHandler h : this.handlerList) { if (h.isCompatible(targetContext, image)) { //Return the first handler in the prioritized list that is compatible return h; @@ -138,10 +138,8 @@ public class ImageHandlerRegistry { */ public synchronized ImageFlavor[] getSupportedFlavors(RenderingContext context) { //Extract all ImageFlavors into a single array - List flavors = new java.util.ArrayList(); - Iterator iter = this.handlerList.iterator(); - while (iter.hasNext()) { - ImageHandler handler = (ImageHandler)iter.next(); + List<ImageFlavor> flavors = new java.util.ArrayList<ImageFlavor>(); + for (ImageHandler handler : this.handlerList) { if (handler.isCompatible(context, null)) { ImageFlavor[] f = handler.getSupportedImageFlavors(); for (int i = 0; i < f.length; i++) { @@ -149,7 +147,7 @@ public class ImageHandlerRegistry { } } } - return (ImageFlavor[])flavors.toArray(new ImageFlavor[flavors.size()]); + return flavors.toArray(new ImageFlavor[flavors.size()]); } /** diff --git a/src/java/org/apache/fop/render/afp/AFPCustomizable.java b/src/java/org/apache/fop/render/afp/AFPCustomizable.java index 04f3a6eeb..684ac057c 100644 --- a/src/java/org/apache/fop/render/afp/AFPCustomizable.java +++ b/src/java/org/apache/fop/render/afp/AFPCustomizable.java @@ -72,6 +72,16 @@ public interface AFPCustomizable { void setDitheringQuality(float quality); /** + * Sets the image encoding quality setting to use when encoding bitmap images. + * The default setting is 1.0 which means loss-less encoding. Settings of less than 1.0 + * allow loss-less encoding schemes like JPEG. The value serves as quality setting for + * the encoders in that case. + * @param quality Defines the desired quality level. + * Valid values: a value between 0.0f (lowest) and 1.0f (best, loss-less) + */ + void setBitmapEncodingQuality(float quality); + + /** * Sets the output/device resolution * * @param resolution @@ -123,4 +133,11 @@ public interface AFPCustomizable { */ void setResourceLevelDefaults(AFPResourceLevelDefaults defaults); + /** + * Sets whether or not to JPEG images can be embedded in the AFP document. + * + * @param canEmbed whether or not to embed JPEG image + */ + void canEmbedJpeg(boolean canEmbed); + } diff --git a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java index 3c3fc123f..29f689555 100644 --- a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java @@ -429,6 +429,11 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler } /** {@inheritDoc} */ + public void setBitmapEncodingQuality(float quality) { + this.paintingState.setBitmapEncodingQuality(quality); + } + + /** {@inheritDoc} */ public void setShadingMode(AFPShadingMode shadingMode) { this.shadingMode = shadingMode; } @@ -483,4 +488,9 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler return pageSegmentMap.get(uri); } + /** {@inheritDoc} */ + public void canEmbedJpeg(boolean canEmbed) { + paintingState.setCanEmbedJpeg(canEmbed); + } + } diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandler.java b/src/java/org/apache/fop/render/afp/AFPImageHandler.java index 244263213..118207d38 100644 --- a/src/java/org/apache/fop/render/afp/AFPImageHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPImageHandler.java @@ -62,24 +62,17 @@ public abstract class AFPImageHandler implements ImageHandlerBase { */ public static AFPObjectAreaInfo createObjectAreaInfo(AFPPaintingState paintingState, Rectangle targetRect) { - AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(); AFPUnitConverter unitConv = paintingState.getUnitConverter(); int[] coords = unitConv.mpts2units(new float[] {targetRect.x, targetRect.y}); - objectAreaInfo.setX(coords[X]); - objectAreaInfo.setY(coords[Y]); int width = Math.round(unitConv.mpt2units(targetRect.width)); - objectAreaInfo.setWidth(width); int height = Math.round(unitConv.mpt2units(targetRect.height)); - objectAreaInfo.setHeight(height); int resolution = paintingState.getResolution(); - objectAreaInfo.setHeightRes(resolution); - objectAreaInfo.setWidthRes(resolution); - - objectAreaInfo.setRotation(paintingState.getRotation()); + AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(coords[X], coords[Y], width, + height, resolution, paintingState.getRotation()); return objectAreaInfo; } diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawCCITTFax.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawCCITTFax.java index 83d41ba8c..85ef580f5 100644 --- a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawCCITTFax.java +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawCCITTFax.java @@ -19,6 +19,12 @@ package org.apache.fop.render.afp; +import java.awt.Rectangle; +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.impl.ImageRawCCITTFax; @@ -38,7 +44,11 @@ public class AFPImageHandlerRawCCITTFax extends AbstractAFPImageHandlerRawStream ImageFlavor.RAW_CCITTFAX, }; + /** logging instance */ + private final Log log = LogFactory.getLog(AFPImageHandlerRawJPEG.class); + /** {@inheritDoc} */ + @Override protected void setAdditionalParameters(AFPDataObjectInfo dataObjectInfo, ImageRawStream image) { AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)dataObjectInfo; @@ -54,6 +64,15 @@ public class AFPImageHandlerRawCCITTFax extends AbstractAFPImageHandlerRawStream } /** {@inheritDoc} */ + @Override + public void handleImage(RenderingContext context, Image image, Rectangle pos) + throws IOException { + log.debug("Embedding undecoded CCITT data as data container..."); + super.handleImage(context, image, pos); + } + + /** {@inheritDoc} */ + @Override protected AFPDataObjectInfo createDataObjectInfo() { return new AFPImageObjectInfo(); } diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawJPEG.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawJPEG.java new file mode 100644 index 000000000..e318c49fb --- /dev/null +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawJPEG.java @@ -0,0 +1,205 @@ +/* + * 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; + + AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)createDataObjectInfo(); + AFPPaintingState paintingState = afpContext.getPaintingState(); + + // set resource information + setResourceInformation(imageObjectInfo, + 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; + } + +} diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java index fcfc9c64c..f32f7305b 100644 --- a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java @@ -19,6 +19,12 @@ package org.apache.fop.render.afp; +import java.awt.Rectangle; +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.impl.ImageRawEPS; @@ -40,6 +46,9 @@ public class AFPImageHandlerRawStream extends AbstractAFPImageHandlerRawStream { ImageFlavor.RAW_EPS, }; + /** logging instance */ + private final Log log = LogFactory.getLog(AFPImageHandlerRawJPEG.class); + /** {@inheritDoc} */ public int getPriority() { return 200; @@ -56,11 +65,23 @@ public class AFPImageHandlerRawStream extends AbstractAFPImageHandlerRawStream { } /** {@inheritDoc} */ + @Override protected AFPDataObjectInfo createDataObjectInfo() { return new AFPDataObjectInfo(); } /** {@inheritDoc} */ + @Override + public void handleImage(RenderingContext context, Image image, Rectangle pos) + throws IOException { + if (log.isDebugEnabled()) { + log.debug("Embedding undecoded image data (" + image.getInfo().getMimeType() + + ") as data container..."); + } + super.handleImage(context, image, pos); + } + + /** {@inheritDoc} */ public boolean isCompatible(RenderingContext targetContext, Image image) { if (targetContext instanceof AFPRenderingContext) { AFPRenderingContext afpContext = (AFPRenderingContext)targetContext; diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java index c516da702..0b4b6ea98 100644 --- a/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java @@ -28,10 +28,10 @@ import java.awt.image.MultiPixelPackedSampleModel; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; -import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -40,6 +40,9 @@ 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.image.writer.ImageWriter; +import org.apache.xmlgraphics.image.writer.ImageWriterParams; +import org.apache.xmlgraphics.image.writer.ImageWriterRegistry; import org.apache.xmlgraphics.ps.ImageEncodingHelper; import org.apache.xmlgraphics.util.MimeConstants; import org.apache.xmlgraphics.util.UnitConv; @@ -50,6 +53,7 @@ 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; @@ -284,7 +288,26 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima functionSet = 45; //IOCA FS45 required for CMYK } - helper.encode(baos); + //Lossy or loss-less? + if (!paintingState.canEmbedJpeg() + && paintingState.getBitmapEncodingQuality() < 1.0f) { + try { + if (log.isDebugEnabled()) { + log.debug("Encoding using baseline DCT (JPEG, q=" + + paintingState.getBitmapEncodingQuality() + ")..."); + } + encodeToBaselineDCT(renderedImage, + paintingState.getBitmapEncodingQuality(), + paintingState.getResolution(), + baos); + imageObjectInfo.setCompression(ImageContent.COMPID_JPEG); + } catch (IOException ioe) { + //Some JPEG codecs cannot encode CMYK + helper.encode(baos); + } + } else { + helper.encode(baos); + } imageData = baos.toByteArray(); } } @@ -393,6 +416,14 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima return false; } - } + private void encodeToBaselineDCT(RenderedImage image, + float quality, int resolution, OutputStream out) throws IOException { + ImageWriter writer = ImageWriterRegistry.getInstance().getWriterFor("image/jpeg"); + ImageWriterParams params = new ImageWriterParams(); + params.setJPEGQuality(quality, true); + params.setResolution(resolution); + writer.writeImage(image, out, params); + } + } } diff --git a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java index fc8d10508..25d684e42 100644 --- a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java +++ b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java @@ -23,10 +23,12 @@ import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.List; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; + import org.apache.fop.afp.AFPResourceLevel; import org.apache.fop.afp.AFPResourceLevelDefaults; import org.apache.fop.afp.fonts.AFPFont; @@ -80,10 +82,10 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator log.error("Mandatory font configuration element '<font-triplet...' is missing"); return null; } - for (int j = 0; j < triple.length; j++) { - int weight = FontUtil.parseCSS2FontWeight(triple[j].getAttribute("weight")); - FontTriplet triplet = new FontTriplet(triple[j].getAttribute("name"), - triple[j].getAttribute("style"), + for (Configuration config : triple) { + int weight = FontUtil.parseCSS2FontWeight(config.getAttribute("weight")); + FontTriplet triplet = new FontTriplet(config.getAttribute("name"), + config.getAttribute("style"), weight); tripletList.add(triplet); } @@ -183,10 +185,10 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator if (base14 != null) { try { - Class<?> clazz = Class.forName( - "org.apache.fop.fonts.base14." + base14); + Class<? extends Typeface> clazz = Class.forName( + "org.apache.fop.fonts.base14." + base14).asSubclass(Typeface.class); try { - Typeface tf = (Typeface)clazz.newInstance(); + Typeface tf = clazz.newInstance(); font.addCharacterSet(sizeMpt, CharacterSetBuilder.getInstance() .build(characterset, codepage, encoding, tf)); @@ -222,10 +224,10 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator String base14 = afpFontCfg.getAttribute("base14-font", null); if (base14 != null) { try { - Class<?> clazz = Class.forName("org.apache.fop.fonts.base14." - + base14); + Class<? extends Typeface> clazz = Class.forName("org.apache.fop.fonts.base14." + + base14).asSubclass(Typeface.class); try { - Typeface tf = (Typeface)clazz.newInstance(); + Typeface tf = clazz.newInstance(); characterSet = CharacterSetBuilder.getInstance() .build(characterset, codepage, encoding, tf); } catch (Exception ie) { @@ -319,7 +321,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator if (log.isDebugEnabled()) { log.debug("Adding font " + afi.getAFPFont().getFontName()); } - List/*<FontTriplet>*/ fontTriplets = afi.getFontTriplets(); + List<FontTriplet> fontTriplets = afi.getFontTriplets(); for (int j = 0; j < fontTriplets.size(); ++j) { FontTriplet triplet = (FontTriplet) fontTriplets.get(j); if (log.isDebugEnabled()) { @@ -396,6 +398,24 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator boolean nativeImageSupport = imagesCfg.getAttributeAsBoolean("native", false); customizable.setNativeImagesSupported(nativeImageSupport); + Configuration jpegConfig = imagesCfg.getChild("jpeg"); + boolean allowEmbedding = false; + float ieq = 1.0f; + if (jpegConfig != null) { + allowEmbedding = jpegConfig.getAttributeAsBoolean("allow-embedding", false); + String bitmapEncodingQuality = jpegConfig.getAttribute("bitmap-encoding-quality", null); + + if (bitmapEncodingQuality != null) { + try { + ieq = Float.parseFloat(bitmapEncodingQuality); + } catch (NumberFormatException nfe) { + //ignore and leave the default above + } + } + } + customizable.canEmbedJpeg(allowEmbedding); + customizable.setBitmapEncodingQuality(ieq); + // shading (filled rectangles) Configuration shadingCfg = cfg.getChild("shading"); AFPShadingMode shadingMode = AFPShadingMode.valueOf( @@ -480,7 +500,7 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) throws FOPException { FontManager fontManager = userAgent.getFactory().getFontManager(); - List<FontCollection> fontCollections = new java.util.ArrayList<FontCollection>(); + List<AFPFontCollection> fontCollections = new ArrayList<AFPFontCollection>(); Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); if (cfg != null) { diff --git a/src/java/org/apache/fop/render/afp/AFPSVGHandler.java b/src/java/org/apache/fop/render/afp/AFPSVGHandler.java index 7ade64006..48b82bbf3 100644 --- a/src/java/org/apache/fop/render/afp/AFPSVGHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPSVGHandler.java @@ -154,23 +154,18 @@ public class AFPSVGHandler extends AbstractGenericSVGHandler { private AFPObjectAreaInfo createObjectAreaInfo(AFPPaintingState paintingState, int x, int y, int width, int height, int resolution) { // set the data object parameters - AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(); AffineTransform at = paintingState.getData().getTransform(); at.translate(x, y); - objectAreaInfo.setX((int)Math.round(at.getTranslateX())); - objectAreaInfo.setY((int)Math.round(at.getTranslateY())); - - objectAreaInfo.setWidthRes(resolution); - objectAreaInfo.setHeightRes(resolution); - AFPUnitConverter unitConv = paintingState.getUnitConverter(); - objectAreaInfo.setWidth(Math.round(unitConv.mpt2units(width))); - objectAreaInfo.setHeight(Math.round(unitConv.mpt2units(height))); int rotation = paintingState.getRotation(); - objectAreaInfo.setRotation(rotation); - + int objX = (int) Math.round(at.getTranslateX()); + int objY = (int) Math.round(at.getTranslateY()); + int objWidth = Math.round(unitConv.mpt2units(width)); + int objHeight = Math.round(unitConv.mpt2units(height)); + AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(objX, objY, objWidth, objHeight, + resolution, rotation); return objectAreaInfo; } diff --git a/src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java b/src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java index 5374c7051..b36646117 100644 --- a/src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java +++ b/src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java @@ -103,8 +103,7 @@ public abstract class AbstractAFPImageHandlerRawStream extends AFPImageHandler AFPPaintingState paintingState = afpContext.getPaintingState(); int resolution = paintingState.getResolution(); AFPObjectAreaInfo objectAreaInfo = dataObjectInfo.getObjectAreaInfo(); - objectAreaInfo.setWidthRes(resolution); - objectAreaInfo.setHeightRes(resolution); + objectAreaInfo.setResolution(resolution); // Image content ImageRawStream imageStream = (ImageRawStream)image; |