瀏覽代碼

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 年之前
父節點
當前提交
fd263a114c
共有 35 個檔案被更改,包括 874 行新增139 行删除
  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 查看文件

@@ -796,6 +796,23 @@ Note that the value of the encoding attribute in the example is the double-byte
</p>
<source><![CDATA[
<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 id="afp-goca-config">
<title>GOCA (Vector Graphics)</title>

+ 1
- 0
src/java/META-INF/services/org.apache.fop.render.ImageHandler 查看文件

@@ -17,4 +17,5 @@ org.apache.fop.render.afp.AFPImageHandlerRenderedImage
org.apache.fop.render.afp.AFPImageHandlerGraphics2D
org.apache.fop.render.afp.AFPImageHandlerRawStream
org.apache.fop.render.afp.AFPImageHandlerRawCCITTFax
org.apache.fop.render.afp.AFPImageHandlerRawJPEG
org.apache.fop.render.afp.AFPImageHandlerSVG

+ 3
- 0
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);

+ 4
- 8
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

+ 2
- 1
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

+ 38
- 53
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;
}

}

+ 43
- 0
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
@@ -219,6 +225,24 @@ public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState
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
* is disabled for wider compatibility. When disabled, any CMYK image is
@@ -259,6 +283,25 @@ public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState
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
*

+ 1
- 2
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);
}


+ 5
- 3
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;
}


+ 14
- 6
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

+ 2
- 2
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

+ 1
- 1
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);
}

+ 1
- 1
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);
}
}

+ 4
- 4
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);
}

/**

+ 15
- 17
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()]);
}

/**

+ 17
- 0
src/java/org/apache/fop/render/afp/AFPCustomizable.java 查看文件

@@ -71,6 +71,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
*
@@ -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);

}

+ 10
- 0
src/java/org/apache/fop/render/afp/AFPDocumentHandler.java 查看文件

@@ -428,6 +428,11 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
this.paintingState.setDitheringQuality(quality);
}

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

}

+ 2
- 9
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;
}


+ 19
- 0
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();
}

+ 205
- 0
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;
}

}

+ 21
- 0
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,10 +65,22 @@ 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) {

+ 34
- 3
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);
}

}
}

+ 32
- 12
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) {

+ 6
- 11
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;
}


+ 1
- 2
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;

+ 4
- 0
status.xml 查看文件

@@ -60,6 +60,10 @@
documents. Example: the fix of marks layering will be such a case when it's done.
-->
<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">
Simplification of the build: Reduced code duplication and layout engine tests.
</action>

+ 76
- 0
test/java/org/apache/fop/afp/AFPObjectAreaInfoTestCase.java 查看文件

@@ -0,0 +1,76 @@
/*
* 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 查看文件

@@ -0,0 +1,61 @@
/*
* 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 查看文件

@@ -0,0 +1,89 @@
/*
* 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 查看文件

@@ -19,18 +19,21 @@

package org.apache.fop.afp;

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

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

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

+ 92
- 0
test/java/org/apache/fop/render/afp/AFPRendererConfiguratorTestCase.java 查看文件

@@ -0,0 +1,92 @@
/*
* 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 查看文件

@@ -27,6 +27,8 @@ import org.junit.runners.Suite.SuiteClasses;
* Test suite for FOP's AFP output.
*/
@RunWith(Suite.class)
@SuiteClasses({ NoOperationTestCase.class })
@SuiteClasses({
NoOperationTestCase.class,
AFPRendererConfiguratorTestCase.class })
public class AFPTestSuite {
}

+ 16
- 0
test/resources/conf/afp/bitmap_encode_quality.xconf 查看文件

@@ -0,0 +1,16 @@
<?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 查看文件

@@ -0,0 +1,16 @@
<?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 查看文件

@@ -0,0 +1,13 @@
<?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…
取消
儲存