diff options
author | Jeremias Maerki <jeremias@apache.org> | 2008-03-27 14:29:44 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2008-03-27 14:29:44 +0000 |
commit | f1e20bb4e5ed277795329e5b05cf1f2485b9387a (patch) | |
tree | 5a729248f7c9aad876f2ad91a2723cb9aedae709 /src/java/org/apache/fop/render/pdf | |
parent | 36be5975f91f0a4dd17aefed11669153df2fed1b (diff) | |
download | xmlgraphics-fop-f1e20bb4e5ed277795329e5b05cf1f2485b9387a.tar.gz xmlgraphics-fop-f1e20bb4e5ed277795329e5b05cf1f2485b9387a.zip |
When a JPEG image is embedded, an optionally embedded color profile is filtered out as it's already embedded separately in the PDF file.
Worked around a problem (PDF renderer) with JPEG image containing RGB color profiles which are not sRGB. The images drifted into yellow. The color profile is simply disabled in this case. Please let us know if you know what the problem could be.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@641827 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/render/pdf')
-rw-r--r-- | src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java | 10 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/pdf/ImageRawJPEGAdapter.java | 101 |
2 files changed, 109 insertions, 2 deletions
diff --git a/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java b/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java index b676ad6d5..caf8928ac 100644 --- a/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java +++ b/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java @@ -81,7 +81,7 @@ public abstract class AbstractImageAdapter implements PDFImage { /** {@inheritDoc} */ public void setup(PDFDocument doc) { - ICC_Profile prof = image.getICCProfile(); + ICC_Profile prof = getEffectiveICCProfile(); PDFDeviceColorSpace pdfCS = toPDFColorSpace(getImageColorSpace()); if (prof != null) { pdfICCStream = setupColorProfile(doc, prof, pdfCS); @@ -100,6 +100,14 @@ public abstract class AbstractImageAdapter implements PDFImage { } } + /** + * Returns the effective ICC profile for the image. + * @return an ICC profile or null + */ + protected ICC_Profile getEffectiveICCProfile() { + return image.getICCProfile(); + } + private static PDFICCStream setupColorProfile(PDFDocument doc, ICC_Profile prof, PDFDeviceColorSpace pdfCS) { boolean defaultsRGB = ColorProfileUtil.isDefaultsRGB(prof); diff --git a/src/java/org/apache/fop/render/pdf/ImageRawJPEGAdapter.java b/src/java/org/apache/fop/render/pdf/ImageRawJPEGAdapter.java index 4b0ce4a85..1c8fceb50 100644 --- a/src/java/org/apache/fop/render/pdf/ImageRawJPEGAdapter.java +++ b/src/java/org/apache/fop/render/pdf/ImageRawJPEGAdapter.java @@ -18,19 +18,33 @@ /* $Id$ */ package org.apache.fop.render.pdf; +import java.awt.color.ICC_Profile; +import java.io.DataInput; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; +import org.apache.commons.io.IOUtils; + import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; +import org.apache.xmlgraphics.image.loader.impl.JPEGConstants; +import org.apache.xmlgraphics.image.loader.impl.JPEGFile; +import org.apache.xmlgraphics.image.loader.util.ImageUtil; import org.apache.fop.pdf.DCTFilter; import org.apache.fop.pdf.PDFDeviceColorSpace; import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFFilter; import org.apache.fop.pdf.PDFFilterList; +import org.apache.fop.util.ColorProfileUtil; /** * PDFImage implementation for the PDF renderer which handles raw JPEG images. + * <p> + * The JPEG is copied to the XObject's stream as-is but some elements (marker segments) are + * filtered. For example, an embedded color profile is filtered since it is already added as + * a PDF object and associated with the XObject. This way, the PDF file size is kept as small + * as possible. */ public class ImageRawJPEGAdapter extends AbstractImageAdapter { @@ -68,6 +82,21 @@ public class ImageRawJPEGAdapter extends AbstractImageAdapter { } /** {@inheritDoc} */ + protected ICC_Profile getEffectiveICCProfile() { + ICC_Profile profile = super.getEffectiveICCProfile(); + if (profile != null + && profile.getNumComponents() == 3 + && !ColorProfileUtil.isDefaultsRGB(profile)) { + //RGB profiles which are not sRGB don't seem to work. + //Without this override, the image drifts into yellow for an unknown reason. + //TODO Find out why this happens. + //Test using a JPEG images with, for example, "Adobe RGB 1998" color profile. + profile = null; + } + return profile; + } + + /** {@inheritDoc} */ public int getBitsPerComponent() { return 8; } @@ -84,7 +113,77 @@ public class ImageRawJPEGAdapter extends AbstractImageAdapter { /** {@inheritDoc} */ public void outputContents(OutputStream out) throws IOException { - getImage().writeTo(out); + InputStream in = getImage().createInputStream(); + in = ImageUtil.decorateMarkSupported(in); + try { + JPEGFile jpeg = new JPEGFile(in); + DataInput din = jpeg.getDataInput(); + + //Copy the whole JPEG file except: + // - the ICC profile + //TODO Thumbnails could safely be skipped, too. + //TODO Metadata (XMP, IPTC, EXIF) could safely be skipped, too. + while (true) { + int reclen; + int segID = jpeg.readMarkerSegment(); + switch (segID) { + case JPEGConstants.SOI: + out.write(0xFF); + out.write(segID); + break; + case JPEGConstants.EOI: + case JPEGConstants.SOS: + out.write(0xFF); + out.write(segID); + IOUtils.copy(in, out); //Just copy the rest! + return; + /* + case JPEGConstants.APP1: //Metadata + case JPEGConstants.APPD: + jpeg.skipCurrentMarkerSegment(); + break;*/ + case JPEGConstants.APP2: //ICC (see ICC1V42.pdf) + boolean skipICCProfile = false; + in.mark(16); + try { + reclen = jpeg.readSegmentLength(); + // Check for ICC profile + byte[] iccString = new byte[11]; + din.readFully(iccString); + din.skipBytes(1); //string terminator (null byte) + + if ("ICC_PROFILE".equals(new String(iccString, "US-ASCII"))) { + skipICCProfile = (this.image.getICCProfile() != null); + } + } finally { + in.reset(); + } + if (skipICCProfile) { + //ICC profile is skipped as it is already embedded as a PDF object + jpeg.skipCurrentMarkerSegment(); + break; + } + default: + out.write(0xFF); + out.write(segID); + + reclen = jpeg.readSegmentLength(); + //write short + out.write((reclen >>> 8) & 0xFF); + out.write((reclen >>> 0) & 0xFF); + int left = reclen - 2; + byte[] buf = new byte[2048]; + while (left > 0) { + int part = Math.min(buf.length, left); + din.readFully(buf, 0, part); + out.write(buf, 0, part); + left -= part; + } + } + } + } finally { + IOUtils.closeQuietly(in); + } } /** {@inheritDoc} */ |