Browse Source

Bugzilla#52089: Allow JPEG images to be embedded in an AFP document as

is, without being decoded and encoded. It also allows lossy JPEG compression.

Patch by Jeremias Maerki and Mehdi Houshmand.


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1195952 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_1rc1old
Peter Hancock 12 years ago
parent
commit
fd263a114c
35 changed files with 874 additions and 139 deletions
  1. 17
    0
      src/documentation/content/xdocs/trunk/output.xml
  2. 1
    0
      src/java/META-INF/services/org.apache.fop.render.ImageHandler
  3. 3
    0
      src/java/org/apache/fop/afp/AFPDataObjectFactory.java
  4. 4
    8
      src/java/org/apache/fop/afp/AFPDitheredRectanglePainter.java
  5. 2
    1
      src/java/org/apache/fop/afp/AFPImageObjectInfo.java
  6. 38
    53
      src/java/org/apache/fop/afp/AFPObjectAreaInfo.java
  7. 43
    0
      src/java/org/apache/fop/afp/AFPPaintingState.java
  8. 1
    2
      src/java/org/apache/fop/afp/AFPResourceManager.java
  9. 5
    3
      src/java/org/apache/fop/afp/fonts/AFPFontInfo.java
  10. 14
    6
      src/java/org/apache/fop/afp/ioca/ImageContent.java
  11. 2
    2
      src/java/org/apache/fop/afp/modca/AbstractDataObject.java
  12. 1
    1
      src/java/org/apache/fop/afp/modca/GraphicsObject.java
  13. 1
    1
      src/java/org/apache/fop/afp/modca/ObjectContainer.java
  14. 4
    4
      src/java/org/apache/fop/afp/modca/Registry.java
  15. 15
    17
      src/java/org/apache/fop/render/ImageHandlerRegistry.java
  16. 17
    0
      src/java/org/apache/fop/render/afp/AFPCustomizable.java
  17. 10
    0
      src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
  18. 2
    9
      src/java/org/apache/fop/render/afp/AFPImageHandler.java
  19. 19
    0
      src/java/org/apache/fop/render/afp/AFPImageHandlerRawCCITTFax.java
  20. 205
    0
      src/java/org/apache/fop/render/afp/AFPImageHandlerRawJPEG.java
  21. 21
    0
      src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java
  22. 34
    3
      src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
  23. 32
    12
      src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java
  24. 6
    11
      src/java/org/apache/fop/render/afp/AFPSVGHandler.java
  25. 1
    2
      src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java
  26. 4
    0
      status.xml
  27. 76
    0
      test/java/org/apache/fop/afp/AFPObjectAreaInfoTestCase.java
  28. 61
    0
      test/java/org/apache/fop/afp/AFPPaintingStateTestCase.java
  29. 89
    0
      test/java/org/apache/fop/afp/AFPResourceManagerTestCase.java
  30. 6
    3
      test/java/org/apache/fop/afp/AFPTestSuite.java
  31. 92
    0
      test/java/org/apache/fop/render/afp/AFPRendererConfiguratorTestCase.java
  32. 3
    1
      test/java/org/apache/fop/render/afp/AFPTestSuite.java
  33. 16
    0
      test/resources/conf/afp/bitmap_encode_quality.xconf
  34. 16
    0
      test/resources/conf/afp/can_embed_jpeg.xconf
  35. 13
    0
      test/resources/conf/afp/no_image_config.xconf

+ 17
- 0
src/documentation/content/xdocs/trunk/output.xml View File

</p> </p>
<source><![CDATA[ <source><![CDATA[
<images mode="b+w" bits-per-pixel="1" dithering-quality="maximum"/>]]></source> <images mode="b+w" bits-per-pixel="1" dithering-quality="maximum"/>]]></source>
<p>
By default, JPEG images are rasterized to a bitmap and the bitmap is included in the AFP doc.
However it is possible to encode in a lossless way to maintain maximum quality. But due
to lack of support for compression schemes like LZW (patent concerns), bitmap data is currently
not compressed resulting in large AFP files. Using the "allow-embedding" attribute on jpeg child
element allows the user to pass the JPEG as is in the document. The default is set to "false" since
there are compatibility concerns as some AFP printers don't support JPEG decoding. Using the
"bitmap-encoding-quality" attribute it is possible to enable lossy compression (JPEG baseline
DCT). The default is "1.0" which means lossless encoding. Setting a value lower than 1.0, JPEG
compression is enabled and the setting is used as the quality setting when encoding bitmap data.
Note that this setting does not always have an effect. Bi-level (1 bit) bitmaps are not compressed
using JPEG. Example:
</p>
<source><![CDATA[
<images mode="color" cmyk="true">
<jpeg allow-embedding="false" bitmap-encoding-quality="0.8"/>
</images>]]></source>
</section> </section>
<section id="afp-goca-config"> <section id="afp-goca-config">
<title>GOCA (Vector Graphics)</title> <title>GOCA (Vector Graphics)</title>

+ 1
- 0
src/java/META-INF/services/org.apache.fop.render.ImageHandler View File

