From 9cb8e3b0f34379dc67101f20fe52966d73763b48 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Fri, 24 Mar 2006 08:56:55 +0000 Subject: [PATCH] Bugfix for ICC color profile parsing in JPEG images. Ported detection code for CMYK JPEG images generated by Adobe Photoshop from maintenance branch. Adobe inverts CMYK images. Reenabled ICC color profile embedding for PDF. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@388460 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/image/AbstractFopImage.java | 10 +++++ src/java/org/apache/fop/image/FopImage.java | 5 ++- src/java/org/apache/fop/image/JpegImage.java | 44 ++++++++++++++----- src/java/org/apache/fop/pdf/BitmapImage.java | 7 ++- src/java/org/apache/fop/pdf/PDFImage.java | 5 ++- src/java/org/apache/fop/pdf/PDFXObject.java | 19 +++++--- .../apache/fop/render/pdf/FopPDFImage.java | 19 +++++--- .../apache/fop/render/ps/PSGraphics2D.java | 4 ++ 8 files changed, 86 insertions(+), 27 deletions(-) diff --git a/src/java/org/apache/fop/image/AbstractFopImage.java b/src/java/org/apache/fop/image/AbstractFopImage.java index af4593038..b6cfeba3f 100644 --- a/src/java/org/apache/fop/image/AbstractFopImage.java +++ b/src/java/org/apache/fop/image/AbstractFopImage.java @@ -103,6 +103,11 @@ public abstract class AbstractFopImage implements FopImage { */ protected Color transparentColor = null; + /** + * Photoshop generated CMYK JPEGs are inverted. + */ + protected boolean invertImage = false; + /** * Constructor. * Construct a new FopImage object and initialize its default properties: @@ -321,6 +326,11 @@ public abstract class AbstractFopImage implements FopImage { return this.transparentColor; } + /** @return true for CMYK images generated by Adobe Photoshop */ + public boolean isInverted() { + return this.invertImage; + } + /** * Return the image data (pixels, uncompressed). * @return the image data diff --git a/src/java/org/apache/fop/image/FopImage.java b/src/java/org/apache/fop/image/FopImage.java index 510a66f05..60e637718 100644 --- a/src/java/org/apache/fop/image/FopImage.java +++ b/src/java/org/apache/fop/image/FopImage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -141,6 +141,9 @@ public interface FopImage { */ byte[] getSoftMask(); + /** @return true for CMYK images generated by Adobe Photoshop */ + boolean isInverted(); + /** * Returns the decoded and uncompressed image as a array of * width * height * [colorspace-multiplicator] pixels. diff --git a/src/java/org/apache/fop/image/JpegImage.java b/src/java/org/apache/fop/image/JpegImage.java index ad4f6fe40..247322d18 100644 --- a/src/java/org/apache/fop/image/JpegImage.java +++ b/src/java/org/apache/fop/image/JpegImage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,12 +19,12 @@ package org.apache.fop.image; // Java -import java.io.ByteArrayOutputStream; import java.awt.color.ColorSpace; import java.awt.color.ICC_Profile; // FOP import org.apache.commons.io.IOUtils; +import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.fop.util.CMYKColorSpace; /** @@ -36,6 +36,7 @@ import org.apache.fop.util.CMYKColorSpace; public class JpegImage extends AbstractFopImage { private ICC_Profile iccProfile = null; private boolean foundICCProfile = false; + private boolean hasAPPEMarker = false; /** * Create a jpeg image with the info. @@ -55,7 +56,7 @@ public class JpegImage extends AbstractFopImage { */ protected boolean loadOriginalData() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ByteArrayOutputStream iccStream = new ByteArrayOutputStream(); + ByteArrayOutputStream iccStream = null; int index = 0; boolean cont = true; @@ -136,11 +137,29 @@ public class JpegImage extends AbstractFopImage { this.raw[index + 2], this.raw[index + 3]) + 2; + if (iccStream == null) { + iccStream = new ByteArrayOutputStream(); + } iccStream.write(this.raw, index + 18, chunkSize - 18); } + index += calcBytes(this.raw[index + 2], + this.raw[index + 3]) + 2; + // Check for Adobe APPE Marker + } else if ((uByte(this.raw[index]) == 0xff + && uByte(this.raw[index + 1]) == 0xee + && uByte(this.raw[index + 2]) == 0 + && uByte(this.raw[index + 3]) == 14 + && "Adobe".equals(new String(this.raw, index + 4, 5)))) { + // The reason for reading the APPE marker is that Adobe Photoshop + // generates CMYK JPEGs with inverted values. The correct thing + // to do would be to interpret the values in the marker, but for now + // only assume that if APPE marker is present and colorspace is CMYK, + // the image is inverted. + hasAPPEMarker = true; + index += calcBytes(this.raw[index + 2], this.raw[index + 3]) + 2; } else { @@ -157,13 +176,15 @@ public class JpegImage extends AbstractFopImage { + "JpegImage - Invalid JPEG Header."); return false; } - if (iccStream.size() > 0) { - byte[] align = new byte[((iccStream.size()) % 8) + 8]; - try { - iccStream.write(align); - } catch (Exception ex) { - log.error("Error while aligning ICC stream: " + ex.getMessage(), ex); - return false; + if (iccStream != null && iccStream.size() > 0) { + int padding = (8 - (iccStream.size() % 8)) % 8; + if (padding != 0) { + try { + iccStream.write(new byte[padding]); + } catch (Exception ex) { + log.error("Error while aligning ICC stream: " + ex.getMessage(), ex); + return false; + } } try { iccProfile = ICC_Profile.getInstance(iccStream.toByteArray()); @@ -175,6 +196,9 @@ public class JpegImage extends AbstractFopImage { log.error("ColorSpace not specified for JPEG image"); return false; } + if (hasAPPEMarker && this.colorSpace.getType() == ColorSpace.TYPE_CMYK) { + this.invertImage = true; + } return true; } diff --git a/src/java/org/apache/fop/pdf/BitmapImage.java b/src/java/org/apache/fop/pdf/BitmapImage.java index 6c8f61e5c..4e6664cff 100644 --- a/src/java/org/apache/fop/pdf/BitmapImage.java +++ b/src/java/org/apache/fop/pdf/BitmapImage.java @@ -172,6 +172,11 @@ public class BitmapImage implements PDFImage { return maskRef; } + /** @see org.apache.fop.pdf.PDFImage#isInverted() */ + public boolean isInverted() { + return false; + } + /** * @see org.apache.fop.pdf.PDFImage#outputContents(OutputStream) */ @@ -208,7 +213,7 @@ public class BitmapImage implements PDFImage { public PDFFilter getPDFFilter() { return null; } - + } diff --git a/src/java/org/apache/fop/pdf/PDFImage.java b/src/java/org/apache/fop/pdf/PDFImage.java index 8be9c28a1..23114c656 100644 --- a/src/java/org/apache/fop/pdf/PDFImage.java +++ b/src/java/org/apache/fop/pdf/PDFImage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -109,6 +109,9 @@ public interface PDFImage { */ String getSoftMask(); + /** @return true for CMYK images generated by Adobe Photoshop */ + boolean isInverted(); + /** * Get the PDF Filter to be applied to the image. * diff --git a/src/java/org/apache/fop/pdf/PDFXObject.java b/src/java/org/apache/fop/pdf/PDFXObject.java index 0607add55..058628b79 100644 --- a/src/java/org/apache/fop/pdf/PDFXObject.java +++ b/src/java/org/apache/fop/pdf/PDFXObject.java @@ -131,13 +131,18 @@ public class PDFXObject extends AbstractPDFStream { + "\n"); } - /* PhotoShop generates CMYK values that's inverse, - this will invert the values - too bad if it's not - a PhotoShop image... - */ - if (pdfimage.getColorSpace().getColorSpace() - == PDFColorSpace.DEVICE_CMYK) { - sb.append("/Decode [ 1.0 0.0 1.0 0.0 1.0 0.0 1.1 0.0 ]\n"); + if (pdfimage.isInverted()) { + /* PhotoShop generates CMYK values that's inverse, + * this will invert the values - too bad if it's not + * a PhotoShop image... + */ + if (pdfimage.getColorSpace().getColorSpace() == PDFColorSpace.DEVICE_CMYK) { + sb.append("/Decode [ 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 ]\n"); + } else if (pdfimage.getColorSpace().getColorSpace() == PDFColorSpace.DEVICE_RGB) { + sb.append("/Decode [ 1.0 0.0 1.0 0.0 1.0 0.0 ]\n"); + } else if (pdfimage.getColorSpace().getColorSpace() == PDFColorSpace.DEVICE_GRAY) { + sb.append("/Decode [ 1.0 0.0 ]\n"); + } } if (pdfimage.isTransparent()) { diff --git a/src/java/org/apache/fop/render/pdf/FopPDFImage.java b/src/java/org/apache/fop/render/pdf/FopPDFImage.java index d35204e9e..d1beb0961 100644 --- a/src/java/org/apache/fop/render/pdf/FopPDFImage.java +++ b/src/java/org/apache/fop/render/pdf/FopPDFImage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,12 +81,6 @@ public class FopPDFImage implements PDFImage { pdfFilter.setApplied(true); isDCT = true; - ICC_Profile prof = fopImage.getICCProfile(); - PDFColorSpace pdfCS = toPDFColorSpace(fopImage.getColorSpace()); - if (prof != null) { - pdfICCStream = doc.getFactory().makePDFICCStream(); - pdfICCStream.setColorSpace(prof, pdfCS); - } } else if ("image/tiff".equals(fopImage.getMimeType()) && fopImage instanceof TIFFImage) { TIFFImage tiffImage = (TIFFImage) fopImage; @@ -116,6 +110,12 @@ public class FopPDFImage implements PDFImage { } else { fopImage.load(FopImage.BITMAP); } + ICC_Profile prof = fopImage.getICCProfile(); + PDFColorSpace pdfCS = toPDFColorSpace(fopImage.getColorSpace()); + if (prof != null) { + pdfICCStream = doc.getFactory().makePDFICCStream(); + pdfICCStream.setColorSpace(prof, pdfCS); + } //Handle transparency mask if applicable if (fopImage.hasSoftMask()) { byte [] softMask = fopImage.getSoftMask(); @@ -200,6 +200,11 @@ public class FopPDFImage implements PDFImage { return softMaskRef; } + /** @return true for CMYK images generated by Adobe Photoshop */ + public boolean isInverted() { + return fopImage.isInverted(); + } + /** * @see org.apache.fop.pdf.PDFImage#isPS() */ diff --git a/src/java/org/apache/fop/render/ps/PSGraphics2D.java b/src/java/org/apache/fop/render/ps/PSGraphics2D.java index 5522656e2..eb7b59e39 100644 --- a/src/java/org/apache/fop/render/ps/PSGraphics2D.java +++ b/src/java/org/apache/fop/render/ps/PSGraphics2D.java @@ -390,6 +390,10 @@ public class PSGraphics2D extends AbstractGraphics2D { return this.mask; } + public boolean isInverted() { + return false; + } + public byte[] getBitmaps() { return this.bitmaps; } -- 2.39.5