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-ffa450edef68tags/fop-0_92-beta
@@ -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 |
@@ -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. |
@@ -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; | |||
} | |||
@@ -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; | |||
} | |||
} | |||
@@ -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. | |||
* |
@@ -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()) { |
@@ -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() | |||
*/ |
@@ -390,6 +390,10 @@ public class PSGraphics2D extends AbstractGraphics2D { | |||
return this.mask; | |||
} | |||
public boolean isInverted() { | |||
return false; | |||
} | |||
public byte[] getBitmaps() { | |||
return this.bitmaps; | |||
} |