org.apache.fop.render.afp.AFPImageHandlerGraphics2D org.apache.fop.render.afp.AFPImageHandlerGraphics2D
org.apache.fop.render.afp.AFPImageHandlerRawStream org.apache.fop.render.afp.AFPImageHandlerRawStream
org.apache.fop.render.afp.AFPImageHandlerRawCCITTFax org.apache.fop.render.afp.AFPImageHandlerRawCCITTFax
org.apache.fop.render.afp.AFPImageHandlerRawJPEG
org.apache.fop.render.afp.AFPImageHandlerSVG org.apache.fop.render.afp.AFPImageHandlerSVG

+ 3
- 0
src/java/org/apache/fop/afp/AFPDataObjectFactory.java View File

case TIFFImage.COMP_FAX_G4_2D: case TIFFImage.COMP_FAX_G4_2D:
imageObj.setEncoding(ImageContent.COMPID_G3_MMR); imageObj.setEncoding(ImageContent.COMPID_G3_MMR);
break; break;
case ImageContent.COMPID_JPEG:
imageObj.setEncoding((byte)compression);
break;
default: default:
throw new IllegalStateException( throw new IllegalStateException(
"Invalid compression scheme: " + compression); "Invalid compression scheme: " + compression);

+ 4
- 8
src/java/org/apache/fop/afp/AFPDitheredRectanglePainter.java View File

imageObjectInfo.setData(dither); imageObjectInfo.setData(dither);


//Positioning //Positioning
AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo();
int rotation = paintingState.getRotation(); int rotation = paintingState.getRotation();
AffineTransform at = paintingState.getData().getTransform(); AffineTransform at = paintingState.getData().getTransform();
Point2D origin = at.transform(new Point2D.Float( Point2D origin = at.transform(new Point2D.Float(
rectanglePaintInfo.getX() * 1000, rectanglePaintInfo.getX() * 1000,
rectanglePaintInfo.getY() * 1000), null); rectanglePaintInfo.getY() * 1000), null);
objectAreaInfo.setX((int)Math.round(origin.getX()));
objectAreaInfo.setY((int)Math.round(origin.getY()));
AFPUnitConverter unitConv = paintingState.getUnitConverter(); AFPUnitConverter unitConv = paintingState.getUnitConverter();
float width = unitConv.pt2units(rectanglePaintInfo.getWidth()); float width = unitConv.pt2units(rectanglePaintInfo.getWidth());
float height = unitConv.pt2units(rectanglePaintInfo.getHeight()); 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); imageObjectInfo.setObjectAreaInfo(objectAreaInfo);


//Create rectangle //Create rectangle

+ 2
- 1
src/java/org/apache/fop/afp/AFPImageObjectInfo.java View File

* @return true if this image uses compression * @return true if this image uses compression
*/ */
public boolean hasCompression() { public boolean hasCompression() {
return compression > -1;
return compression != -1;
} }


/** /**
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
@Override
public String toString() { public String toString() {
return "AFPImageObjectInfo{" + super.toString() return "AFPImageObjectInfo{" + super.toString()
+ ", compression=" + compression + ", compression=" + compression

+ 38
- 53
src/java/org/apache/fop/afp/AFPObjectAreaInfo.java View File

* dimensions and resolutions of data objects. * dimensions and resolutions of data objects.
*/ */
public class AFPObjectAreaInfo { 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 widthRes;
private int heightRes; 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; 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; 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.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;
} }


/** /**
/** /**
* Returns the width resolution of this data object * 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() { public int getWidthRes() {
return widthRes; return widthRes;
/** /**
* Returns the height resolution of this data object * 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() { public int getHeightRes() {
return heightRes; return heightRes;
return rotation; return rotation;
} }


/**
* Sets the data object rotation
*
* @param rotation the data object rotation
*/
public void setRotation(int rotation) {
this.rotation = rotation;
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public String toString() { public String toString() {
return "x=" + x 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;
} }


} }

+ 43
- 0
src/java/org/apache/fop/afp/AFPPaintingState.java View File

/** dithering quality setting (0.0f..1.0f) */ /** dithering quality setting (0.0f..1.0f) */
private float ditheringQuality; private float ditheringQuality;


/** image encoding quality setting (0.0f..1.0f) */
private float bitmapEncodingQuality;

/** color image handler */ /** color image handler */
private ColorConverter colorConverter = GrayScaleColorConverter.getInstance(); private ColorConverter colorConverter = GrayScaleColorConverter.getInstance();


* format. * format.
*/ */
private boolean nativeImagesSupported = false; private boolean nativeImagesSupported = false;

private boolean canEmbedJpeg = false;

/** /**
* true if CMYK images (requires IOCA FS45 suppport on the target platform) * true if CMYK images (requires IOCA FS45 suppport on the target platform)
* may be generated * may be generated
return this.nativeImagesSupported; return this.nativeImagesSupported;
} }


/**
* 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 * Controls whether CMYK images (IOCA FS45) are enabled. By default, support
* is disabled for wider compatibility. When disabled, any CMYK image is * is disabled for wider compatibility. When disabled, any CMYK image is
this.ditheringQuality = quality; this.ditheringQuality = quality;
} }


/**
* 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 * Sets the output/device resolution
* *

+ 1
- 2
src/java/org/apache/fop/afp/AFPResourceManager.java View File



private void includeObject(AFPDataObjectInfo dataObjectInfo, private void includeObject(AFPDataObjectInfo dataObjectInfo,
String objectName) { String objectName) {
IncludeObject includeObject
= dataObjectFactory.createInclude(objectName, dataObjectInfo);
IncludeObject includeObject = dataObjectFactory.createInclude(objectName, dataObjectInfo);
dataStream.getCurrentPage().addObject(includeObject); dataStream.getCurrentPage().addObject(includeObject);
} }



+ 5
- 3
src/java/org/apache/fop/afp/fonts/AFPFontInfo.java View File



import java.util.List; import java.util.List;


import org.apache.fop.fonts.FontTriplet;



/** /**
* FontInfo contains meta information on fonts * FontInfo contains meta information on fonts
public class AFPFontInfo { public class AFPFontInfo {


private AFPFont font; private AFPFont font;
private List/*<FontTriplet>*/ tripletList;
private List<FontTriplet> tripletList;


