aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/java/org/apache/fop/pdf/AlphaRasterImage.java35
-rw-r--r--src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java12
-rw-r--r--src/java/org/apache/fop/svg/PDFGraphics2D.java237
-rw-r--r--src/java/org/apache/fop/svg/PDFImageElementBridge.java36
4 files changed, 133 insertions, 187 deletions
diff --git a/src/java/org/apache/fop/pdf/AlphaRasterImage.java b/src/java/org/apache/fop/pdf/AlphaRasterImage.java
index be476bdb2..0b83cc3d6 100644
--- a/src/java/org/apache/fop/pdf/AlphaRasterImage.java
+++ b/src/java/org/apache/fop/pdf/AlphaRasterImage.java
@@ -22,6 +22,8 @@ package org.apache.fop.pdf;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
import java.io.IOException;
import java.io.OutputStream;
@@ -137,18 +139,37 @@ public class AlphaRasterImage implements PDFImage {
throw new UnsupportedOperationException(
"Expected only one band/component for the alpha channel");
}
+
+ //...and write the Raster line by line with a reusable buffer
int dataType = alpha.getDataBuffer().getDataType();
- if (dataType != DataBuffer.TYPE_BYTE) {
+ if (dataType == DataBuffer.TYPE_BYTE) {
+ byte[] line = new byte[nbands * w];
+ for (int y = 0; y < h; y++) {
+ alpha.getDataElements(0, y, w, 1, line);
+ out.write(line);
+ }
+ } else if (dataType == DataBuffer.TYPE_INT) {
+ //Is there an better way to get a 8bit raster from a TYPE_INT raster?
+ int shift = 24;
+ SampleModel sampleModel = alpha.getSampleModel();
+ if (sampleModel instanceof SinglePixelPackedSampleModel) {
+ SinglePixelPackedSampleModel m = (SinglePixelPackedSampleModel)sampleModel;
+ shift = m.getBitOffsets()[0];
+ }
+ int[] iline = new int[nbands * w];
+ byte[] line = new byte[nbands * w];
+ for (int y = 0; y < h; y++) {
+ alpha.getDataElements(0, y, w, 1, iline);
+ for (int i = 0; i < w; i++) {
+ line[i] = (byte)(iline[i] >> shift);
+ }
+ out.write(line);
+ }
+ } else {
throw new UnsupportedOperationException("Unsupported DataBuffer type: "
+ alpha.getDataBuffer().getClass().getName());
}
- //...and write the Raster line by line with a reusable buffer
- byte[] line = new byte[nbands * w];
- for (int y = 0; y < h; y++) {
- alpha.getDataElements(0, y, w, 1, line);
- out.write(line);
- }
}
/** {@inheritDoc} */
diff --git a/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java b/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java
index cd80a6797..d9fd614cc 100644
--- a/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java
+++ b/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java
@@ -59,6 +59,9 @@ public abstract class AbstractImageAdapter implements PDFImage {
public AbstractImageAdapter(Image image, String key) {
this.image = image;
this.key = key;
+ if (log.isDebugEnabled()) {
+ log.debug("New ImageAdapter created for key: " + key);
+ }
}
/** {@inheritDoc} */
@@ -96,11 +99,16 @@ public abstract class AbstractImageAdapter implements PDFImage {
pdfICCStream = cs.getICCStream();
}
} else {
- if (cs == null && "sRGB".equals(desc)) {
+ if (cs == null && desc.startsWith("sRGB")) {
//It's the default sRGB profile which we mapped to DefaultRGB in PDFRenderer
cs = doc.getResources().getColorSpace("DefaultRGB");
}
- pdfICCStream = cs.getICCStream();
+ if (cs != null) {
+ pdfICCStream = cs.getICCStream();
+ } else {
+ //DefaultRGB hasn't been mapped to sRGB
+ //(that's the case with a plain PDFGraphics2D)
+ }
}
}
if (doc.getProfile().getPDFAMode().isPDFA1LevelB()) {
diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java
index fdc54b48f..864809ebe 100644
--- a/src/java/org/apache/fop/svg/PDFGraphics2D.java
+++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java
@@ -41,7 +41,6 @@ import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.Raster;
@@ -65,6 +64,7 @@ import org.apache.batik.gvt.PatternPaint;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageSize;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
@@ -86,7 +86,6 @@ import org.apache.fop.pdf.PDFGState;
import org.apache.fop.pdf.PDFImage;
import org.apache.fop.pdf.PDFImageXObject;
import org.apache.fop.pdf.PDFLink;
-import org.apache.fop.pdf.PDFName;
import org.apache.fop.pdf.PDFNumber;
import org.apache.fop.pdf.PDFPattern;
import org.apache.fop.pdf.PDFResourceContext;
@@ -94,6 +93,7 @@ import org.apache.fop.pdf.PDFResources;
import org.apache.fop.pdf.PDFState;
import org.apache.fop.pdf.PDFText;
import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.pdf.ImageRawCCITTFaxAdapter;
import org.apache.fop.render.pdf.ImageRawJPEGAdapter;
import org.apache.fop.render.pdf.ImageRenderedAdapter;
import org.apache.fop.util.ColorExt;
@@ -143,10 +143,10 @@ public class PDFGraphics2D extends AbstractGraphics2D {
protected int baseLevel = 0;
/**
- * The count of JPEG images added to document so they recieve
+ * The count of natively handled images added to document so they receive
* unique keys.
*/
- protected int[] jpegCount = {0};
+ protected int nativeCount = 0;
/**
* The current font information.
@@ -232,7 +232,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
this.pageRef = g.pageRef;
this.graphicsState = g.graphicsState;
this.currentStream = g.currentStream;
- this.jpegCount = g.jpegCount;
+ this.nativeCount = g.nativeCount;
this.outputStream = g.outputStream;
this.ovFontState = g.ovFontState;
}
@@ -401,44 +401,41 @@ public class PDFGraphics2D extends AbstractGraphics2D {
}
/**
- * Add a JPEG image directly to the PDF document.
- * This is used by the PDFImageElementBridge to draw a JPEG
- * directly into the pdf document rather than converting the image into
+ * Add a natively handled image directly to the PDF document.
+ * This is used by the PDFImageElementBridge to draw a natively handled image
+ * (like JPEG or CCITT images)
+ * directly into the PDF document rather than converting the image into
* a bitmap and increasing the size.
*
- * @param jpeg the jpeg image to draw
+ * @param image the image to draw
* @param x the x position
* @param y the y position
* @param width the width to draw the image
* @param height the height to draw the image
*/
- public void addJpegImage(ImageRawJPEG jpeg, float x, float y,
+ void addNativeImage(org.apache.xmlgraphics.image.loader.Image image, float x, float y,
float width, float height) {
preparePainting();
- // Need to include hash code as when invoked from FO you
- // may have several 'independent' PDFGraphics2D so the
- // count is not enough.
- String key = "__AddJPEG_" + hashCode() + "_" + jpegCount[0];
- jpegCount[0]++;
- PDFImage pdfimage = new ImageRawJPEGAdapter(jpeg, key);
- PDFName imageName = this.pdfDoc.addImage(resourceContext,
- pdfimage).getName();
- AffineTransform at = getTransform();
- double[] matrix = new double[6];
- at.getMatrix(matrix);
- currentStream.write("q\n");
- if (!at.isIdentity()) {
- concatMatrix(matrix);
+ String key = image.getInfo().getOriginalURI();
+ if (key == null) {
+ // Need to include hash code as when invoked from FO you
+ // may have several 'independent' PDFGraphics2D so the
+ // count is not enough.
+ key = "__AddNative_" + hashCode() + "_" + nativeCount;
+ nativeCount++;
}
- Shape imclip = getClip();
- writeClip(imclip);
-
- currentStream.write("" + width + " 0 0 "
- + (-height) + " "
- + x + " "
- + (y + height) + " cm\n"
- + imageName + " Do\nQ\n");
-
+
+ PDFImage pdfImage;
+ if (image instanceof ImageRawJPEG) {
+ pdfImage = new ImageRawJPEGAdapter((ImageRawJPEG)image, key);
+ } else if (image instanceof ImageRawCCITTFax) {
+ pdfImage = new ImageRawCCITTFaxAdapter((ImageRawCCITTFax)image, key);
+ } else {
+ throw new IllegalArgumentException(
+ "Unsupported Image subclass: " + image.getClass().getName());
+ }
+
+ PDFXObject xObject = this.pdfDoc.addImage(resourceContext, pdfImage);
if (outputStream != null) {
try {
this.pdfDoc.output(outputStream);
@@ -446,6 +443,10 @@ public class PDFGraphics2D extends AbstractGraphics2D {
// ignore exception, will be thrown again later
}
}
+
+ AffineTransform at = new AffineTransform();
+ at.translate(x, y);
+ useXObject(xObject, at, width, height);
}
/**
@@ -492,40 +493,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
BufferedImage.TYPE_INT_ARGB);
}
- /**
- * Draws as much of the specified image as has already been scaled
- * to fit inside the specified rectangle.
- * <p>
- * The image is drawn inside the specified rectangle of this
- * graphics context's coordinate space, and is scaled if
- * necessary. Transparent pixels do not affect whatever pixels
- * are already there.
- * <p>
- * This method returns immediately in all cases, even if the
- * entire image has not yet been scaled, dithered, and converted
- * for the current output device.
- * If the current output representation is not yet complete, then
- * <code>drawImage</code> returns <code>false</code>. As more of
- * the image becomes available, the process that draws the image notifies
- * the image observer by calling its <code>imageUpdate</code> method.
- * <p>
- * A scaled version of an image will not necessarily be
- * available immediately just because an unscaled version of the
- * image has been constructed for this output device. Each size of
- * the image may be cached separately and generated from the original
- * data in a separate image production sequence.
- * @param img the specified image to be drawn.
- * @param x the <i>x</i> coordinate.
- * @param y the <i>y</i> coordinate.
- * @param width the width of the rectangle.
- * @param height the height of the rectangle.
- * @param observer object to be notified as more of
- * the image is converted.
- * @return true if the image was drawn
- * @see java.awt.Image
- * @see java.awt.image.ImageObserver
- * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
- */
+ /** {@inheritDoc} */
public boolean drawImage(Image img, int x, int y, int width, int height,
ImageObserver observer) {
preparePainting();
@@ -533,8 +501,9 @@ public class PDFGraphics2D extends AbstractGraphics2D {
// the pdf document. If so, we just reuse the reference;
// otherwise we have to build a FopImage and add it to the pdf
// document
- PDFXObject imageInfo = pdfDoc.getXObject("TempImage:" + img.toString());
- if (imageInfo == null) {
+ String key = "TempImage:" + img.toString();
+ PDFXObject xObject = pdfDoc.getXObject(key);
+ if (xObject == null) {
// OK, have to build and add a PDF image
Dimension size = new Dimension(width, height);
@@ -553,92 +522,14 @@ public class PDFGraphics2D extends AbstractGraphics2D {
}
g.dispose();
- final byte[] result = new byte[buf.getWidth() * buf.getHeight() * 3 /*for RGB*/];
- byte[] mask = new byte[buf.getWidth() * buf.getHeight()];
- boolean hasMask = false;
- //boolean binaryMask = true;
-
- Raster raster = buf.getData();
- DataBuffer bd = raster.getDataBuffer();
-
- int count = 0;
- int maskpos = 0;
- int[] iarray;
- int i, j, val, alpha;
- switch (bd.getDataType()) {
- case DataBuffer.TYPE_INT:
- int[][] idata = ((DataBufferInt)bd).getBankData();
- for (i = 0; i < idata.length; i++) {
- iarray = idata[i];
- for (j = 0; j < iarray.length; j++) {
- val = iarray[j];
- alpha = val >>> 24;
- mask[maskpos++] = (byte)(alpha & 0xFF);
- if (alpha != 255) {
- hasMask = true;
- }
- result[count++] = (byte)((val >> 16) & 0xFF);
- result[count++] = (byte)((val >> 8) & 0xFF);
- result[count++] = (byte)((val) & 0xFF);
- }
- }
- break;
- default:
- // error
- break;
- }
- String ref = null;
- if (hasMask) {
- // if the mask is binary then we could convert it into a bitmask
- BitmapImage fopimg = new BitmapImage("TempImageMask:"
- + img.toString(), buf.getWidth(),
- buf.getHeight(), mask, null);
- fopimg.setColorSpace(new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_GRAY));
- PDFImageXObject xobj = pdfDoc.addImage(resourceContext, fopimg);
- ref = xobj.referencePDF();
-
- if (outputStream != null) {
- try {
- this.pdfDoc.output(outputStream);
- } catch (IOException ioe) {
- // ignore exception, will be thrown again later
- }
- }
- } else {
- mask = null;
- }
-
- BitmapImage fopimg = new BitmapImage("TempImage:"
- + img.toString(), buf.getWidth(),
- buf.getHeight(), result, ref);
- imageInfo = pdfDoc.addImage(resourceContext, fopimg);
- //int xObjectNum = imageInfo.getXNumber();
-
- if (outputStream != null) {
- try {
- this.pdfDoc.output(outputStream);
- } catch (IOException ioe) {
- // ignore exception, will be thrown again later
- }
- }
+ xObject = addRenderedImage(key, buf);
} else {
- resourceContext.getPDFResources().addXObject(imageInfo);
+ resourceContext.getPDFResources().addXObject(xObject);
}
- // now do any transformation required and add the actual image
- // placement instance
- AffineTransform at = getTransform();
- double[] matrix = new double[6];
- at.getMatrix(matrix);
- currentStream.write("q\n");
- if (!at.isIdentity()) {
- concatMatrix(matrix);
- }
- Shape imclip = getClip();
- writeClip(imclip);
- currentStream.write("" + width + " 0 0 " + (-height) + " " + x
- + " " + (y + height) + " cm\n"
- + imageInfo.getName() + " Do\nQ\n");
+ AffineTransform at = new AffineTransform();
+ at.translate(x, y);
+ useXObject(xObject, at, width, height);
return true;
}
@@ -1342,18 +1233,24 @@ public class PDFGraphics2D extends AbstractGraphics2D {
/** {@inheritDoc} */
public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
- preparePainting();
String key = "TempImage:" + img.toString();
+ drawInnerRenderedImage(key, img, xform);
+ }
+
+ /** {@inheritDoc} */
+ public void drawInnerRenderedImage(String key, RenderedImage img, AffineTransform xform) {
+ preparePainting();
PDFXObject xObject = pdfDoc.getXObject(key);
if (xObject == null) {
- ImageInfo info = new ImageInfo(null, "image/unknown");
- ImageSize size = new ImageSize(img.getWidth(), img.getHeight(), 72);
- info.setSize(size);
- ImageRendered imgRend = new ImageRendered(info, img, null);
- ImageRenderedAdapter adapter = new ImageRenderedAdapter(imgRend, key);
- xObject = pdfDoc.addImage(resourceContext, adapter);
+ xObject = addRenderedImage(key, img);
+ } else {
+ resourceContext.getPDFResources().addXObject(xObject);
}
+ useXObject(xObject, xform, img.getWidth(), img.getHeight());
+ }
+
+ private void useXObject(PDFXObject xObject, AffineTransform xform, float width, float height) {
// now do any transformation required and add the actual image
// placement instance
currentStream.write("q\n");
@@ -1361,11 +1258,29 @@ public class PDFGraphics2D extends AbstractGraphics2D {
Shape imclip = getClip();
writeClip(imclip);
concatMatrix(xform);
- currentStream.write("" + img.getWidth() + " 0 0 " + (-img.getHeight()) + " 0"
- + " " + (img.getHeight()) + " cm\n"
+ String w = PDFNumber.doubleOut(width, DEC);
+ String h = PDFNumber.doubleOut(height, DEC);
+ currentStream.write("" + w + " 0 0 -" + h + " 0 " + h + " cm\n"
+ xObject.getName() + " Do\nQ\n");
}
+ private PDFXObject addRenderedImage(String key, RenderedImage img) {
+ ImageInfo info = new ImageInfo(null, "image/unknown");
+ ImageSize size = new ImageSize(img.getWidth(), img.getHeight(), 72);
+ info.setSize(size);
+ ImageRendered imgRend = new ImageRendered(info, img, null);
+ ImageRenderedAdapter adapter = new ImageRenderedAdapter(imgRend, key);
+ PDFXObject xObject = pdfDoc.addImage(resourceContext, adapter);
+ if (outputStream != null) {
+ try {
+ this.pdfDoc.output(outputStream);
+ } catch (IOException ioe) {
+ // ignore exception, will be thrown again later
+ }
+ }
+ return xObject;
+ }
+
/** {@inheritDoc} */
public void drawRenderableImage(RenderableImage img,
AffineTransform xform) {
diff --git a/src/java/org/apache/fop/svg/PDFImageElementBridge.java b/src/java/org/apache/fop/svg/PDFImageElementBridge.java
index a2542e86f..c3698b837 100644
--- a/src/java/org/apache/fop/svg/PDFImageElementBridge.java
+++ b/src/java/org/apache/fop/svg/PDFImageElementBridge.java
@@ -39,6 +39,7 @@ import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.image.loader.ImageSessionContext;
import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
+import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
@@ -56,6 +57,7 @@ public class PDFImageElementBridge extends SVGImageElementBridge {
private final ImageFlavor[] supportedFlavors = new ImageFlavor[]
{ImageFlavor.RAW_JPEG,
+ ImageFlavor.RAW_CCITTFAX,
ImageFlavor.GRAPHICS2D,
ImageFlavor.XML_DOM};
/**
@@ -90,9 +92,9 @@ public class PDFImageElementBridge extends SVGImageElementBridge {
}
}
if (image instanceof ImageRawJPEG) {
- ImageRawJPEG jpegImage = (ImageRawJPEG)image;
- specializedNode = new PDFJpegNode(jpegImage, ctx, imageElement, purl);
-
+ specializedNode = new LoaderImageNode(image, ctx, imageElement, purl);
+ } else if (image instanceof ImageRawCCITTFax) {
+ specializedNode = new LoaderImageNode(image, ctx, imageElement, purl);
} else if (image instanceof ImageGraphics2D) {
ImageGraphics2D g2dImage = (ImageGraphics2D)image;
specializedNode = new Graphics2DNode(g2dImage);
@@ -135,29 +137,29 @@ public class PDFImageElementBridge extends SVGImageElementBridge {
/**
- * A PDF jpeg node.
- * This holds a jpeg image so that it can be drawn into
+ * An image node for natively handled Image instance.
+ * This holds a natively handled image so that it can be drawn into
* the PDFGraphics2D.
*/
- public class PDFJpegNode extends AbstractGraphicsNode {
+ public class LoaderImageNode extends AbstractGraphicsNode {
- private ImageRawJPEG jpeg;
+ private Image image;
private BridgeContext ctx;
private Element imageElement;
private ParsedURL purl;
private GraphicsNode origGraphicsNode = null;
/**
- * Create a new PDF JPEG node for drawing JPEG images
- * into pdf graphics.
- * @param j the JPEG image
+ * Create a new image node for drawing natively handled images
+ * into PDF graphics.
+ * @param image the JPEG image
* @param ctx the bridge context
* @param imageElement the SVG image element
* @param purl the URL to the image
*/
- public PDFJpegNode(ImageRawJPEG j, BridgeContext ctx,
+ public LoaderImageNode(Image image, BridgeContext ctx,
Element imageElement, ParsedURL purl) {
- this.jpeg = j;
+ this.image = image;
this.ctx = ctx;
this.imageElement = imageElement;
this.purl = purl;
@@ -175,9 +177,9 @@ public class PDFImageElementBridge extends SVGImageElementBridge {
float x = 0;
float y = 0;
try {
- float width = jpeg.getSize().getWidthPx();
- float height = jpeg.getSize().getHeightPx();
- pdfg.addJpegImage(jpeg, x, y, width, height);
+ float width = image.getSize().getWidthPx();
+ float height = image.getSize().getHeightPx();
+ pdfg.addNativeImage(image, x, y, width, height);
} catch (Exception e) {
ctx.getUserAgent().displayError(e);
}
@@ -203,8 +205,8 @@ public class PDFImageElementBridge extends SVGImageElementBridge {
/** {@inheritDoc} */
public Rectangle2D getPrimitiveBounds() {
return new Rectangle2D.Double(0, 0,
- jpeg.getSize().getWidthPx(),
- jpeg.getSize().getHeightPx());
+ image.getSize().getWidthPx(),
+ image.getSize().getHeightPx());
}
/** {@inheritDoc} */