/** /**
* Main constructor * Main constructor
* @param afpFont The AFP Font * @param afpFont The AFP Font
* @param tripletList List of font triplets to associate with this 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.font = afpFont;
this.tripletList = tripletList; this.tripletList = tripletList;
} }
* *
* @return List of font triplets * @return List of font triplets
*/ */
public List/*<FontTriplet>*/ getFontTriplets() {
public List<FontTriplet> getFontTriplets() {
return tripletList; return tripletList;
} }



+ 14
- 6
src/java/org/apache/fop/afp/ioca/ImageContent.java View File

*/ */
public static final byte COMPID_G3_MMR = (byte)0x82; 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 */ /** the image size parameter */
private ImageSizeParameter imageSizeParameter = null; private ImageSizeParameter imageSizeParameter = null;


private byte ideSize = 1; private byte ideSize = 1;


/** the image compression */ /** the image compression */
private byte compression = (byte)0xC0;
private byte compression = (byte)0xC0; //Baseline DCT in case of JPEG compression


/** the image data */ /** the image data */
private byte[] data; private byte[] data;
* @param color the IDE color model. * @param color the IDE color model.
* @deprecated use {@link #setIDEStructureParameter(IDEStructureParameter)} instead * @deprecated use {@link #setIDEStructureParameter(IDEStructureParameter)} instead
*/ */
@Deprecated
public void setImageIDEColorModel(byte color) { public void setImageIDEColorModel(byte color) {
needIDEStructureParameter().setColorModel(color); needIDEStructureParameter().setColorModel(color);
} }
* @param subtractive true for subtractive mode, false for additive mode * @param subtractive true for subtractive mode, false for additive mode
* @deprecated use {@link #setIDEStructureParameter(IDEStructureParameter)} instead * @deprecated use {@link #setIDEStructureParameter(IDEStructureParameter)} instead
*/ */
@Deprecated
public void setSubtractive(boolean subtractive) { public void setSubtractive(boolean subtractive) {
needIDEStructureParameter().setSubtractive(subtractive); needIDEStructureParameter().setSubtractive(subtractive);
} }
private static final int MAX_DATA_LEN = 65535; private static final int MAX_DATA_LEN = 65535;


/** {@inheritDoc} */ /** {@inheritDoc} */
@Override
protected void writeContent(OutputStream os) throws IOException { protected void writeContent(OutputStream os) throws IOException {
if (imageSizeParameter != null) { if (imageSizeParameter != null) {
imageSizeParameter.writeToStream(os); imageSizeParameter.writeToStream(os);
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
@Override
protected void writeStart(OutputStream os) throws IOException { protected void writeStart(OutputStream os) throws IOException {
final byte[] startData = new byte[] { final byte[] startData = new byte[] {
(byte)0x91, // ID (byte)0x91, // ID
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
@Override
protected void writeEnd(OutputStream os) throws IOException { protected void writeEnd(OutputStream os) throws IOException {
final byte[] endData = new byte[] { final byte[] endData = new byte[] {
(byte)0x93, // ID (byte)0x93, // ID
(byte)0x95, // ID (byte)0x95, // ID
0x02, // Length 0x02, // Length
encoding, encoding,
0x01, // RECID
(byte)(encoding == COMPID_JPEG ? 0xFE : 0x01), // RECID
}; };
return encodingData; return encodingData;
} }
* @return byte[] The data stream. * @return byte[] The data stream.
*/ */
private byte[] getExternalAlgorithmParameter() { private byte[] getExternalAlgorithmParameter() {
if (encoding == (byte)0x83 && compression != 0) {
if (encoding == COMPID_JPEG && compression != 0) {
final byte[] extAlgData = new byte[] { final byte[] extAlgData = new byte[] {
(byte)0x95, // ID
(byte)0x9F, // ID
0x00, // Length 0x00, // Length
0x10, // ALGTYPE = Compression Algorithm 0x10, // ALGTYPE = Compression Algorithm
0x00, // Reserved 0x00, // Reserved
(byte)0x83, // COMPRID = JPEG
COMPID_JPEG, // COMPRID = JPEG
0x00, // Reserved 0x00, // Reserved
0x00, // Reserved 0x00, // Reserved
0x00, // Reserved 0x00, // Reserved
compression, // MARKER
compression, // MARKER
0x00, // Reserved 0x00, // Reserved
0x00, // Reserved 0x00, // Reserved
0x00, // Reserved 0x00, // Reserved

+ 2
- 2
src/java/org/apache/fop/afp/modca/AbstractDataObject.java View File

int height = objectAreaInfo.getHeight(); int height = objectAreaInfo.getHeight();
int widthRes = objectAreaInfo.getWidthRes(); int widthRes = objectAreaInfo.getWidthRes();
int heightRes = objectAreaInfo.getHeightRes(); int heightRes = objectAreaInfo.getHeightRes();
ObjectAreaDescriptor objectAreaDescriptor
= factory.createObjectAreaDescriptor(width, height, widthRes, heightRes);
ObjectAreaDescriptor objectAreaDescriptor = factory.createObjectAreaDescriptor(width,
height, widthRes, heightRes);
getObjectEnvironmentGroup().setObjectAreaDescriptor(objectAreaDescriptor); getObjectEnvironmentGroup().setObjectAreaDescriptor(objectAreaDescriptor);


// object area position // object area position

+ 1
- 1
src/java/org/apache/fop/afp/modca/GraphicsObject.java View File

final int leftEdge = 0; final int leftEdge = 0;
final int topEdge = 0; final int topEdge = 0;
GraphicsDataDescriptor graphicsDataDescriptor = factory.createGraphicsDataDescriptor( GraphicsDataDescriptor graphicsDataDescriptor = factory.createGraphicsDataDescriptor(
leftEdge, width, topEdge, height, widthRes, heightRes);
leftEdge, width, topEdge, height, widthRes, heightRes);


getObjectEnvironmentGroup().setDataDescriptor(graphicsDataDescriptor); getObjectEnvironmentGroup().setDataDescriptor(graphicsDataDescriptor);
} }

+ 1
- 1
src/java/org/apache/fop/afp/modca/ObjectContainer.java View File



ContainerDataDescriptor containerDataDescriptor ContainerDataDescriptor containerDataDescriptor
= factory.createContainerDataDescriptor( = factory.createContainerDataDescriptor(
dataWidth, dataHeight, widthRes, heightRes);
dataWidth, dataHeight, widthRes, heightRes);
getObjectEnvironmentGroup().setDataDescriptor(containerDataDescriptor); getObjectEnvironmentGroup().setDataDescriptor(containerDataDescriptor);
} }
} }

+ 4
- 4
src/java/org/apache/fop/afp/modca/Registry.java View File

package org.apache.fop.afp.modca; package org.apache.fop.afp.modca;


import java.util.Collections; import java.util.Collections;
import java.util.HashMap;


import org.apache.xmlgraphics.util.MimeConstants; import org.apache.xmlgraphics.util.MimeConstants;


private static final byte COMPID_TRUETYPE_OPENTYPE_FONT_COLLECTION_RESOURCE_OBJECT = 53; private static final byte COMPID_TRUETYPE_OPENTYPE_FONT_COLLECTION_RESOURCE_OBJECT = 53;


/** mime type entry mapping */ /** 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 */ /** singleton instance */
private static Registry instance = null; private static Registry instance = null;
* @return the MOD:CA object type * @return the MOD:CA object type
*/ */
public ObjectType getObjectType(String mimeType) { public ObjectType getObjectType(String mimeType) {
return (ObjectType)mimeObjectTypeMap.get(mimeType);
return mimeObjectTypeMap.get(mimeType);
} }


/** /**

+ 15
- 17
src/java/org/apache/fop/render/ImageHandlerRegistry.java View File

/** the logger */ /** the logger */
private static Log log = LogFactory.getLog(ImageHandlerRegistry.class); 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(); return h1.getPriority() - h2.getPriority();
} }
}; };


/** Map containing image handlers for various {@link Image} subclasses. */ /** 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 */ /** 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; private int handlerRegistrations;


* @param handler the ImageHandler instance * @param handler the ImageHandler instance
*/ */
public synchronized void addHandler(ImageHandler handler) { public synchronized void addHandler(ImageHandler handler) {
Class imageClass = handler.getSupportedImageClass();
Class<? extends Image> imageClass = handler.getSupportedImageClass();
//List //List
this.handlers.put(imageClass, handler); this.handlers.put(imageClass, handler);


//Sorted insert (sort by priority) //Sorted insert (sort by priority)
ListIterator iter = this.handlerList.listIterator();
ListIterator<ImageHandler> iter = this.handlerList.listIterator();
while (iter.hasNext()) { while (iter.hasNext()) {
ImageHandler h = (ImageHandler)iter.next();
ImageHandler h = iter.next();
if (HANDLER_COMPARATOR.compare(handler, h) < 0) { if (HANDLER_COMPARATOR.compare(handler, h) < 0) {
iter.previous(); iter.previous();
break; break;
* @return the image handler responsible for handling the image or null if none is available * @return the image handler responsible for handling the image or null if none is available
*/ */
public ImageHandler getHandler(RenderingContext targetContext, Image image) { 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)) { if (h.isCompatible(targetContext, image)) {
//Return the first handler in the prioritized list that is compatible //Return the first handler in the prioritized list that is compatible
return h; return h;
*/ */
public synchronized ImageFlavor[] getSupportedFlavors(RenderingContext context) { public synchronized ImageFlavor[] getSupportedFlavors(RenderingContext context) {
//Extract all ImageFlavors into a single array //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)) { if (handler.isCompatible(context, null)) {
ImageFlavor[] f = handler.getSupportedImageFlavors(); ImageFlavor[] f = handler.getSupportedImageFlavors();
for (int i = 0; i < f.length; i++) { for (int i = 0; i < f.length; i++) {
} }
} }
} }
return (ImageFlavor[])flavors.toArray(new ImageFlavor[flavors.size()]);
return flavors.toArray(new ImageFlavor[flavors.size()]);
} }


/** /**

+ 17
- 0
src/java/org/apache/fop/render/afp/AFPCustomizable.java View File

*/ */
void setDitheringQuality(float quality); 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 * Sets the output/device resolution
* *
*/ */
void setResourceLevelDefaults(AFPResourceLevelDefaults defaults); 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);

} }

+ 10
- 0
src/java/org/apache/fop/render/afp/AFPDocumentHandler.java View File

this.paintingState.setDitheringQuality(quality); this.paintingState.setDitheringQuality(quality);
} }


/** {@inheritDoc} */
public void setBitmapEncodingQuality(float quality) {
this.paintingState.setBitmapEncodingQuality(quality);
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public void setShadingMode(AFPShadingMode shadingMode) { public void setShadingMode(AFPShadingMode shadingMode) {
this.shadingMode = shadingMode; this.shadingMode = shadingMode;
return pageSegmentMap.get(uri); return pageSegmentMap.get(uri);
} }


/** {@inheritDoc} */
public void canEmbedJpeg(boolean canEmbed) {
paintingState.setCanEmbedJpeg(canEmbed);
}

} }

+ 2
- 9
src/java/org/apache/fop/render/afp/AFPImageHandler.java View File

*/ */
public static AFPObjectAreaInfo createObjectAreaInfo(AFPPaintingState paintingState, public static AFPObjectAreaInfo createObjectAreaInfo(AFPPaintingState paintingState,
Rectangle targetRect) { Rectangle targetRect) {
AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo();
AFPUnitConverter unitConv = paintingState.getUnitConverter(); AFPUnitConverter unitConv = paintingState.getUnitConverter();


int[] coords = unitConv.mpts2units(new float[] {targetRect.x, targetRect.y}); 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)); int width = Math.round(unitConv.mpt2units(targetRect.width));
objectAreaInfo.setWidth(width);


int height = Math.round(unitConv.mpt2units(targetRect.height)); int height = Math.round(unitConv.mpt2units(targetRect.height));
objectAreaInfo.setHeight(height);


int resolution = paintingState.getResolution(); 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; return objectAreaInfo;
} }



+ 19
- 0
src/java/org/apache/fop/render/afp/AFPImageHandlerRawCCITTFax.java View File



package org.apache.fop.render.afp; 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.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor; import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
ImageFlavor.RAW_CCITTFAX, ImageFlavor.RAW_CCITTFAX,
}; };


/** logging instance */
private final Log log = LogFactory.getLog(AFPImageHandlerRawJPEG.class);

/** {@inheritDoc} */ /** {@inheritDoc} */
@Override
protected void setAdditionalParameters(AFPDataObjectInfo dataObjectInfo, protected void setAdditionalParameters(AFPDataObjectInfo dataObjectInfo,
ImageRawStream image) { ImageRawStream image) {
AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)dataObjectInfo; AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)dataObjectInfo;
} }


/** {@inheritDoc} */ /** {@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() { protected AFPDataObjectInfo createDataObjectInfo() {
return new AFPImageObjectInfo(); return new AFPImageObjectInfo();
} }

+ 205
- 0
src/java/org/apache/fop/render/afp/AFPImageHandlerRawJPEG.java View File

/*
* 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;
}

}

+ 21
- 0
src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java View File



package org.apache.fop.render.afp; 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.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor; import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.impl.ImageRawEPS; import org.apache.xmlgraphics.image.loader.impl.ImageRawEPS;
ImageFlavor.RAW_EPS, ImageFlavor.RAW_EPS,
}; };


/** logging instance */
private final Log log = LogFactory.getLog(AFPImageHandlerRawJPEG.class);

/** {@inheritDoc} */ /** {@inheritDoc} */
public int getPriority() { public int getPriority() {
return 200; return 200;
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
@Override
protected AFPDataObjectInfo createDataObjectInfo() { protected AFPDataObjectInfo createDataObjectInfo() {
return new AFPDataObjectInfo(); 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} */ /** {@inheritDoc} */
public boolean isCompatible(RenderingContext targetContext, Image image) { public boolean isCompatible(RenderingContext targetContext, Image image) {
if (targetContext instanceof AFPRenderingContext) { if (targetContext instanceof AFPRenderingContext) {

+ 34
- 3
src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java View File

import java.awt.image.Raster; import java.awt.image.Raster;
import java.awt.image.RenderedImage; import java.awt.image.RenderedImage;
import java.awt.image.SampleModel; import java.awt.image.SampleModel;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;


import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;


import org.apache.xmlgraphics.image.loader.ImageInfo; import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageSize; import org.apache.xmlgraphics.image.loader.ImageSize;
import org.apache.xmlgraphics.image.loader.impl.ImageRendered; 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.ps.ImageEncodingHelper;
import org.apache.xmlgraphics.util.MimeConstants; import org.apache.xmlgraphics.util.MimeConstants;
import org.apache.xmlgraphics.util.UnitConv; import org.apache.xmlgraphics.util.UnitConv;
import org.apache.fop.afp.AFPPaintingState; import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.afp.AFPResourceInfo; import org.apache.fop.afp.AFPResourceInfo;
import org.apache.fop.afp.AFPResourceManager; import org.apache.fop.afp.AFPResourceManager;
import org.apache.fop.afp.ioca.ImageContent;
import org.apache.fop.afp.modca.ResourceObject; import org.apache.fop.afp.modca.ResourceObject;
import org.apache.fop.render.ImageHandler; import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RenderingContext; import org.apache.fop.render.RenderingContext;
functionSet = 45; //IOCA FS45 required for CMYK 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(); imageData = baos.toByteArray();
} }
} }
return false; 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);
}


}
} }

+ 32
- 12
src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java View File

import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List; import java.util.List;


import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.configuration.ConfigurationException;

import org.apache.fop.afp.AFPResourceLevel; import org.apache.fop.afp.AFPResourceLevel;
import org.apache.fop.afp.AFPResourceLevelDefaults; import org.apache.fop.afp.AFPResourceLevelDefaults;
import org.apache.fop.afp.fonts.AFPFont; import org.apache.fop.afp.fonts.AFPFont;
log.error("Mandatory font configuration element '<font-triplet...' is missing"); log.error("Mandatory font configuration element '<font-triplet...' is missing");
return null; 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); weight);
tripletList.add(triplet); tripletList.add(triplet);
} }


if (base14 != null) { if (base14 != null) {
try { 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 { try {
Typeface tf = (Typeface)clazz.newInstance();
Typeface tf = clazz.newInstance();
font.addCharacterSet(sizeMpt, font.addCharacterSet(sizeMpt,
CharacterSetBuilder.getInstance() CharacterSetBuilder.getInstance()
.build(characterset, codepage, encoding, tf)); .build(characterset, codepage, encoding, tf));
String base14 = afpFontCfg.getAttribute("base14-font", null); String base14 = afpFontCfg.getAttribute("base14-font", null);
if (base14 != null) { if (base14 != null) {
try { 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 { try {
Typeface tf = (Typeface)clazz.newInstance();
Typeface tf = clazz.newInstance();
characterSet = CharacterSetBuilder.getInstance() characterSet = CharacterSetBuilder.getInstance()
.build(characterset, codepage, encoding, tf); .build(characterset, codepage, encoding, tf);
} catch (Exception ie) { } catch (Exception ie) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Adding font " + afi.getAFPFont().getFontName()); 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) { for (int j = 0; j < fontTriplets.size(); ++j) {
FontTriplet triplet = (FontTriplet) fontTriplets.get(j); FontTriplet triplet = (FontTriplet) fontTriplets.get(j);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
boolean nativeImageSupport = imagesCfg.getAttributeAsBoolean("native", false); boolean nativeImageSupport = imagesCfg.getAttributeAsBoolean("native", false);
customizable.setNativeImagesSupported(nativeImageSupport); 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) // shading (filled rectangles)
Configuration shadingCfg = cfg.getChild("shading"); Configuration shadingCfg = cfg.getChild("shading");
AFPShadingMode shadingMode = AFPShadingMode.valueOf( AFPShadingMode shadingMode = AFPShadingMode.valueOf(
public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo)
throws FOPException { throws FOPException {
FontManager fontManager = userAgent.getFactory().getFontManager(); 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()); Configuration cfg = super.getRendererConfig(documentHandler.getMimeType());
if (cfg != null) { if (cfg != null) {

+ 6
- 11
src/java/org/apache/fop/render/afp/AFPSVGHandler.java View File

private AFPObjectAreaInfo createObjectAreaInfo(AFPPaintingState paintingState, private AFPObjectAreaInfo createObjectAreaInfo(AFPPaintingState paintingState,
int x, int y, int width, int height, int resolution) { int x, int y, int width, int height, int resolution) {
// set the data object parameters // set the data object parameters
AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo();


AffineTransform at = paintingState.getData().getTransform(); AffineTransform at = paintingState.getData().getTransform();
at.translate(x, y); 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(); AFPUnitConverter unitConv = paintingState.getUnitConverter();
objectAreaInfo.setWidth(Math.round(unitConv.mpt2units(width)));
objectAreaInfo.setHeight(Math.round(unitConv.mpt2units(height)));


int rotation = paintingState.getRotation(); 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; return objectAreaInfo;
} }



+ 1
- 2
src/java/org/apache/fop/render/afp/AbstractAFPImageHandlerRawStream.java View File

AFPPaintingState paintingState = afpContext.getPaintingState(); AFPPaintingState paintingState = afpContext.getPaintingState();
int resolution = paintingState.getResolution(); int resolution = paintingState.getResolution();
AFPObjectAreaInfo objectAreaInfo = dataObjectInfo.getObjectAreaInfo(); AFPObjectAreaInfo objectAreaInfo = dataObjectInfo.getObjectAreaInfo();
objectAreaInfo.setWidthRes(resolution);
objectAreaInfo.setHeightRes(resolution);
objectAreaInfo.setResolution(resolution);


// Image content // Image content
ImageRawStream imageStream = (ImageRawStream)image; ImageRawStream imageStream = (ImageRawStream)image;

+ 4
- 0
status.xml View File

documents. Example: the fix of marks layering will be such a case when it's done. documents. Example: the fix of marks layering will be such a case when it's done.
--> -->
<release version="FOP Trunk" date="TBD"> <release version="FOP Trunk" date="TBD">
<action context="Code" dev="PH" type="add" fixes-bug="52089" due-to="JM, Mehdi Houshmand">
Allow JPEG images to be embedded in an AFP document as is, without being decoded and
encoded.
</action>
<action context="Code" dev="PH" type="add" fixes-bug="52010" due-to="Mehdi Houshmand"> <action context="Code" dev="PH" type="add" fixes-bug="52010" due-to="Mehdi Houshmand">
Simplification of the build: Reduced code duplication and layout engine tests. Simplification of the build: Reduced code duplication and layout engine tests.
</action> </action>

+ 76
- 0
test/java/org/apache/fop/afp/AFPObjectAreaInfoTestCase.java View File

/*
* 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.afp;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;

/**
* Test case for {@link AFPObjectAreaInfo}.
*/
public class AFPObjectAreaInfoTestCase {

private AFPObjectAreaInfo sut;

/**
* Instantiate the system under test
*/
@Before
public void setUp() {
sut = new AFPObjectAreaInfo(1, 2, 3, 4, 5, 6);
}

/**
* Test the getter functions with arbitrary data.
*/
@Test
public void testGetters() {
assertEquals(1, sut.getX());
assertEquals(2, sut.getY());
assertEquals(3, sut.getWidth());
assertEquals(4, sut.getHeight());
assertEquals(5, sut.getWidthRes());
assertEquals(5, sut.getHeightRes());
assertEquals(6, sut.getRotation());
}

/**
* Test the resolution setters with arbitrary data.
*/
@Test
public void testSetters() {
assertEquals(5, sut.getWidthRes());
assertEquals(5, sut.getHeightRes());

sut.setResolution(20);
assertEquals(20, sut.getWidthRes());
assertEquals(20, sut.getHeightRes());

sut.setHeightRes(10);
assertEquals(20, sut.getWidthRes());
assertEquals(10, sut.getHeightRes());

sut.setWidthRes(9);
assertEquals(9, sut.getWidthRes());
assertEquals(10, sut.getHeightRes());
}
}

+ 61
- 0
test/java/org/apache/fop/afp/AFPPaintingStateTestCase.java View File

/*
* 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.afp;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;

/**
* Test case for {@link AFPPaintingState}.
*/
public class AFPPaintingStateTestCase {
private AFPPaintingState sut;

/**
* Set up the system under test
*/
@Before
public void setUp() {
sut = new AFPPaintingState();
}

/**
* Test {get,set}BitmapEncodingQuality()
*/
@Test
public void testGetSetBitmapEncodingQuality() {
sut.setBitmapEncodingQuality(0.5f);
assertEquals(0.5f, sut.getBitmapEncodingQuality(), 0.01f);

sut.setBitmapEncodingQuality(0.9f);
assertEquals(0.9f, sut.getBitmapEncodingQuality(), 0.01f);
}

/**
* Test {,set}CanEmbedJpeg
*/
public void testGetSetCanEmbedJpeg() {
assertEquals(false, sut.canEmbedJpeg());
sut.setCanEmbedJpeg(true);
assertEquals(true, sut.canEmbedJpeg());
}
}

+ 89
- 0
test/java/org/apache/fop/afp/AFPResourceManagerTestCase.java View File

/*
* 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.afp;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.junit.Before;
import org.junit.Test;

import org.apache.xmlgraphics.util.MimeConstants;

/**
* Test case for {@link AFPResourceManager}.
*/
public class AFPResourceManagerTestCase {

private AFPResourceManager sut;

@Before
public void setUp() throws IOException {
sut = new AFPResourceManager();
AFPPaintingState paintingState = new AFPPaintingState();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
DataStream stream = sut.createDataStream(paintingState, outStream);
stream.startPage(0, 0, 0, 10, 10);
}

/**
* Ensures that if tryIncludeObject() is called with a new object, it returns false suggesting
* that we have to create said object. However, if it is called with an object that has already
* been created, it returns true suggesting that we don't have to create that object again.
* Page-segment is false.
*
* @throws IOException if an I/O error occurs
*/
@Test
public void testTryIncludeObjectWithPageSegFalse() throws IOException {
AFPDataObjectInfo dataInfo = createAFPDataObjectInfo();
// An empty object needs to be created every time!
assertFalse(sut.tryIncludeObject(dataInfo));
sut.createObject(dataInfo);
assertTrue(sut.tryIncludeObject(dataInfo));
}

/**
* {@code testTryIncludeObjectWithPageSegFalse()} but with page-segment true.
*
* @throws IOException if an I/O error occurs
*/
@Test
public void testTryIncludeObjectWithPageSegTrue() throws IOException {
AFPDataObjectInfo dataInfo = createAFPDataObjectInfo();
dataInfo.setCreatePageSegment(true);
// An empty object needs to be created every time!
assertFalse(sut.tryIncludeObject(dataInfo));
sut.createObject(dataInfo);
assertTrue(sut.tryIncludeObject(dataInfo));
}

private AFPDataObjectInfo createAFPDataObjectInfo() {
AFPDataObjectInfo dataInfo = new AFPDataObjectInfo();
dataInfo.setMimeType(MimeConstants.MIME_TIFF);
dataInfo.setData(new byte[1]);
AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(0, 0, 10, 10, 1, 0);
dataInfo.setObjectAreaInfo(objectAreaInfo);
return dataInfo;
}
}

+ 6
- 3
test/java/org/apache/fop/afp/AFPTestSuite.java View File



package org.apache.fop.afp; package org.apache.fop.afp;


import org.apache.fop.afp.modca.IncludeObjectTestCase;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses; import org.junit.runners.Suite.SuiteClasses;


import org.apache.fop.afp.modca.IncludeObjectTestCase;

/** /**
* Test suite for FOP's AFP classes. * Test suite for FOP's AFP classes.
*/ */
@RunWith(Suite.class) @RunWith(Suite.class)
@SuiteClasses({ @SuiteClasses({
IncludeObjectTestCase.class,
AFPResourceUtilTestCase.class
IncludeObjectTestCase.class,
AFPResourceUtilTestCase.class,
AFPObjectAreaInfoTestCase.class,
AFPPaintingStateTestCase.class
}) })
public class AFPTestSuite { public class AFPTestSuite {
} }

+ 92
- 0
test/java/org/apache/fop/render/afp/AFPRendererConfiguratorTestCase.java View File

/*
* 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.io.IOException;

import org.junit.BeforeClass;
import org.junit.Test;
import org.xml.sax.SAXException;

import org.apache.fop.afp.AFPPaintingState;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory;

/**
* Test case for {@link AFPRendererConfigurator}.
*/
public class AFPRendererConfiguratorTestCase {
private static FOUserAgent userAgent;

private AFPRendererConfigurator sut;

/**
* The FOUserAgent only needs to be created once.
*/
@BeforeClass
public static void createUserAgent() {
userAgent = FopFactory.newInstance().newFOUserAgent();
}

/**
* Assigns an FOUserAgen with a config file at <code>uri</code>
*
* @param uri the URI of the config file
*/
private void setConfigFile(String uri) {
String confTestsDir = "test/resources/conf/afp/";
try {
userAgent.getFactory().setUserConfig(confTestsDir + uri);
sut = new AFPRendererConfigurator(userAgent);
} catch (IOException ioe) {
fail("IOException: " + ioe);
} catch (SAXException se) {
fail("SAXException: " + se);
}
}

/**
* Test several config files relating to JPEG images in AFP.
*
* @throws FOPException if an error is thrown
*/
@Test
public void testJpegImageConfig() throws FOPException {
testJpegSettings("no_image_config.xconf", 1.0f, false);
testJpegSettings("can_embed_jpeg.xconf", 1.0f, true);
testJpegSettings("bitmap_encode_quality.xconf", 0.5f, false);
}

private void testJpegSettings(String uri, float bitmapEncodingQual, boolean canEmbed)
throws FOPException {
AFPDocumentHandler docHandler = new AFPDocumentHandler();

setConfigFile(uri);
sut.configure(docHandler);

AFPPaintingState paintingState = docHandler.getPaintingState();
assertEquals(bitmapEncodingQual, paintingState.getBitmapEncodingQuality(), 0.01f);
assertEquals(canEmbed, paintingState.canEmbedJpeg());
}
}

+ 3
- 1
test/java/org/apache/fop/render/afp/AFPTestSuite.java View File

* Test suite for FOP's AFP output. * Test suite for FOP's AFP output.
*/ */
@RunWith(Suite.class) @RunWith(Suite.class)
@SuiteClasses({ NoOperationTestCase.class })
@SuiteClasses({
NoOperationTestCase.class,
AFPRendererConfiguratorTestCase.class })
public class AFPTestSuite { public class AFPTestSuite {
} }

+ 16
- 0
test/resources/conf/afp/bitmap_encode_quality.xconf View File

<?xml version="1.0" encoding="UTF-8"?>
<fop version="1.0">
<base>.</base>
<source-resolution>72</source-resolution>
<target-resolution>72</target-resolution>
<image-loading>
</image-loading>
<default-page-settings height="11in" width="8.26in"/>
<renderers>
<renderer mime="application/x-afp">
<images>
<jpeg allow-embedding="false" bitmap-encoding-quality="0.5"/>
</images>
</renderer>
</renderers>
</fop>

+ 16
- 0
test/resources/conf/afp/can_embed_jpeg.xconf View File

<?xml version="1.0" encoding="UTF-8"?>
<fop version="1.0">
<base>.</base>
<source-resolution>72</source-resolution>
<target-resolution>72</target-resolution>
<image-loading>
</image-loading>
<default-page-settings height="11in" width="8.26in"/>
<renderers>
<renderer mime="application/x-afp">
<images>
<jpeg allow-embedding="true"/>
</images>
</renderer>
</renderers>
</fop>

+ 13
- 0
test/resources/conf/afp/no_image_config.xconf View File

<?xml version="1.0" encoding="UTF-8"?>
<fop version="1.0">
<base>.</base>
<source-resolution>72</source-resolution>
<target-resolution>72</target-resolution>
<image-loading>
</image-loading>
<default-page-settings height="11in" width="8.26in"/>
<renderers>
<renderer mime="application/x-afp">
</renderer>
</renderers>
</fop>

Loading…
Cancel
Save