git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1069439 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_1rc1old
@@ -21,9 +21,16 @@ package org.apache.fop.afp.goca; | |||
import java.awt.Color; | |||
import java.awt.color.ColorSpace; | |||
import java.io.DataOutput; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import org.apache.commons.io.output.ByteArrayOutputStream; | |||
import org.apache.xmlgraphics.java2d.color.CIELabColorSpace; | |||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; | |||
/** | |||
* Sets the current processing color for the following GOCA structured fields | |||
*/ | |||
@@ -37,56 +44,96 @@ public class GraphicsSetProcessColor extends AbstractGraphicsDrawingOrder { | |||
* X'08' CIELAB | |||
* X'40' Standard OCA color space | |||
*/ | |||
private static final byte RGB = 0x01, CMYK = 0x04; | |||
private static final byte RGB = 0x01, CMYK = 0x04, CIELAB = 0x08; | |||
private final Color color; | |||
private final float[] colorComponents; | |||
private final int componentsSize; | |||
/** | |||
* Main constructor | |||
* | |||
* @param color | |||
* the color to set | |||
* @param color the color to set | |||
*/ | |||
public GraphicsSetProcessColor(Color color) { | |||
this.color = color; | |||
this.colorComponents = color.getColorComponents(null); | |||
if (color instanceof ColorWithAlternatives) { | |||
ColorWithAlternatives cwa = (ColorWithAlternatives)color; | |||
Color alt = cwa.getFirstAlternativeOfType(ColorSpace.TYPE_CMYK); | |||
if (alt != null) { | |||
this.color = alt; | |||
this.componentsSize = 4; | |||
return; | |||
} | |||
} | |||
ColorSpace cs = color.getColorSpace(); | |||
int colSpaceType = cs.getType(); | |||
if (colSpaceType == ColorSpace.TYPE_CMYK) { | |||
this.color = color; | |||
} else if (cs instanceof CIELabColorSpace) { | |||
//TODO Convert between illuminants if not D50 according to rendering intents | |||
//Right now, we're assuming D50 as the GOCA spec requires. | |||
this.color = color; | |||
//16bit components didn't work, and 8-bit sadly has reduced accuracy. | |||
} else { | |||
if (!color.getColorSpace().isCS_sRGB()) { | |||
this.color = ColorUtil.toSRGBColor(color); | |||
} else { | |||
this.color = color; | |||
} | |||
} | |||
this.componentsSize = this.color.getColorSpace().getNumComponents(); | |||
} | |||
/** {@inheritDoc} */ | |||
public int getDataLength() { | |||
return 12 + colorComponents.length; | |||
return 12 + this.componentsSize; | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
byte getOrderCode() { | |||
return (byte) 0xB2; | |||
} | |||
/** {@inheritDoc} */ | |||
public void writeToStream(OutputStream os) throws IOException { | |||
float[] colorComponents = color.getColorComponents(null); | |||
// COLSPCE | |||
byte colspace; | |||
int colSpaceType = color.getColorSpace().getType(); | |||
ColorSpace cs = color.getColorSpace(); | |||
int colSpaceType = cs.getType(); | |||
ByteArrayOutputStream baout = new ByteArrayOutputStream(); | |||
byte[] colsizes; | |||
if (colSpaceType == ColorSpace.TYPE_CMYK) { | |||
colspace = CMYK; | |||
colsizes = new byte[] {0x08, 0x08, 0x08, 0x08}; | |||
for (int i = 0; i < colorComponents.length; i++) { | |||
baout.write(Math.round(colorComponents[i] * 255)); | |||
} | |||
} else if (colSpaceType == ColorSpace.TYPE_RGB) { | |||
colspace = RGB; | |||
colsizes = new byte[] {0x08, 0x08, 0x08, 0x00}; | |||
for (int i = 0; i < colorComponents.length; i++) { | |||
baout.write(Math.round(colorComponents[i] * 255)); | |||
} | |||
} else if (cs instanceof CIELabColorSpace) { | |||
colspace = CIELAB; | |||
colsizes = new byte[] {0x08, 0x08, 0x08, 0x00}; | |||
DataOutput dout = new java.io.DataOutputStream(baout); | |||
//According to GOCA, I'd expect the multiplicator below to be 255f, not 100f | |||
//But only IBM AFP Workbench seems to support Lab colors and it requires "c * 100f" | |||
int l = Math.round(colorComponents[0] * 100f); | |||
int a = Math.round(colorComponents[1] * 255f) - 128; | |||
int b = Math.round(colorComponents[2] * 255f) - 128; | |||
dout.writeByte(l); | |||
dout.writeByte(a); | |||
dout.writeByte(b); | |||
} else { | |||
LOG.error("unsupported colorspace " + colSpaceType); | |||
colspace = RGB; | |||
} | |||
// COLSIZE(S) | |||
byte[] colsizes = new byte[] {0x00, 0x00, 0x00, 0x00}; | |||
for (int i = 0; i < colorComponents.length; i++) { | |||
colsizes[i] = (byte) 8; | |||
throw new IllegalStateException(); | |||
} | |||
int len = getDataLength(); | |||
byte[] data = new byte[len]; | |||
byte[] data = new byte[12]; | |||
data[0] = getOrderCode(); // GSPCOL order code | |||
data[1] = (byte) (len - 2); // LEN | |||
data[2] = 0x00; // reserved; must be zero | |||
@@ -100,15 +147,12 @@ public class GraphicsSetProcessColor extends AbstractGraphicsDrawingOrder { | |||
data[10] = colsizes[2]; | |||
data[11] = colsizes[3]; | |||
// COLVALUE(S) | |||
for (int i = 0; i < colorComponents.length; i++) { | |||
data[i + 12] = (byte) (colorComponents[i] * 255); | |||
} | |||
os.write(data); | |||
baout.writeTo(os); | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public String toString() { | |||
return "GraphicsSetProcessColor(col=" + color + ")"; | |||
} |
@@ -26,6 +26,7 @@ import java.util.Iterator; | |||
import java.util.List; | |||
import org.apache.xmlgraphics.java2d.color.ColorConverter; | |||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||
import org.apache.fop.afp.AFPDataObjectInfo; | |||
import org.apache.fop.afp.AFPObjectAreaInfo; | |||
@@ -82,6 +83,7 @@ public class GraphicsObject extends AbstractDataObject { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void setViewport(AFPDataObjectInfo dataObjectInfo) { | |||
super.setViewport(dataObjectInfo); | |||
@@ -145,7 +147,7 @@ public class GraphicsObject extends AbstractDataObject { | |||
* @param color the active color to use | |||
*/ | |||
public void setColor(Color color) { | |||
if (!color.equals(graphicsState.color)) { | |||
if (!ColorUtil.isSameColor(color, graphicsState.color)) { | |||
addObject(new GraphicsSetProcessColor(colorConverter.convert(color))); | |||
graphicsState.color = color; | |||
} | |||
@@ -341,6 +343,7 @@ public class GraphicsObject extends AbstractDataObject { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public String toString() { | |||
return "GraphicsObject: " + getName(); | |||
} | |||
@@ -354,6 +357,7 @@ public class GraphicsObject extends AbstractDataObject { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void setComplete(boolean complete) { | |||
Iterator it = objects.iterator(); | |||
while (it.hasNext()) { | |||
@@ -364,6 +368,7 @@ public class GraphicsObject extends AbstractDataObject { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected void writeStart(OutputStream os) throws IOException { | |||
super.writeStart(os); | |||
byte[] data = new byte[17]; | |||
@@ -372,12 +377,14 @@ public class GraphicsObject extends AbstractDataObject { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected void writeContent(OutputStream os) throws IOException { | |||
super.writeContent(os); | |||
writeObjects(objects, os); | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected void writeEnd(OutputStream os) throws IOException { | |||
byte[] data = new byte[17]; | |||
copySF(data, Type.END, Category.GRAPHICS); |
@@ -26,6 +26,10 @@ import java.io.OutputStream; | |||
import org.apache.commons.io.output.ByteArrayOutputStream; | |||
import org.apache.xmlgraphics.java2d.color.CIELabColorSpace; | |||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; | |||
/** | |||
* Generator class for PTOCA data structures. | |||
*/ | |||
@@ -311,9 +315,18 @@ public abstract class PtocaBuilder implements PtocaConstants { | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void setExtendedTextColor(Color col) throws IOException { | |||
if (col.equals(currentColor)) { | |||
if (ColorUtil.isSameColor(col, currentColor)) { | |||
return; | |||
} | |||
if (col instanceof ColorWithAlternatives) { | |||
ColorWithAlternatives cwa = (ColorWithAlternatives)col; | |||
Color alt = cwa.getFirstAlternativeOfType(ColorSpace.TYPE_CMYK); | |||
if (alt != null) { | |||
col = alt; | |||
} | |||
} | |||
ColorSpace cs = col.getColorSpace(); | |||
newControlSequence(); | |||
if (col.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { | |||
writeByte(0x00); // Reserved; must be zero | |||
@@ -332,6 +345,25 @@ public abstract class PtocaBuilder implements PtocaConstants { | |||
int component = Math.round(comps[i] * 255); | |||
writeByte(component); | |||
} | |||
} else if (cs instanceof CIELabColorSpace) { | |||
writeByte(0x00); // Reserved; must be zero | |||
writeByte(0x08); // Color space - 0x08 = CIELAB | |||
writeByte(0x00); // Reserved; must be zero | |||
writeByte(0x00); // Reserved; must be zero | |||
writeByte(0x00); // Reserved; must be zero | |||
writeByte(0x00); // Reserved; must be zero | |||
writeByte(8); // Number of bits in component 1 | |||
writeByte(8); // Number of bits in component 2 | |||
writeByte(8); // Number of bits in component 3 | |||
writeByte(0); // Number of bits in component 4 | |||
//Sadly, 16 bit components don't seem to work | |||
float[] colorComponents = col.getColorComponents(null); | |||
int l = Math.round(colorComponents[0] * 255f); | |||
int a = Math.round(colorComponents[1] * 255f) - 128; | |||
int b = Math.round(colorComponents[2] * 255f) - 128; | |||
writeByte(l); // L* | |||
writeByte(a); // a* | |||
writeByte(b); // b* | |||
} else { | |||
writeByte(0x00); // Reserved; must be zero | |||
writeByte(0x01); // Color space - 0x01 = RGB |
@@ -19,7 +19,6 @@ | |||
package org.apache.fop.apps; | |||
import java.awt.color.ColorSpace; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
@@ -151,7 +150,7 @@ public class FopFactory implements ImageContext { | |||
/** Optional overriding LayoutManagerMaker */ | |||
private LayoutManagerMaker lmMakerOverride = null; | |||
private Set ignoredNamespaces; | |||
private Set<String> ignoredNamespaces; | |||
private FOURIResolver foURIResolver; | |||
@@ -165,6 +164,7 @@ public class FopFactory implements ImageContext { | |||
this.fontManager = new FontManager() { | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void setFontBaseURL(String fontBase) throws MalformedURLException { | |||
super.setFontBaseURL(getFOURIResolver().checkBaseURL(fontBase)); | |||
} | |||
@@ -175,7 +175,7 @@ public class FopFactory implements ImageContext { | |||
this.rendererFactory = new RendererFactory(); | |||
this.xmlHandlers = new XMLHandlerRegistry(); | |||
this.imageHandlers = new ImageHandlerRegistry(); | |||
this.ignoredNamespaces = new java.util.HashSet(); | |||
this.ignoredNamespaces = new java.util.HashSet<String>(); | |||
} | |||
/** | |||
@@ -381,6 +381,7 @@ public class FopFactory implements ImageContext { | |||
* @throws MalformedURLException if there's a problem with a file URL | |||
* @deprecated use getFontManager().setFontBaseURL(fontBase) instead | |||
*/ | |||
@Deprecated | |||
public void setFontBaseURL(String fontBase) throws MalformedURLException { | |||
getFontManager().setFontBaseURL(fontBase); | |||
} | |||
@@ -389,6 +390,7 @@ public class FopFactory implements ImageContext { | |||
* @return the font base URL | |||
* @deprecated use getFontManager().setFontBaseURL(fontBase) instead | |||
*/ | |||
@Deprecated | |||
public String getFontBaseURL() { | |||
return getFontManager().getFontBaseURL(); | |||
} | |||
@@ -516,6 +518,7 @@ public class FopFactory implements ImageContext { | |||
* @return true if kerning on base 14 fonts is enabled | |||
* @deprecated use getFontManager().isBase14KerningEnabled() instead | |||
*/ | |||
@Deprecated | |||
public boolean isBase14KerningEnabled() { | |||
return getFontManager().isBase14KerningEnabled(); | |||
} | |||
@@ -525,6 +528,7 @@ public class FopFactory implements ImageContext { | |||
* @param value true if kerning should be activated | |||
* @deprecated use getFontManager().setBase14KerningEnabled(boolean) instead | |||
*/ | |||
@Deprecated | |||
public void setBase14KerningEnabled(boolean value) { | |||
getFontManager().setBase14KerningEnabled(value); | |||
} | |||
@@ -652,7 +656,7 @@ public class FopFactory implements ImageContext { | |||
* namespace is in the ignored set. | |||
* @param namespaceURIs the namespace URIs | |||
*/ | |||
public void ignoreNamespaces(Collection namespaceURIs) { | |||
public void ignoreNamespaces(Collection<String> namespaceURIs) { | |||
this.ignoredNamespaces.addAll(namespaceURIs); | |||
} | |||
@@ -666,7 +670,7 @@ public class FopFactory implements ImageContext { | |||
} | |||
/** @return the set of namespaces that are ignored by FOP */ | |||
public Set getIgnoredNamespace() { | |||
public Set<String> getIgnoredNamespace() { | |||
return Collections.unmodifiableSet(this.ignoredNamespaces); | |||
} | |||
@@ -742,6 +746,7 @@ public class FopFactory implements ImageContext { | |||
* @param useCache use cache or not | |||
* @deprecated use getFontManager().setUseCache(boolean) instead | |||
*/ | |||
@Deprecated | |||
public void setUseCache(boolean useCache) { | |||
getFontManager().setUseCache(useCache); | |||
} | |||
@@ -751,6 +756,7 @@ public class FopFactory implements ImageContext { | |||
* @return whether this factory is uses the cache | |||
* @deprecated use getFontManager().useCache() instead | |||
*/ | |||
@Deprecated | |||
public boolean useCache() { | |||
return getFontManager().useCache(); | |||
} | |||
@@ -760,6 +766,7 @@ public class FopFactory implements ImageContext { | |||
* @return the font cache | |||
* @deprecated use getFontManager().getFontCache() instead | |||
*/ | |||
@Deprecated | |||
public FontCache getFontCache() { | |||
return getFontManager().getFontCache(); | |||
} | |||
@@ -793,20 +800,13 @@ public class FopFactory implements ImageContext { | |||
} | |||
/** | |||
* Create (if needed) and return an ICC ColorSpace instance. | |||
* | |||
* The ICC profile source is taken from the src attribute of the color-profile FO element. | |||
* If the ICC ColorSpace is not yet in the cache a new one is created and stored in the cache. | |||
* | |||
* The FOP URI resolver is used to try and locate the ICC file. | |||
* If that fails null is returned. | |||
* | |||
* @param baseUri a base URI to resolve relative URIs | |||
* @param iccProfileSrc ICC Profile source to return a ColorSpace for | |||
* @return ICC ColorSpace object or null if ColorSpace could not be created | |||
* Returns the color space cache for this instance. | |||
* <p> | |||
* Note: this method should not be considered as part of FOP's external API. | |||
* @return the color space cache | |||
*/ | |||
public ColorSpace getColorSpace(String baseUri, String iccProfileSrc) { | |||
return colorSpaceCache.get(baseUri, iccProfileSrc); | |||
public ColorSpaceCache getColorSpaceCache() { | |||
return this.colorSpaceCache; | |||
} | |||
} |
@@ -0,0 +1,94 @@ | |||
/* | |||
* 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.fo.expr; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.datatypes.PercentBase; | |||
import org.apache.fop.datatypes.PercentBaseContext; | |||
import org.apache.fop.fo.properties.ColorProperty; | |||
import org.apache.fop.fo.properties.Property; | |||
/** | |||
* Implements the cie-lab-color() function. | |||
* @since XSL-FO 2.0 | |||
*/ | |||
class CIELabColorFunction extends FunctionBase { | |||
/** | |||
* cie-lab-color() takes 2 times 3 arguments. | |||
* {@inheritDoc} | |||
*/ | |||
public int nbArgs() { | |||
return 2 * 3; | |||
} | |||
public PercentBase getPercentBase() { | |||
return new CIELabPercentBase(); | |||
} | |||
/** {@inheritDoc} */ | |||
public Property eval(Property[] args, | |||
PropertyInfo pInfo) throws PropertyException { | |||
float red = args[0].getNumber().floatValue(); | |||
float green = args[1].getNumber().floatValue(); | |||
float blue = args[2].getNumber().floatValue(); | |||
/* Verify sRGB replacement arguments */ | |||
if ((red < 0 || red > 255) | |||
|| (green < 0 || green > 255) | |||
|| (blue < 0 || blue > 255)) { | |||
throw new PropertyException("sRGB color values out of range. " | |||
+ "Arguments to cie-lab-color() must be [0..255] or [0%..100%]"); | |||
} | |||
float l = args[3].getNumber().floatValue(); | |||
float a = args[4].getNumber().floatValue(); | |||
float b = args[5].getNumber().floatValue(); | |||
if (l < 0 || l > 100) { | |||
throw new PropertyException("L* value out of range. Valid range: [0..100]"); | |||
} | |||
if (a < -127 || a > 127 || b < -127 || b > 127) { | |||
throw new PropertyException("a* and b* values out of range. Valid range: [-127..+127]"); | |||
} | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append("cie-lab-color(" + red + "," + green + "," + blue + "," | |||
+ l + "," + a + "," + b + ")"); | |||
FOUserAgent ua = (pInfo == null) | |||
? null | |||
: (pInfo.getFO() == null ? null : pInfo.getFO().getUserAgent()); | |||
return ColorProperty.getInstance(ua, sb.toString()); | |||
} | |||
private static class CIELabPercentBase implements PercentBase { | |||
public int getDimension() { | |||
return 0; | |||
} | |||
public double getBaseValue() { | |||
return 1.0f; | |||
} | |||
public int getBaseLength(PercentBaseContext context) { | |||
return 0; | |||
} | |||
} | |||
} |
@@ -0,0 +1,112 @@ | |||
/* | |||
* 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.fo.expr; | |||
import org.apache.fop.datatypes.PercentBase; | |||
import org.apache.fop.datatypes.PercentBaseContext; | |||
import org.apache.fop.fo.pagination.ColorProfile; | |||
import org.apache.fop.fo.pagination.Declarations; | |||
import org.apache.fop.fo.properties.ColorProperty; | |||
import org.apache.fop.fo.properties.Property; | |||
/** | |||
* Implements the rgb-named-color() function. | |||
* @since XSL-FO 2.0 | |||
*/ | |||
class NamedColorFunction extends FunctionBase { | |||
/** | |||
* rgb-named-color() takes a 5 arguments. | |||
* {@inheritDoc} | |||
*/ | |||
public int nbArgs() { | |||
return 5; | |||
} | |||
/** {@inheritDoc} */ | |||
public PercentBase getPercentBase() { | |||
return new NamedPercentBase(); | |||
} | |||
/** {@inheritDoc} */ | |||
public Property eval(Property[] args, | |||
PropertyInfo pInfo) throws PropertyException { | |||
// Map color profile NCNAME to src from declarations/color-profile element | |||
String colorProfileName = args[3].getString(); | |||
String colorName = args[4].getString(); | |||
Declarations decls = pInfo.getFO().getRoot().getDeclarations(); | |||
ColorProfile cp = null; | |||
if (decls != null) { | |||
cp = decls.getColorProfile(colorProfileName); | |||
} | |||
if (cp == null) { | |||
PropertyException pe = new PropertyException("The " + colorProfileName | |||
+ " color profile was not declared"); | |||
pe.setPropertyInfo(pInfo); | |||
throw pe; | |||
} | |||
String src = (cp != null ? cp.getSrc() : ""); | |||
float red = 0, green = 0, blue = 0; | |||
red = args[0].getNumber().floatValue(); | |||
green = args[1].getNumber().floatValue(); | |||
blue = args[2].getNumber().floatValue(); | |||
/* Verify rgb replacement arguments */ | |||
if ((red < 0 || red > 255) | |||
|| (green < 0 || green > 255) | |||
|| (blue < 0 || blue > 255)) { | |||
throw new PropertyException("sRGB color values out of range. " | |||
+ "Arguments to rgb-named-color() must be [0..255] or [0%..100%]"); | |||
} | |||
// rgb-named-color is replaced with fop-rgb-named-color which has an extra argument | |||
// containing the color profile src attribute as it is defined in the color-profile | |||
// declarations element. | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append("fop-rgb-named-color("); | |||
sb.append(red / 255f); | |||
sb.append(',').append(green / 255f); | |||
sb.append(',').append(blue / 255f); | |||
sb.append(',').append(colorProfileName); | |||
sb.append(',').append(src); | |||
sb.append(", '").append(colorName).append('\''); | |||
sb.append(")"); | |||
return ColorProperty.getInstance(pInfo.getUserAgent(), sb.toString()); | |||
} | |||
private static final class NamedPercentBase implements PercentBase { | |||
/** {@inheritDoc} */ | |||
public int getBaseLength(PercentBaseContext context) throws PropertyException { | |||
return 0; | |||
} | |||
/** {@inheritDoc} */ | |||
public double getBaseValue() { | |||
return 255f; | |||
} | |||
/** {@inheritDoc} */ | |||
public int getDimension() { | |||
return 0; | |||
} | |||
} | |||
} |
@@ -69,6 +69,8 @@ public final class PropertyParser extends PropertyTokenizer { | |||
FUNCTION_TABLE.put("label-end", new LabelEndFunction()); | |||
FUNCTION_TABLE.put("body-start", new BodyStartFunction()); | |||
FUNCTION_TABLE.put("rgb-icc", new ICCColorFunction()); | |||
FUNCTION_TABLE.put("rgb-named-color", new NamedColorFunction()); //since XSL-FO 2.0 | |||
FUNCTION_TABLE.put("cie-lab-color", new CIELabColorFunction()); //since XSL-FO 2.0 | |||
FUNCTION_TABLE.put("cmyk", new CMYKcolorFunction()); //non-standard!!! | |||
/** |
@@ -80,7 +80,6 @@ class PropertyTokenizer { | |||
void next() throws PropertyException { | |||
currentTokenValue = null; | |||
currentTokenStartIndex = exprIndex; | |||
boolean currentMaybeOperator = recognizeOperator; | |||
boolean bSawDecimal; | |||
recognizeOperator = true; | |||
while ( true ) { | |||
@@ -244,14 +243,14 @@ class PropertyTokenizer { | |||
private void nextColor() throws PropertyException { | |||
if (exprIndex < exprLength | |||
&& isHexDigit(expr.charAt(exprIndex))) { | |||
if (exprIndex < exprLength) { | |||
++exprIndex; | |||
scanHexDigits(); | |||
int len = exprIndex - currentTokenStartIndex - 1; | |||
if (len % 3 == 0) { | |||
currentToken = TOK_COLORSPEC; | |||
} else { | |||
//Actually not a color at all, but an NCNAME starting with "#" | |||
scanRestOfName(); | |||
currentToken = TOK_NCNAME; | |||
} |
@@ -70,6 +70,7 @@ public final class ColorProperty extends Property { | |||
* @throws PropertyException | |||
* for invalid or inconsistent FO input | |||
*/ | |||
@Override | |||
public Property convertProperty(Property p, | |||
PropertyList propertyList, FObj fo) | |||
throws PropertyException { | |||
@@ -120,11 +121,13 @@ public final class ColorProperty extends Property { | |||
* @param foUserAgent FOP user agent | |||
* @return float the AWT color represented by this ColorType instance | |||
*/ | |||
@Override | |||
public Color getColor(FOUserAgent foUserAgent) { | |||
return color; | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public String toString() { | |||
return ColorUtil.colorToString(color); | |||
} | |||
@@ -140,23 +143,27 @@ public final class ColorProperty extends Property { | |||
/** | |||
* @return this.colorType cast as an Object | |||
*/ | |||
@Override | |||
public Object getObject() { | |||
return this; | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (o instanceof ColorProperty) { | |||
return ((ColorProperty) o).color.equals(this.color); | |||
return org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor( | |||
((ColorProperty) o).color, this.color); | |||
} | |||
return false; | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public int hashCode() { | |||
return this.color.hashCode(); | |||
} |
@@ -0,0 +1,91 @@ | |||
/* | |||
* 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.pdf; | |||
/** | |||
* This class represents a "CIE L*a*b*" color space. It is expected that the components have | |||
* the following ranges: L* [0..100], a* and b* [-127..127] | |||
*/ | |||
public class PDFCIELabColorSpace extends PDFArray implements PDFColorSpace { | |||
/** | |||
* Creates a new "CIE L*a*b*" color space. Valid value ranges for the white and black point | |||
* are [0..1] as per the PDF spec. | |||
* @param whitePoint the white point | |||
* @param blackPoint the optional black point (may be null) | |||
*/ | |||
public PDFCIELabColorSpace(float[] whitePoint, float[] blackPoint) { | |||
super(); | |||
add(new PDFName("Lab")); | |||
PDFDictionary dict = new PDFDictionary(); | |||
dict.put("WhitePoint", toPDFArray("White point", whitePoint)); | |||
if (whitePoint[1] != 1f) { | |||
throw new IllegalArgumentException("The white point's Y coordinate must be 1.0"); | |||
} | |||
if (blackPoint != null) { | |||
dict.put("BlackPoint", toPDFArray("Black point", blackPoint)); | |||
} | |||
dict.put("Range", new PDFArray(dict, new int[] {-128, 128, -128, 128})); | |||
add(dict); | |||
} | |||
private PDFArray toPDFArray(String name, float[] whitePoint) { | |||
PDFArray wp = new PDFArray(); | |||
if (whitePoint == null || whitePoint.length != 3) { | |||
throw new IllegalArgumentException(name + " must be given an have 3 components"); | |||
} | |||
for (int i = 0; i < 3; i++) { | |||
wp.add(whitePoint[i]); | |||
} | |||
return wp; | |||
} | |||
/** {@inheritDoc} */ | |||
public String getName() { | |||
return "CS" + this.getObjectNumber(); | |||
} | |||
/** {@inheritDoc} */ | |||
public int getNumComponents() { | |||
return 3; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isCMYKColorSpace() { | |||
return false; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isDeviceColorSpace() { | |||
return false; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isGrayColorSpace() { | |||
return false; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isRGBColorSpace() { | |||
return false; | |||
} | |||
} |
@@ -21,18 +21,17 @@ package org.apache.fop.pdf; | |||
import java.awt.Color; | |||
import java.awt.color.ColorSpace; | |||
import java.awt.color.ICC_ColorSpace; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.xmlgraphics.java2d.color.DeviceCMYKColorSpace; | |||
import org.apache.fop.util.ColorExt; | |||
/** | |||
* PDF Color object. | |||
* This is used to output color to a PDF content stream. | |||
* PDF Color object. It is currently only used to hold the transparent color of a masked bitmap | |||
* image. And in this context, only RGB and Gray values are used. | |||
* <p> | |||
* Use of this class is discouraged. {@link PDFColorHandler} is now used for in-content color | |||
* selection. For masked bitmaps, it may be wiser to switch to {@link Color} in the long run. | |||
*/ | |||
public class PDFColor extends PDFPathPaint { | |||
// could be 3.0 as well. | |||
@@ -46,14 +45,8 @@ public class PDFColor extends PDFPathPaint { | |||
private double yellow = -1.0; | |||
private double black = -1.0; | |||
// TODO - It would probably be better to reorganize PDFPathPaint/PDFColor/PDFColorSpace | |||
// class hierarchy. However, at this early stages of my FOP understanding, I can | |||
// not really oversee the consequences of such a switch (nor whether it would be | |||
// appropriate). | |||
private ColorExt colorExt = null; | |||
/** | |||
* Create a PDF color with double values ranging from 0 to 1 | |||
* Create a PDF color with double values ranging from 0 to 1. | |||
* | |||
* @param theRed the red double value | |||
* @param theGreen the green double value | |||
@@ -68,82 +61,28 @@ public class PDFColor extends PDFPathPaint { | |||
this.blue = theBlue; | |||
} | |||
/** | |||
* Create PDFColor for the given document and based on the java.awt.Color object | |||
* | |||
* In case the java.awt.Color is an instance of the ColorExt class a PDFICCStream is added to | |||
* the PDFDocument that is being created | |||
* | |||
* @param pdfDoc PDFDocument that is being created | |||
* @param col Color object from which to create this PDFColor | |||
*/ | |||
public PDFColor(PDFDocument pdfDoc, Color col) { | |||
this(col); | |||
// TODO - 1) There is a potential conflict when FOP and Batik elements use the same color | |||
// profile name for different profiles. | |||
// 2) In case the same color profile is used with different names it will be | |||
// included multiple times in the PDF | |||
// | |||
if (colorExt != null | |||
&& pdfDoc.getResources().getColorSpace(colorExt.getIccProfileName()) == null) { | |||
PDFICCStream pdfIccStream = new PDFICCStream(); | |||
ColorSpace ceCs = colorExt.getOrigColorSpace(); | |||
try { | |||
pdfIccStream.setColorSpace(((ICC_ColorSpace)ceCs).getProfile(), null); | |||
pdfIccStream.setData( | |||
((ICC_ColorSpace)colorExt.getColorSpace()).getProfile().getData()); | |||
} catch (IOException ioe) { | |||
log.error("Failed to set profile data for " + colorExt.getIccProfileName()); | |||
} | |||
pdfDoc.registerObject(pdfIccStream); | |||
pdfDoc.getFactory().makeICCBasedColorSpace( | |||
null, colorExt.getIccProfileName(), pdfIccStream); | |||
if (log.isInfoEnabled()) { | |||
log.info("Adding PDFICCStream " + colorExt.getIccProfileName() | |||
+ " for " + colorExt.getIccProfileSrc()); | |||
} | |||
} | |||
} | |||
/** | |||
* Create a PDF color from a java.awt.Color object. | |||
* | |||
* Different Color objects are handled differently. Cases recognized are. | |||
* | |||
* 1. CMYK color | |||
* 2. ColorExt color | |||
* 3. 'Normal' java.awt.Color (RGB case assumed) | |||
* 3. 'Normal' java.awt.Color (RGB case assumed or implicit conversion to sRGB) | |||
* | |||
* @param col the java.awt.Color object for which to create a PDFColor object | |||
*/ | |||
public PDFColor(java.awt.Color col) { | |||
ColorSpace cs = col.getColorSpace(); | |||
ColorExt ce = null; | |||
if (col instanceof ColorExt) { | |||
ce = (ColorExt)col; | |||
cs = ce.getOrigColorSpace(); | |||
} | |||
if (cs != null && cs instanceof DeviceCMYKColorSpace) { | |||
// CMYK case | |||
this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_CMYK); | |||
float[] cmyk = (ce == null | |||
? col.getColorComponents(null) | |||
: ce.getOriginalColorComponents()); | |||
float[] cmyk = col.getColorComponents(null); | |||
this.cyan = cmyk[0]; | |||
this.magenta = cmyk[1]; | |||
this.yellow = cmyk[2]; | |||
this.black = cmyk[3]; | |||
} else if (ce != null) { | |||
// ColorExt (ICC) case | |||
this.colorExt = ce; | |||
float[] rgb = col.getRGBColorComponents(null); | |||
this.red = rgb[0]; | |||
this.green = rgb[1]; | |||
this.blue = rgb[2]; | |||
// TODO - See earlier todo | |||
this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); | |||
} else { | |||
// Default (RGB) Color | |||
// Default (RGB) Color (ICC Colors are converted to sRGB, too) | |||
this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); | |||
float[] comps = new float[3]; | |||
comps = col.getColorComponents(comps); | |||
@@ -163,7 +102,6 @@ public class PDFColor extends PDFPathPaint { | |||
public PDFColor(int theRed, int theGreen, int theBlue) { | |||
this(((double)theRed) / 255d, ((double)theGreen) / 255d, | |||
((double)theBlue) / 255d); | |||
} | |||
/** | |||
@@ -176,8 +114,6 @@ public class PDFColor extends PDFPathPaint { | |||
*/ | |||
public PDFColor(double theCyan, double theMagenta, double theYellow, | |||
double theBlack) { | |||
// super(theNumber);//? | |||
this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_CMYK); | |||
this.cyan = theCyan; | |||
@@ -351,26 +287,7 @@ public class PDFColor extends PDFPathPaint { | |||
public String getColorSpaceOut(boolean fillNotStroke) { | |||
StringBuffer p = new StringBuffer(""); | |||
if (this.colorExt != null) { | |||
if (fillNotStroke) { | |||
p.append("/" + this.colorExt.getIccProfileName() + " cs "); | |||
} else { | |||
p.append("/" + this.colorExt.getIccProfileName() + " CS "); | |||
} | |||
float[] colorArgs; | |||
colorArgs = this.colorExt.getOriginalColorComponents(); | |||
if (colorArgs == null) { | |||
colorArgs = this.colorExt.getColorComponents(null); | |||
} | |||
for (int ix = 0; ix < colorArgs.length; ix++) { | |||
p.append(colorArgs[ix] + " "); | |||
} | |||
if (fillNotStroke) { | |||
p.append("sc\n"); | |||
} else { | |||
p.append("SC\n"); | |||
} | |||
} else if (this.colorSpace.getColorSpace() | |||
if (this.colorSpace.getColorSpace() | |||
== PDFDeviceColorSpace.DEVICE_RGB) { // colorspace is RGB | |||
// according to pdfspec 12.1 p.399 | |||
// if the colors are the same then just use the g or G operator |
@@ -0,0 +1,231 @@ | |||
/* | |||
* 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.pdf; | |||
import java.awt.Color; | |||
import java.awt.color.ColorSpace; | |||
import java.awt.color.ICC_ColorSpace; | |||
import java.awt.color.ICC_Profile; | |||
import java.text.DecimalFormat; | |||
import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.java2d.color.CIELabColorSpace; | |||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; | |||
import org.apache.xmlgraphics.java2d.color.DeviceCMYKColorSpace; | |||
import org.apache.xmlgraphics.java2d.color.NamedColorSpace; | |||
import org.apache.xmlgraphics.java2d.color.profile.ColorProfileUtil; | |||
import org.apache.fop.util.DecimalFormatCache; | |||
/** | |||
* This class handles the registration of color spaces and the generation of PDF code to select | |||
* the right colors given a {@link Color} instance. | |||
*/ | |||
public class PDFColorHandler { | |||
private Log log = LogFactory.getLog(PDFColorHandler.class); | |||
private PDFResources resources; | |||
private Map<String, PDFCIELabColorSpace> cieLabColorSpaces; | |||
public PDFColorHandler(PDFResources resources) { | |||
this.resources = resources; | |||
} | |||
private PDFDocument getDocument() { | |||
return this.resources.getDocumentSafely(); | |||
} | |||
/** | |||
* Generates code to select the given color and handles the registration of color spaces in | |||
* PDF where necessary. | |||
* @param codeBuffer the target buffer to receive the color selection code | |||
* @param color the color | |||
* @param fill true for fill color, false for stroke color | |||
*/ | |||
public void establishColor(StringBuffer codeBuffer, Color color, boolean fill) { | |||
if (color instanceof ColorWithAlternatives) { | |||
ColorWithAlternatives colExt = (ColorWithAlternatives)color; | |||
//Alternate colors have priority | |||
Color[] alt = colExt.getAlternativeColors(); | |||
for (int i = 0, c = alt.length; i < c; i++) { | |||
Color col = alt[i]; | |||
boolean established = establishColorFromColor(codeBuffer, col, fill); | |||
if (established) { | |||
return; | |||
} | |||
} | |||
if (log.isDebugEnabled() && alt.length > 0) { | |||
log.debug("None of the alternative colors are supported. Using fallback: " | |||
+ color); | |||
} | |||
} | |||
//Fallback | |||
boolean established = establishColorFromColor(codeBuffer, color, fill); | |||
if (!established) { | |||
establishDeviceRGB(codeBuffer, color, fill); | |||
} | |||
} | |||
private boolean establishColorFromColor(StringBuffer codeBuffer, Color color, boolean fill) { | |||
ColorSpace cs = color.getColorSpace(); | |||
if (cs instanceof DeviceCMYKColorSpace) { | |||
establishDeviceCMYK(codeBuffer, color, fill); | |||
return true; | |||
} else if (!cs.isCS_sRGB()) { | |||
if (cs instanceof ICC_ColorSpace) { | |||
PDFICCBasedColorSpace pdfcs = getICCBasedColorSpace((ICC_ColorSpace)cs); | |||
establishColor(codeBuffer, pdfcs, color, fill); | |||
return true; | |||
} else if (cs instanceof NamedColorSpace) { | |||
PDFSeparationColorSpace sepcs = getSeparationColorSpace((NamedColorSpace)cs); | |||
establishColor(codeBuffer, sepcs, color, fill); | |||
return true; | |||
} else if (cs instanceof CIELabColorSpace) { | |||
CIELabColorSpace labcs = (CIELabColorSpace)cs; | |||
PDFCIELabColorSpace pdflab = getCIELabColorSpace(labcs); | |||
selectColorSpace(codeBuffer, pdflab, fill); | |||
float[] comps = color.getColorComponents(null); | |||
float[] nativeComps = labcs.toNativeComponents(comps); | |||
writeColor(codeBuffer, nativeComps, labcs.getNumComponents(), (fill ? "sc" : "SC")); | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
private PDFICCBasedColorSpace getICCBasedColorSpace(ICC_ColorSpace cs) { | |||
ICC_Profile profile = cs.getProfile(); | |||
String desc = ColorProfileUtil.getICCProfileDescription(profile); | |||
if (log.isDebugEnabled()) { | |||
log.trace("ICC profile encountered: " + desc); | |||
} | |||
PDFICCBasedColorSpace pdfcs = this.resources.getICCColorSpaceByProfileName(desc); | |||
if (pdfcs == null) { | |||
//color space is not in the PDF, yet | |||
PDFFactory factory = getDocument().getFactory(); | |||
PDFICCStream pdfICCStream = factory.makePDFICCStream(); | |||
PDFDeviceColorSpace altSpace = PDFDeviceColorSpace.toPDFColorSpace(cs); | |||
pdfICCStream.setColorSpace(profile, altSpace); | |||
pdfcs = factory.makeICCBasedColorSpace(null, desc, pdfICCStream); | |||
} | |||
return pdfcs; | |||
} | |||
private PDFSeparationColorSpace getSeparationColorSpace(NamedColorSpace cs) { | |||
PDFName colorName = new PDFName(cs.getColorName()); | |||
PDFSeparationColorSpace sepcs = (PDFSeparationColorSpace)this.resources.getColorSpace( | |||
colorName); | |||
if (sepcs == null) { | |||
//color space is not in the PDF, yet | |||
PDFFactory factory = getDocument().getFactory(); | |||
sepcs = factory.makeSeparationColorSpace(null, cs); | |||
} | |||
return sepcs; | |||
} | |||
private PDFCIELabColorSpace getCIELabColorSpace(CIELabColorSpace labCS) { | |||
if (this.cieLabColorSpaces == null) { | |||
this.cieLabColorSpaces = new java.util.HashMap<String, PDFCIELabColorSpace>(); | |||
} | |||
float[] wp = labCS.getWhitePoint(); | |||
StringBuilder sb = new StringBuilder(); | |||
for (int i = 0; i < 3; i++) { | |||
if (i > 0) { | |||
sb.append(','); | |||
} | |||
sb.append(wp[i]); | |||
} | |||
String key = sb.toString(); | |||
PDFCIELabColorSpace cielab = this.cieLabColorSpaces.get(key); | |||
if (cielab == null) { | |||
//color space is not in the PDF, yet | |||
float[] wp1 = new float[] {wp[0] / 100f, wp[1] / 100f, wp[2] / 100f}; | |||
cielab = new PDFCIELabColorSpace(wp1, null); | |||
getDocument().registerObject(cielab); | |||
this.resources.addColorSpace(cielab); | |||
this.cieLabColorSpaces.put(key, cielab); | |||
} | |||
return cielab; | |||
} | |||
private void establishColor(StringBuffer codeBuffer, | |||
PDFColorSpace pdfcs, Color color, boolean fill) { | |||
selectColorSpace(codeBuffer, pdfcs, fill); | |||
writeColor(codeBuffer, color, pdfcs.getNumComponents(), (fill ? "sc" : "SC")); | |||
} | |||
private void selectColorSpace(StringBuffer codeBuffer, PDFColorSpace pdfcs, boolean fill) { | |||
codeBuffer.append(new PDFName(pdfcs.getName())); | |||
if (fill) { | |||
codeBuffer.append(" cs "); | |||
} else { | |||
codeBuffer.append(" CS "); | |||
} | |||
} | |||
private void establishDeviceRGB(StringBuffer codeBuffer, Color color, boolean fill) { | |||
float[] comps; | |||
if (color.getColorSpace().isCS_sRGB()) { | |||
comps = color.getColorComponents(null); | |||
} else { | |||
if (log.isDebugEnabled()) { | |||
log.debug("Converting color to sRGB as a fallback: " + color); | |||
} | |||
ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); | |||
comps = color.getColorComponents(sRGB, null); | |||
} | |||
if (ColorUtil.isGray(color)) { | |||
comps = new float[] {comps[0]}; //assuming that all components are the same | |||
writeColor(codeBuffer, comps, 1, (fill ? "g" : "G")); | |||
} else { | |||
writeColor(codeBuffer, comps, 3, (fill ? "rg" : "RG")); | |||
} | |||
} | |||
private void establishDeviceCMYK(StringBuffer codeBuffer, Color color, boolean fill) { | |||
writeColor(codeBuffer, color, 4, (fill ? "k" : "K")); | |||
} | |||
private void writeColor(StringBuffer codeBuffer, Color color, int componentCount, | |||
String command) { | |||
float[] comps = color.getColorComponents(null); | |||
writeColor(codeBuffer, comps, componentCount, command); | |||
} | |||
private void writeColor(StringBuffer codeBuffer, float[] comps, int componentCount, | |||
String command) { | |||
if (comps.length != componentCount) { | |||
throw new IllegalStateException("Color with unexpected component count encountered"); | |||
} | |||
DecimalFormat df = DecimalFormatCache.getDecimalFormat(4); | |||
for (int i = 0, c = comps.length; i < c; i++) { | |||
codeBuffer.append(df.format(comps[i])).append(" "); | |||
} | |||
codeBuffer.append(command).append("\n"); | |||
} | |||
} |
@@ -19,6 +19,8 @@ | |||
package org.apache.fop.pdf; | |||
import java.awt.color.ColorSpace; | |||
/** | |||
* Represents a device-specific color space. Used for mapping DeviceRGB, DeviceCMYK and DeviceGray. | |||
*/ | |||
@@ -137,4 +139,28 @@ public class PDFDeviceColorSpace implements PDFColorSpace { | |||
return getColorSpace() == DEVICE_GRAY; | |||
} | |||
/** | |||
* Returns a suitable {@link PDFDeviceColorSpace} object given a {@link ColorSpace} object. | |||
* @param cs ColorSpace instance | |||
* @return a PDF-based color space | |||
*/ | |||
public static PDFDeviceColorSpace toPDFColorSpace(ColorSpace cs) { | |||
if (cs == null) { | |||
return null; | |||
} | |||
PDFDeviceColorSpace pdfCS = new PDFDeviceColorSpace(0); | |||
switch (cs.getType()) { | |||
case ColorSpace.TYPE_CMYK: | |||
pdfCS.setColorSpace(PDFDeviceColorSpace.DEVICE_CMYK); | |||
break; | |||
case ColorSpace.TYPE_GRAY: | |||
pdfCS.setColorSpace(PDFDeviceColorSpace.DEVICE_GRAY); | |||
break; | |||
default: | |||
pdfCS.setColorSpace(PDFDeviceColorSpace.DEVICE_RGB); | |||
} | |||
return pdfCS; | |||
} | |||
} |
@@ -67,7 +67,7 @@ import org.apache.commons.logging.LogFactory; | |||
*/ | |||
public class PDFDocument { | |||
private static final Integer LOCATION_PLACEHOLDER = new Integer(0); | |||
private static final Long LOCATION_PLACEHOLDER = new Long(0); | |||
/** Integer constant to represent PDF 1.3 */ | |||
public static final int PDF_VERSION_1_3 = 3; | |||
@@ -85,13 +85,13 @@ public class PDFDocument { | |||
private Log log = LogFactory.getLog("org.apache.fop.pdf"); | |||
/** the current character position */ | |||
private int position = 0; | |||
private long position = 0; | |||
/** character position of xref table */ | |||
private int xref; | |||
private long xref; | |||
/** the character position of each object */ | |||
private List location = new ArrayList(); | |||
private List<Long> location = new ArrayList<Long>(); | |||
/** List of objects to write in the trailer */ | |||
private List trailerObjects = new ArrayList(); | |||
@@ -747,6 +747,7 @@ public class PDFDocument { | |||
* @return the image or PDFXObject for the key if found | |||
* @deprecated Use getXObject instead (so forms are treated in the same way) | |||
*/ | |||
@Deprecated | |||
public PDFImageXObject getImage(String key) { | |||
return (PDFImageXObject)this.xObjectsMap.get(key); | |||
} | |||
@@ -911,11 +912,11 @@ public class PDFDocument { | |||
* @param objidx the object's index | |||
* @param position the position | |||
*/ | |||
private void setLocation(int objidx, int position) { | |||
private void setLocation(int objidx, long position) { | |||
while (this.location.size() <= objidx) { | |||
this.location.add(LOCATION_PLACEHOLDER); | |||
} | |||
this.location.set(objidx, new Integer(position)); | |||
this.location.set(objidx, position); | |||
} | |||
/** | |||
@@ -1071,6 +1072,9 @@ public class PDFDocument { | |||
for (int count = 0; count < this.location.size(); count++) { | |||
final String padding = "0000000000"; | |||
s = this.location.get(count).toString(); | |||
if (s.length() > 10) { | |||
throw new IOException("PDF file too large. PDF cannot grow beyond approx. 9.3GB."); | |||
} | |||
/* contruct xref entry for object */ | |||
loc = padding.substring(s.length()) + s; |
@@ -20,6 +20,7 @@ | |||
package org.apache.fop.pdf; | |||
// Java | |||
import java.awt.Color; | |||
import java.awt.geom.Point2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.io.FileNotFoundException; | |||
@@ -27,6 +28,7 @@ import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.MalformedURLException; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.BitSet; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
@@ -40,6 +42,8 @@ import org.apache.commons.io.output.ByteArrayOutputStream; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||
import org.apache.xmlgraphics.java2d.color.NamedColorSpace; | |||
import org.apache.xmlgraphics.xmp.Metadata; | |||
import org.apache.fop.fonts.CIDFont; | |||
@@ -779,23 +783,23 @@ public class PDFFactory { | |||
for (currentPosition = 0; currentPosition < lastPosition; | |||
currentPosition++) { // for every consecutive color pair | |||
PDFColor currentColor = (PDFColor)theColors.get(currentPosition); | |||
PDFColor nextColor = (PDFColor)theColors.get(currentPosition | |||
+ 1); | |||
// colorspace must be consistant | |||
if (getDocument().getColorSpace() != currentColor.getColorSpace()) { | |||
currentColor.setColorSpace( | |||
getDocument().getColorSpace()); | |||
Color currentColor = (Color)theColors.get(currentPosition); | |||
Color nextColor = (Color)theColors.get(currentPosition + 1); | |||
// colorspace must be consistent, so we simply convert to sRGB where necessary | |||
if (!currentColor.getColorSpace().isCS_sRGB()) { | |||
//Convert to sRGB | |||
currentColor = ColorUtil.toSRGBColor(currentColor); | |||
theColors.set(currentPosition, currentColor); | |||
} | |||
if (getDocument().getColorSpace() | |||
!= nextColor.getColorSpace()) { | |||
nextColor.setColorSpace( | |||
getDocument().getColorSpace()); | |||
if (!nextColor.getColorSpace().isCS_sRGB()) { | |||
//Convert to sRGB | |||
nextColor = ColorUtil.toSRGBColor(nextColor); | |||
theColors.set(currentPosition + 1, nextColor); | |||
} | |||
theCzero = currentColor.getVector(); | |||
theCone = nextColor.getVector(); | |||
theCzero = toColorVector(currentColor); | |||
theCone = toColorVector(nextColor); | |||
myfunc = makeFunction(2, null, null, theCzero, theCone, | |||
interpolation); | |||
@@ -843,6 +847,15 @@ public class PDFFactory { | |||
return (myPattern); | |||
} | |||
private List toColorVector(Color nextColor) { | |||
List vector = new java.util.ArrayList(); | |||
float[] comps = nextColor.getColorComponents(null); | |||
for (int i = 0, c = comps.length; i < c; i++) { | |||
vector.add(new Double(comps[i])); | |||
} | |||
return vector; | |||
} | |||
/* ============= named destinations and the name dictionary ============ */ | |||
/** | |||
@@ -1781,6 +1794,38 @@ public class PDFFactory { | |||
return cs; | |||
} | |||
/** | |||
* Create a new Separation color space. | |||
* @param res the resource context (may be null) | |||
* @param ncs the named color space to map to a separation color space | |||
* @return the newly created Separation color space | |||
*/ | |||
public PDFSeparationColorSpace makeSeparationColorSpace(PDFResourceContext res, | |||
NamedColorSpace ncs) { | |||
String colorName = ncs.getColorName(); | |||
final Double zero = new Double(0d); | |||
final Double one = new Double(1d); | |||
List theDomain = Arrays.asList(new Double[] {zero, one}); | |||
List theRange = Arrays.asList(new Double[] {zero, one, zero, one, zero, one}); | |||
List theCZero = Arrays.asList(new Double[] {one, one, one}); | |||
List theCOne = new ArrayList(); | |||
float[] comps = ncs.getRGBColor().getColorComponents(null); | |||
for (int i = 0, c = comps.length; i < c; i++) { | |||
theCOne.add(new Double(comps[i])); | |||
} | |||
PDFFunction tintFunction = makeFunction(2, theDomain, theRange, | |||
theCZero, theCOne, 1.0d); | |||
PDFSeparationColorSpace cs = new PDFSeparationColorSpace(colorName, tintFunction); | |||
getDocument().registerObject(cs); | |||
if (res != null) { | |||
res.getPDFResources().addColorSpace(cs); | |||
} else { | |||
getDocument().getResources().addColorSpace(cs); | |||
} | |||
return cs; | |||
} | |||
/** | |||
* Make an Array object (ex. Widths array for a font). | |||
* |
@@ -86,6 +86,29 @@ public class PDFName extends PDFObject { | |||
return this.name; | |||
} | |||
/** | |||
* Returns the name without the leading slash. | |||
* @return the name without the leading slash | |||
*/ | |||
public String getName() { | |||
return this.name.substring(1); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean equals(Object obj) { | |||
if (!(obj instanceof PDFName)) { | |||
return false; | |||
} | |||
PDFName other = (PDFName)obj; | |||
return this.name.equals(other.name); | |||
} | |||
/** {@inheritDoc} */ | |||
public int hashCode() { | |||
return name.hashCode(); | |||
} | |||
/** {@inheritDoc} */ | |||
protected int output(OutputStream stream) throws IOException { | |||
CountingOutputStream cout = new CountingOutputStream(stream); |
@@ -19,12 +19,15 @@ | |||
package org.apache.fop.pdf; | |||
import java.awt.Color; | |||
import java.awt.Paint; | |||
import java.awt.Shape; | |||
import java.awt.geom.Area; | |||
import java.awt.geom.GeneralPath; | |||
import java.util.Iterator; | |||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||
import org.apache.fop.util.AbstractPaintingState; | |||
/** | |||
@@ -63,13 +66,18 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState | |||
*/ | |||
public boolean setPaint(Paint p) { | |||
PDFData data = getPDFData(); | |||
Paint paint = data.paint; | |||
if (paint == null) { | |||
Paint currentPaint = data.paint; | |||
if (currentPaint == null) { | |||
if (p != null) { | |||
data.paint = p; | |||
return true; | |||
} | |||
} else if (!paint.equals(p)) { | |||
} else if (p instanceof Color && currentPaint instanceof Color) { | |||
if (!ColorUtil.isSameColor((Color)p, (Color)currentPaint)) { | |||
data.paint = p; | |||
return true; | |||
} | |||
} else if (!currentPaint.equals(p)) { | |||
data.paint = p; | |||
return true; | |||
} | |||
@@ -180,11 +188,13 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected AbstractData instantiateData() { | |||
return new PDFData(); | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected AbstractPaintingState instantiate() { | |||
return new PDFPaintingState(); | |||
} | |||
@@ -194,6 +204,7 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState | |||
* This call should be used when the q operator is used | |||
* so that the state is known when popped. | |||
*/ | |||
@Override | |||
public void save() { | |||
AbstractData data = getData(); | |||
AbstractData copy = (AbstractData)data.clone(); | |||
@@ -222,6 +233,7 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState | |||
private float characterSpacing = 0f; | |||
/** {@inheritDoc} */ | |||
@Override | |||
public Object clone() { | |||
PDFData obj = (PDFData)super.clone(); | |||
obj.paint = this.paint; | |||
@@ -237,6 +249,7 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public String toString() { | |||
return super.toString() | |||
+ ", paint=" + paint | |||
@@ -249,6 +262,7 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected AbstractData instantiate() { | |||
return new PDFData(); | |||
} |
@@ -19,6 +19,8 @@ | |||
package org.apache.fop.pdf; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.Iterator; | |||
@@ -33,12 +35,12 @@ import org.apache.fop.fonts.base14.Symbol; | |||
import org.apache.fop.fonts.base14.ZapfDingbats; | |||
/** | |||
* class representing a /Resources object. | |||
* Class representing a /Resources object. | |||
* | |||
* /Resources object contain a list of references to the fonts for the | |||
* document | |||
*/ | |||
public class PDFResources extends PDFObject { | |||
public class PDFResources extends PDFDictionary { | |||
/** | |||
* /Font objects keyed by their internal name | |||
@@ -159,11 +161,14 @@ public class PDFResources extends PDFObject { | |||
* Add a ColorSpace dictionary to the resources. | |||
* @param colorSpace the color space | |||
*/ | |||
public void addColorSpace(PDFICCBasedColorSpace colorSpace) { | |||
this.colorSpaces.put(colorSpace.getName(), colorSpace); | |||
String desc = ColorProfileUtil.getICCProfileDescription( | |||
colorSpace.getICCStream().getICCProfile()); | |||
this.iccColorSpaces.put(desc, colorSpace); | |||
public void addColorSpace(PDFColorSpace colorSpace) { | |||
this.colorSpaces.put(new PDFName(colorSpace.getName()), colorSpace); | |||
if (colorSpace instanceof PDFICCBasedColorSpace) { | |||
PDFICCBasedColorSpace icc = (PDFICCBasedColorSpace)colorSpace; | |||
String desc = ColorProfileUtil.getICCProfileDescription( | |||
icc.getICCStream().getICCProfile()); | |||
this.iccColorSpaces.put(desc, colorSpace); | |||
} | |||
} | |||
/** | |||
@@ -181,106 +186,80 @@ public class PDFResources extends PDFObject { | |||
* @param name the name of the color space | |||
* @return the requested color space or null if it wasn't found | |||
*/ | |||
public PDFICCBasedColorSpace getColorSpace(String name) { | |||
PDFICCBasedColorSpace cs = (PDFICCBasedColorSpace)this.colorSpaces.get(name); | |||
public PDFColorSpace getColorSpace(PDFName name) { | |||
PDFColorSpace cs = (PDFColorSpace)this.colorSpaces.get(name); | |||
return cs; | |||
} | |||
/** | |||
* represent the object in PDF | |||
* This adds the references to all the objects in the current | |||
* resource context. | |||
* | |||
* @return the PDF | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
public String toPDFString() { | |||
StringBuffer p = new StringBuffer(128); | |||
p.append(getObjectID() + "<<\n"); | |||
if (!this.fonts.isEmpty()) { | |||
p.append("/Font <<\n"); | |||
/** {@inheritDoc} */ | |||
protected int output(OutputStream stream) throws IOException { | |||
populateDictionary(); | |||
return super.output(stream); | |||
} | |||
private void populateDictionary() { | |||
if (!this.fonts.isEmpty()) { | |||
PDFDictionary dict = new PDFDictionary(this); | |||
/* construct PDF dictionary of font object references */ | |||
Iterator fontIterator = this.fonts.keySet().iterator(); | |||
while (fontIterator.hasNext()) { | |||
String fontName = (String)fontIterator.next(); | |||
p.append(" /" + fontName + " " | |||
+ ((PDFFont)this.fonts.get(fontName)).referencePDF() | |||
+ "\n"); | |||
dict.put(fontName, (PDFFont)this.fonts.get(fontName)); | |||
} | |||
p.append(">>\n"); | |||
put("Font", dict); | |||
} | |||
PDFShading currentShading = null; | |||
if (!this.shadings.isEmpty()) { | |||
p.append("/Shading <<\n"); | |||
PDFDictionary dict = new PDFDictionary(this); | |||
for (Iterator iter = shadings.iterator(); iter.hasNext();) { | |||
currentShading = (PDFShading)iter.next(); | |||
p.append(" /" + currentShading.getName() + " " | |||
+ currentShading.referencePDF() + " "); // \n ?????? | |||
PDFShading currentShading = (PDFShading)iter.next(); | |||
dict.put(currentShading.getName(), currentShading); | |||
} | |||
p.append(">>\n"); | |||
put("Shading", dict); | |||
} | |||
// "free" the memory. Sorta. | |||
currentShading = null; | |||
PDFPattern currentPattern = null; | |||
if (!this.patterns.isEmpty()) { | |||
p.append("/Pattern <<\n"); | |||
PDFDictionary dict = new PDFDictionary(this); | |||
for (Iterator iter = patterns.iterator(); iter.hasNext();) { | |||
currentPattern = (PDFPattern)iter.next(); | |||
p.append(" /" + currentPattern.getName() + " " | |||
+ currentPattern.referencePDF() + " "); | |||
PDFPattern currentPattern = (PDFPattern)iter.next(); | |||
dict.put(currentPattern.getName(), currentPattern); | |||
} | |||
p.append(">>\n"); | |||
put("Pattern", dict); | |||
} | |||
// "free" the memory. Sorta. | |||
currentPattern = null; | |||
p.append("/ProcSet [ /PDF /ImageB /ImageC /Text ]\n"); | |||
PDFArray procset = new PDFArray(this); | |||
procset.add(new PDFName("PDF")); | |||
procset.add(new PDFName("ImageB")); | |||
procset.add(new PDFName("ImageC")); | |||
procset.add(new PDFName("Text")); | |||
put("ProcSet", procset); | |||
if (this.xObjects != null && !this.xObjects.isEmpty()) { | |||
p = p.append("/XObject <<\n"); | |||
PDFDictionary dict = new PDFDictionary(this); | |||
for (Iterator iter = xObjects.iterator(); iter.hasNext();) { | |||
PDFXObject xobj = (PDFXObject)iter.next(); | |||
p = p.append(" " + xobj.getName() + " " | |||
+ xobj.referencePDF() | |||
+ "\n"); | |||
dict.put(xobj.getName().toString(), xobj); | |||
} | |||
p = p.append(">>\n"); | |||
put("XObject", dict); | |||
} | |||
if (!this.gstates.isEmpty()) { | |||
p = p.append("/ExtGState <<\n"); | |||
PDFDictionary dict = new PDFDictionary(this); | |||
for (Iterator iter = gstates.iterator(); iter.hasNext();) { | |||
PDFGState gs = (PDFGState)iter.next(); | |||
p = p.append(" /" + gs.getName() + " " | |||
+ gs.referencePDF() | |||
+ "\n"); | |||
dict.put(gs.getName(), gs); | |||
} | |||
p = p.append(">>\n"); | |||
put("ExtGState", dict); | |||
} | |||
if (!this.colorSpaces.isEmpty()) { | |||
p = p.append("/ColorSpace <<\n"); | |||
PDFDictionary dict = new PDFDictionary(this); | |||
for (Iterator iter = colorSpaces.values().iterator(); iter.hasNext();) { | |||
PDFICCBasedColorSpace colorSpace = (PDFICCBasedColorSpace)iter.next(); | |||
p = p.append(" /" + colorSpace.getName() + " " | |||
+ colorSpace.referencePDF() | |||
+ "\n"); | |||
PDFColorSpace colorSpace = (PDFColorSpace)iter.next(); | |||
dict.put(colorSpace.getName(), colorSpace); | |||
} | |||
p = p.append(">>\n"); | |||
put("ColorSpace", dict); | |||
} | |||
p = p.append(">>\nendobj\n"); | |||
return p.toString(); | |||
} | |||
} |
@@ -0,0 +1,88 @@ | |||
/* | |||
* 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.pdf; | |||
/** | |||
* This class represents a "Separation" color space. It is used in FOP to map named colors. | |||
*/ | |||
public class PDFSeparationColorSpace extends PDFArray implements PDFColorSpace { | |||
/** | |||
* Creates a new "Separation" color space. | |||
* @param colorName the name of the colorant | |||
* @param tintFunction the tint function used as fallback | |||
*/ | |||
public PDFSeparationColorSpace(String colorName, PDFFunction tintFunction) { | |||
super(); | |||
add(new PDFName("Separation")); | |||
add(new PDFName(colorName)); | |||
add(new PDFName("DeviceRGB")); | |||
add(new PDFReference(tintFunction)); | |||
} | |||
/** {@inheritDoc} */ | |||
public String getName() { | |||
//return "CS" + this.getObjectNumber(); | |||
return getColorName().toString(); | |||
} | |||
/** | |||
* Returns the name of the colorant. | |||
* @return the name of the colorant | |||
*/ | |||
public PDFName getColorName() { | |||
return (PDFName)get(1); | |||
} | |||
/** | |||
* Returns a reference to the tint function that is used as a fallback if the colorant is | |||
* not available. | |||
* @return a reference to the tint function | |||
*/ | |||
public PDFReference getTintFunction() { | |||
return (PDFReference)get(2); | |||
} | |||
/** {@inheritDoc} */ | |||
public int getNumComponents() { | |||
return 1; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isCMYKColorSpace() { | |||
return false; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isDeviceColorSpace() { | |||
return false; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isGrayColorSpace() { | |||
return false; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isRGBColorSpace() { | |||
return false; | |||
} | |||
} |
@@ -33,6 +33,7 @@ import java.util.Map; | |||
import org.w3c.dom.Document; | |||
import org.w3c.dom.Node; | |||
import org.w3c.dom.NodeList; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
@@ -75,6 +76,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected String getMainNamespace() { | |||
return NAMESPACE; | |||
} | |||
@@ -101,6 +103,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public IFDocumentNavigationHandler getDocumentNavigationHandler() { | |||
return this; | |||
} | |||
@@ -146,6 +149,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void startDocument() throws IFException { | |||
super.startDocument(); | |||
try { | |||
@@ -161,6 +165,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void startDocumentHeader() throws IFException { | |||
try { | |||
handler.startElement(EL_HEADER); | |||
@@ -170,6 +175,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void endDocumentHeader() throws IFException { | |||
try { | |||
handler.endElement(EL_HEADER); | |||
@@ -179,6 +185,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void startDocumentTrailer() throws IFException { | |||
try { | |||
handler.startElement(EL_TRAILER); | |||
@@ -188,6 +195,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void endDocumentTrailer() throws IFException { | |||
try { | |||
handler.endElement(EL_TRAILER); | |||
@@ -264,6 +272,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void startPageHeader() throws IFException { | |||
try { | |||
handler.startElement(EL_PAGE_HEADER); | |||
@@ -273,6 +282,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void endPageHeader() throws IFException { | |||
try { | |||
handler.endElement(EL_PAGE_HEADER); | |||
@@ -303,6 +313,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void startPageTrailer() throws IFException { | |||
try { | |||
handler.startElement(EL_PAGE_TRAILER); | |||
@@ -312,6 +323,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void endPageTrailer() throws IFException { | |||
try { | |||
commitNavigation(); | |||
@@ -604,7 +616,8 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler | |||
} | |||
} | |||
if (color != null) { | |||
changed = !color.equals(state.getTextColor()); | |||
changed = !org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor( | |||
color, state.getTextColor()); | |||
if (changed) { | |||
state.setTextColor(color); | |||
addAttribute(atts, "color", toString(color)); |
@@ -21,6 +21,8 @@ package org.apache.fop.render.intermediate; | |||
import java.awt.Color; | |||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||
/** a state class for intermediate format data */ | |||
public final class IFState { | |||
@@ -184,7 +186,7 @@ public final class IFState { | |||
* @param color the new text color | |||
*/ | |||
public void setTextColor(Color color) { | |||
if (!color.equals(this.textColor)) { | |||
if (!ColorUtil.isSameColor(color, this.textColor)) { | |||
this.fontChanged = true; | |||
} | |||
this.textColor = color; |
@@ -28,6 +28,8 @@ import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Area; | |||
import java.awt.geom.GeneralPath; | |||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||
import org.apache.fop.fo.Constants; | |||
import org.apache.fop.fonts.FontInfo; | |||
@@ -103,7 +105,7 @@ public class Java2DGraphicsState { | |||
* @return true if the background color has changed | |||
*/ | |||
public boolean updateColor(Color col) { | |||
if (!col.equals(getGraph().getColor())) { | |||
if (!ColorUtil.isSameColor(col, getGraph().getColor())) { | |||
getGraph().setColor(col); | |||
return true; | |||
} else { | |||
@@ -217,12 +219,18 @@ public class Java2DGraphicsState { | |||
* @return true if the new paint changes the current paint | |||
*/ | |||
public boolean updatePaint(Paint p) { | |||
if (getGraph().getPaint() == null) { | |||
Paint currentPaint = getGraph().getPaint(); | |||
if (currentPaint == null) { | |||
if (p != null) { | |||
getGraph().setPaint(p); | |||
return true; | |||
} | |||
} else if (!p.equals(getGraph().getPaint())) { | |||
} else if (p instanceof Color && currentPaint instanceof Color) { | |||
if (!ColorUtil.isSameColor((Color)p, (Color)currentPaint)) { | |||
getGraph().setPaint(p); | |||
return true; | |||
} | |||
} else if (!p.equals(currentPaint)) { | |||
getGraph().setPaint(p); | |||
return true; | |||
} | |||
@@ -271,6 +279,7 @@ public class Java2DGraphicsState { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public String toString() { | |||
String s = "Java2DGraphicsState " + currentGraphics.toString() | |||
+ ", Stroke (width: " + currentStrokeWidth + " style: " |
@@ -35,6 +35,7 @@ import org.apache.fop.pdf.PDFDocument; | |||
import org.apache.fop.pdf.PDFICCBasedColorSpace; | |||
import org.apache.fop.pdf.PDFICCStream; | |||
import org.apache.fop.pdf.PDFImage; | |||
import org.apache.fop.pdf.PDFName; | |||
import org.apache.fop.pdf.PDFReference; | |||
/** | |||
@@ -128,7 +129,8 @@ public abstract class AbstractImageAdapter implements PDFImage { | |||
} else { | |||
if (cs == null && desc.startsWith("sRGB")) { | |||
//It's the default sRGB profile which we mapped to DefaultRGB in PDFRenderer | |||
cs = doc.getResources().getColorSpace("DefaultRGB"); | |||
cs = (PDFICCBasedColorSpace)doc.getResources().getColorSpace( | |||
new PDFName("DefaultRGB")); | |||
} | |||
if (cs == null) { | |||
// sRGB hasn't been set up for the PDF document |
@@ -25,7 +25,7 @@ import java.awt.geom.AffineTransform; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import org.apache.fop.pdf.PDFColor; | |||
import org.apache.fop.pdf.PDFColorHandler; | |||
import org.apache.fop.pdf.PDFDocument; | |||
import org.apache.fop.pdf.PDFFilterList; | |||
import org.apache.fop.pdf.PDFNumber; | |||
@@ -51,6 +51,8 @@ public class PDFContentGenerator { | |||
/** the current stream to add PDF commands to */ | |||
private PDFStream currentStream; | |||
private PDFColorHandler colorHandler; | |||
/** drawing state */ | |||
protected PDFPaintingState currentState = null; | |||
/** Text generation utility holding the current font status */ | |||
@@ -80,6 +82,7 @@ public class PDFContentGenerator { | |||
}; | |||
this.currentState = new PDFPaintingState(); | |||
this.colorHandler = new PDFColorHandler(document.getResources()); | |||
} | |||
/** | |||
@@ -344,8 +347,9 @@ public class PDFContentGenerator { | |||
*/ | |||
public void setColor(Color col, boolean fill, PDFStream stream) { | |||
assert stream != null; | |||
PDFColor color = new PDFColor(this.document, col); | |||
stream.add(color.getColorSpaceOut(fill)); | |||
StringBuffer sb = new StringBuffer(); | |||
setColor(col, fill, sb); | |||
stream.add(sb.toString()); | |||
} | |||
/** | |||
@@ -367,8 +371,7 @@ public class PDFContentGenerator { | |||
*/ | |||
protected void setColor(Color col, boolean fill, StringBuffer pdf) { | |||
if (pdf != null) { | |||
PDFColor color = new PDFColor(this.document, col); | |||
pdf.append(color.getColorSpaceOut(fill)); | |||
colorHandler.establishColor(pdf, col, fill); | |||
} else { | |||
setColor(col, fill, this.currentStream); | |||
} |
@@ -122,6 +122,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
public void setUserAgent(FOUserAgent agent) { | |||
super.setUserAgent(agent); | |||
@@ -143,6 +144,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void setupFontInfo(FontInfo inFontInfo) throws FOPException { | |||
if (mimic != null) { | |||
mimic.setupFontInfo(inFontInfo); | |||
@@ -214,7 +216,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
//TODO Remove the following line (makes changes in the test checks necessary) | |||
addAttribute(name, bkg.toString()); | |||
if (bkg.getColor() != null) { | |||
addAttribute("bkg-color", bkg.getColor().toString()); | |||
addAttribute("bkg-color", ColorUtil.colorToString(bkg.getColor())); | |||
} | |||
if (bkg.getURL() != null) { | |||
addAttribute("bkg-img", bkg.getURL()); | |||
@@ -277,6 +279,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void processOffDocumentItem(OffDocumentItem oDI) { | |||
if (oDI instanceof BookmarkData) { | |||
renderBookmarkTree((BookmarkData) oDI); | |||
@@ -298,6 +301,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
* Renders a BookmarkTree object | |||
* @param bookmarkRoot the BookmarkData object representing the top of the tree | |||
*/ | |||
@Override | |||
protected void renderBookmarkTree(BookmarkData bookmarkRoot) { | |||
if (bookmarkRoot.getWhenToProcess() == OffDocumentItem.END_OF_DOC) { | |||
endPageSequence(); | |||
@@ -346,6 +350,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void startRenderer(OutputStream outputStream) | |||
throws IOException { | |||
log.debug("Rendering areas to Area Tree XML"); | |||
@@ -377,6 +382,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void stopRenderer() throws IOException { | |||
endPageSequence(); | |||
endElement("areaTree"); | |||
@@ -392,6 +398,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void renderPage(PageViewport page) throws IOException, FOPException { | |||
atts.clear(); | |||
addAttribute("bounds", page.getViewArea()); | |||
@@ -416,6 +423,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected void handleExtensionAttachments(List attachments) { | |||
if (attachments != null && attachments.size() > 0) { | |||
startElement("extension-attachments"); | |||
@@ -438,6 +446,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void startPageSequence(PageSequence pageSequence) { | |||
handleDocumentExtensionAttachments(); | |||
endPageSequence(); // move this before handleDocumentExtensionAttachments() ? | |||
@@ -502,6 +511,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderRegionViewport(RegionViewport port) { | |||
if (port != null) { | |||
atts.clear(); | |||
@@ -549,11 +559,13 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected void startVParea(CTM ctm, Rectangle2D clippingRect) { | |||
//only necessary for graphical output | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected void endVParea() { | |||
//only necessary for graphical output | |||
} | |||
@@ -562,6 +574,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
* {@inheritDoc} | |||
* org.apache.fop.area.inline.InlineArea) | |||
*/ | |||
@Override | |||
protected void renderInlineAreaBackAndBorders(InlineArea area) { | |||
//only necessary for graphical output | |||
} | |||
@@ -569,6 +582,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderBeforeFloat(BeforeFloat bf) { | |||
startElement("beforeFloat"); | |||
super.renderBeforeFloat(bf); | |||
@@ -578,6 +592,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderFootnote(Footnote footnote) { | |||
atts.clear(); | |||
addAttribute("top-offset", footnote.getTop()); | |||
@@ -589,6 +604,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderMainReference(MainReference mr) { | |||
atts.clear(); | |||
addAreaAttributes(mr); | |||
@@ -610,7 +626,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
addTraitAttributes(span); | |||
startElement("span", atts); | |||
for (int c = 0; c < span.getColumnCount(); c++) { | |||
NormalFlow flow = (NormalFlow) span.getNormalFlow(c); | |||
NormalFlow flow = span.getNormalFlow(c); | |||
renderFlow(flow); | |||
} | |||
@@ -622,6 +638,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderFlow(NormalFlow flow) { | |||
// the normal flow reference area contains stacked blocks | |||
atts.clear(); | |||
@@ -633,6 +650,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected void renderReferenceArea(Block block) { | |||
handleBlockTraits(block); | |||
@@ -643,6 +661,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
protected void renderBlock(Block block) { | |||
atts.clear(); | |||
addAreaAttributes(block); | |||
@@ -691,6 +710,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderLineArea(LineArea line) { | |||
atts.clear(); | |||
addAreaAttributes(line); | |||
@@ -703,6 +723,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderInlineArea(InlineArea inlineArea) { | |||
atts.clear(); | |||
if (inlineArea.getClass() == InlineArea.class) { | |||
@@ -721,6 +742,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderViewport(Viewport viewport) { | |||
atts.clear(); | |||
addAreaAttributes(viewport); | |||
@@ -738,6 +760,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
public void renderImage(Image image, Rectangle2D pos) { | |||
atts.clear(); | |||
addAreaAttributes(image); | |||
@@ -751,6 +774,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
public void renderContainer(Container cont) { | |||
startElement("container"); | |||
super.renderContainer(cont); | |||
@@ -763,6 +787,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
* @param pos the position of the foreign object | |||
* @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D) | |||
*/ | |||
@Override | |||
public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { | |||
atts.clear(); | |||
addAreaAttributes(fo); | |||
@@ -779,6 +804,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderInlineSpace(Space space) { | |||
atts.clear(); | |||
addAreaAttributes(space); | |||
@@ -791,6 +817,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderText(TextArea text) { | |||
atts.clear(); | |||
if (text.getTextWordSpaceAdjust() != 0) { | |||
@@ -811,6 +838,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderWord(WordArea word) { | |||
atts.clear(); | |||
addAttribute("offset", word.getOffset()); | |||
@@ -838,6 +866,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderSpace(SpaceArea space) { | |||
atts.clear(); | |||
addAttribute("offset", space.getOffset()); | |||
@@ -853,6 +882,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderInlineParent(InlineParent ip) { | |||
atts.clear(); | |||
addAreaAttributes(ip); | |||
@@ -866,6 +896,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderInlineBlockParent(InlineBlockParent ibp) { | |||
atts.clear(); | |||
addAreaAttributes(ibp); | |||
@@ -879,6 +910,7 @@ public class XMLRenderer extends AbstractXMLRenderer { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
protected void renderLeader(Leader area) { | |||
atts.clear(); | |||
addAreaAttributes(area); |
@@ -25,6 +25,7 @@ import org.apache.batik.bridge.BridgeContext; | |||
import org.apache.batik.bridge.DocumentLoader; | |||
import org.apache.batik.bridge.SVGTextElementBridge; | |||
import org.apache.batik.bridge.UserAgent; | |||
import org.apache.batik.dom.svg.SVGOMDocument; | |||
import org.apache.batik.gvt.TextPainter; | |||
import org.apache.xmlgraphics.image.loader.ImageManager; | |||
@@ -86,6 +87,7 @@ public class PDFBridgeContext extends AbstractFOPBridgeContext { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public void registerSVGBridges() { | |||
super.registerSVGBridges(); | |||
@@ -123,10 +125,17 @@ public class PDFBridgeContext extends AbstractFOPBridgeContext { | |||
putBridge(new PDFImageElementBridge()); | |||
} | |||
// Make sure any 'sub bridge contexts' also have our bridges. | |||
//TODO There's no matching method in the super-class here | |||
/** @return the new bridge context */ | |||
/** {@inheritDoc} */ | |||
@Override | |||
public BridgeContext createBridgeContext() { | |||
//Retained for pre-Batik-1.7 compatibility | |||
return createBridgeContext(null); | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public BridgeContext createBridgeContext(SVGOMDocument doc) { | |||
// Make sure any 'sub bridge contexts' also have our bridges. | |||
return new PDFBridgeContext(getUserAgent(), getDocumentLoader(), | |||
fontInfo, | |||
getImageManager(), |
@@ -36,7 +36,7 @@ import org.apache.fop.Version; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.fonts.FontSetup; | |||
import org.apache.fop.pdf.PDFAnnotList; | |||
import org.apache.fop.pdf.PDFColor; | |||
import org.apache.fop.pdf.PDFColorHandler; | |||
import org.apache.fop.pdf.PDFDocument; | |||
import org.apache.fop.pdf.PDFFilterList; | |||
import org.apache.fop.pdf.PDFNumber; | |||
@@ -101,6 +101,7 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { | |||
this.pdfDoc = new PDFDocument("Apache FOP Version " + Version.getVersion() | |||
+ ": PDFDocumentGraphics2D"); | |||
this.pdfContext = new PDFContext(); | |||
this.colorHandler = new PDFColorHandler(this.pdfDoc.getResources()); | |||
} | |||
/** | |||
@@ -232,15 +233,15 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { | |||
* @param col the background colour to fill | |||
*/ | |||
public void setBackgroundColor(Color col) { | |||
Color c = col; | |||
PDFColor currentColour = new PDFColor(c.getRed(), c.getGreen(), c.getBlue()); | |||
currentStream.write("q\n"); | |||
currentStream.write(currentColour.getColorSpaceOut(true)); | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append("q\n"); | |||
this.colorHandler.establishColor(sb, col, true); | |||
currentStream.write("0 0 " + width + " " + height + " re\n"); | |||
sb.append("0 0 ").append(width).append(" ").append(height).append(" re\n"); | |||
currentStream.write("f\n"); | |||
currentStream.write("Q\n"); | |||
sb.append("f\n"); | |||
sb.append("Q\n"); | |||
currentStream.write(sb.toString()); | |||
} | |||
/** |
@@ -75,6 +75,7 @@ import org.apache.fop.fonts.FontSetup; | |||
import org.apache.fop.pdf.BitmapImage; | |||
import org.apache.fop.pdf.PDFAnnotList; | |||
import org.apache.fop.pdf.PDFColor; | |||
import org.apache.fop.pdf.PDFColorHandler; | |||
import org.apache.fop.pdf.PDFConformanceException; | |||
import org.apache.fop.pdf.PDFDeviceColorSpace; | |||
import org.apache.fop.pdf.PDFDocument; | |||
@@ -92,7 +93,6 @@ 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; | |||
/** | |||
* PDF Graphics 2D. | |||
@@ -132,6 +132,9 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand | |||
*/ | |||
protected PDFPaintingState paintingState; | |||
/** the PDF color handler */ | |||
protected PDFColorHandler colorHandler; | |||
/** | |||
* The PDF graphics state level that this svg is being drawn into. | |||
*/ | |||
@@ -194,6 +197,7 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand | |||
PDFResourceContext page, String pref, String font, float size) { | |||
this(textAsShapes); | |||
pdfDoc = doc; | |||
this.colorHandler = new PDFColorHandler(doc.getResources()); | |||
resourceContext = page; | |||
currentFontName = font; | |||
currentFontSize = size; | |||
@@ -220,6 +224,7 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand | |||
public PDFGraphics2D(PDFGraphics2D g) { | |||
super(g); | |||
this.pdfDoc = g.pdfDoc; | |||
this.colorHandler = g.colorHandler; | |||
this.resourceContext = g.resourceContext; | |||
this.currentFontName = g.currentFontName; | |||
this.currentFontSize = g.currentFontSize; | |||
@@ -732,39 +737,20 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand | |||
protected void applyColor(Color col, boolean fill) { | |||
preparePainting(); | |||
Color c = col; | |||
if (col instanceof ColorExt) { | |||
PDFColor currentColour = new PDFColor(this.pdfDoc, col); | |||
currentStream.write(currentColour.getColorSpaceOut(fill)); | |||
} else if (c.getColorSpace().getType() | |||
== ColorSpace.TYPE_RGB) { | |||
PDFColor currentColour = new PDFColor(c.getRed(), c.getGreen(), | |||
c.getBlue()); | |||
currentStream.write(currentColour.getColorSpaceOut(fill)); | |||
} else if (c.getColorSpace().getType() | |||
== ColorSpace.TYPE_CMYK) { | |||
if (pdfDoc.getProfile().getPDFAMode().isPDFA1LevelB()) { | |||
//See PDF/A-1, ISO 19005:1:2005(E), 6.2.3.3 | |||
//FOP is currently restricted to DeviceRGB if PDF/A-1 is active. | |||
throw new PDFConformanceException( | |||
"PDF/A-1 does not allow mixing DeviceRGB and DeviceCMYK."); | |||
} | |||
PDFColor currentColour = new PDFColor(c); | |||
currentStream.write(currentColour.getColorSpaceOut(fill)); | |||
} else if (c.getColorSpace().getType() | |||
== ColorSpace.TYPE_2CLR) { | |||
// used for black/magenta | |||
float[] cComps = c.getColorComponents(new float[1]); | |||
double[] blackMagenta = new double[1]; | |||
for (int i = 0; i < 1; i++) { | |||
blackMagenta[i] = cComps[i]; | |||
} | |||
//PDFColor currentColour = new PDFColor(blackMagenta[0], blackMagenta[1]); | |||
//currentStream.write(currentColour.getColorSpaceOut(fill)); | |||
} else { | |||
throw new UnsupportedOperationException( | |||
"Color Space not supported by PDFGraphics2D: " + c.getColorSpace()); | |||
//TODO Handle this in PDFColorHandler by automatically converting the color. | |||
//This won't work properly anyway after the redesign of ColorExt | |||
if (col.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { | |||
if (pdfDoc.getProfile().getPDFAMode().isPDFA1LevelB()) { | |||
//See PDF/A-1, ISO 19005:1:2005(E), 6.2.3.3 | |||
//FOP is currently restricted to DeviceRGB if PDF/A-1 is active. | |||
throw new PDFConformanceException( | |||
"PDF/A-1 does not allow mixing DeviceRGB and DeviceCMYK."); | |||
} | |||
} | |||
StringBuffer sb = new StringBuffer(); | |||
colorHandler.establishColor(sb, col, fill); | |||
currentStream.write(sb.toString()); | |||
} | |||
/** | |||
@@ -858,14 +844,15 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand | |||
return false; // PDF can't do alpha | |||
} | |||
PDFColor color1 = new PDFColor(c1.getRed(), c1.getGreen(), | |||
c1.getBlue()); | |||
someColors.add(color1); | |||
//PDFColor color1 = new PDFColor(c1.getRed(), c1.getGreen(), | |||
// c1.getBlue()); | |||
someColors.add(c1); | |||
if (count > 0 && count < cols.length - 1) { | |||
theBounds.add(new Double(fractions[count])); | |||
} | |||
} | |||
//Gradients are currently restricted to sRGB | |||
PDFDeviceColorSpace aColorSpace; | |||
aColorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); | |||
PDFPattern myPat = pdfDoc.getFactory().makeGradient( | |||
@@ -933,8 +920,7 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand | |||
return false; // PDF can't do alpha | |||
} | |||
someColors.add(new PDFColor(cc.getRed(), cc.getGreen(), | |||
cc.getBlue())); | |||
someColors.add(cc); | |||
} | |||
float[] fractions = rgp.getFractions(); |
@@ -98,11 +98,13 @@ public class BorderProps implements Serializable { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public int hashCode() { | |||
return toString().hashCode(); | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public boolean equals(Object obj) { | |||
if (obj == null) { | |||
return false; | |||
@@ -112,7 +114,8 @@ public class BorderProps implements Serializable { | |||
if (obj instanceof BorderProps) { | |||
BorderProps other = (BorderProps)obj; | |||
return (style == other.style) | |||
&& color.equals(other.color) | |||
&& org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor( | |||
color, other.color) | |||
&& width == other.width | |||
&& mode == other.mode; | |||
} | |||
@@ -163,6 +166,7 @@ public class BorderProps implements Serializable { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public String toString() { | |||
StringBuffer sbuf = new StringBuffer(); | |||
sbuf.append('('); |
@@ -75,7 +75,8 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable { | |||
* @return true if the color has changed | |||
*/ | |||
public boolean setColor(Color col) { | |||
if (!col.equals(getData().color)) { | |||
Color other = getData().color; | |||
if (!org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor(col, other)) { | |||
getData().color = col; | |||
return true; | |||
} | |||
@@ -114,7 +115,8 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable { | |||
* @return true if the color has changed | |||
*/ | |||
public boolean setBackColor(Color col) { | |||
if (!col.equals(getData().backColor)) { | |||
Color other = getData().backColor; | |||
if (!org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor(col, other)) { | |||
getData().backColor = col; | |||
return true; | |||
} | |||
@@ -364,6 +366,7 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public Object clone() { | |||
AbstractPaintingState state = instantiate(); | |||
state.stateStack = new StateStack(this.stateStack); | |||
@@ -372,6 +375,7 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public String toString() { | |||
return ", stateStack=" + stateStack | |||
+ ", currentData=" + data; | |||
@@ -506,6 +510,7 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public Object clone() { | |||
AbstractData data = instantiate(); | |||
data.color = this.color; | |||
@@ -522,6 +527,7 @@ public abstract class AbstractPaintingState implements Cloneable, Serializable { | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public String toString() { | |||
return "color=" + color | |||
+ ", backColor=" + backColor |
@@ -1,3 +1,4 @@ | |||
<<<<<<< .working | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
@@ -248,3 +249,261 @@ public final class ColorExt extends Color { | |||
} | |||
} | |||
======= | |||
/* | |||
* 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.util; | |||
import java.awt.Color; | |||
import java.awt.color.ColorSpace; | |||
import java.util.Arrays; | |||
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; | |||
/** | |||
* Color helper class. | |||
* <p> | |||
* This class extends java.awt.Color class keeping track of the original color | |||
* property values specified by the fo user in a rgb-icc call. | |||
* @deprecated Replaced by {@link ColorWithAlternatives} | |||
*/ | |||
@Deprecated | |||
public final class ColorExt extends Color { | |||
// | |||
private static final long serialVersionUID = 1L; | |||
// Values of fop-rgb-icc arguments | |||
private float rgbReplacementRed; | |||
private float rgbReplacementGreen; | |||
private float rgbReplacementBlue; | |||
private String iccProfileName; | |||
private String iccProfileSrc; | |||
private ColorSpace colorSpace; | |||
private float[] colorValues; | |||
/* | |||
* Helper for createFromFoRgbIcc | |||
*/ | |||
private ColorExt(ColorSpace colorSpace, float[] colorValues, float opacity) { | |||
super(colorSpace, colorValues, opacity); | |||
} | |||
/* | |||
* Helper for createFromSvgIccColor | |||
*/ | |||
private ColorExt(float red, float green, float blue, float opacity) { | |||
super(red, green, blue, opacity); | |||
} | |||
/** | |||
* Create ColorExt object backup up FO's rgb-icc color function | |||
* | |||
* @param redReplacement | |||
* Red part of RGB replacement color that will be used when ICC | |||
* profile can not be loaded | |||
* @param greenReplacement | |||
* Green part of RGB replacement color that will be used when ICC | |||
* profile can not be loaded | |||
* @param blueReplacement | |||
* Blue part of RGB replacement color that will be used when ICC | |||
* profile can not be loaded | |||
* @param profileName | |||
* Name of ICC profile | |||
* @param profileSrc | |||
* Source of ICC profile | |||
* @param colorSpace | |||
* ICC ColorSpace for the ICC profile | |||
* @param iccValues | |||
* color values | |||
* @return the requested color object | |||
*/ | |||
public static ColorExt createFromFoRgbIcc(float redReplacement, | |||
float greenReplacement, float blueReplacement, String profileName, | |||
String profileSrc, ColorSpace colorSpace, float[] iccValues) { | |||
ColorExt ce = new ColorExt(colorSpace, iccValues, 1.0f); | |||
ce.rgbReplacementRed = redReplacement; | |||
ce.rgbReplacementGreen = greenReplacement; | |||
ce.rgbReplacementBlue = blueReplacement; | |||
ce.iccProfileName = profileName; | |||
ce.iccProfileSrc = profileSrc; | |||
ce.colorSpace = colorSpace; | |||
ce.colorValues = iccValues; | |||
return ce; | |||
} | |||
/** | |||
* Create ColorExt object backing up SVG's icc-color function. | |||
* | |||
* @param red | |||
* Red value resulting from the conversion from the user provided | |||
* (icc) color values to the batik (rgb) color space | |||
* @param green | |||
* Green value resulting from the conversion from the user | |||
* provided (icc) color values to the batik (rgb) color space | |||
* @param blue | |||
* Blue value resulting from the conversion from the user | |||
* provided (icc) color values to the batik (rgb) color space | |||
* @param opacity | |||
* Opacity | |||
* @param profileName | |||
* ICC profile name | |||
* @param profileHref | |||
* the URI to the color profile | |||
* @param profileCS | |||
* ICC ColorSpace profile | |||
* @param colorValues | |||
* ICC color values | |||
* @return the requested color object | |||
*/ | |||
public static ColorExt createFromSvgIccColor( // CSOK: ParameterNumber | |||
float red, float green, | |||
float blue, float opacity, String profileName, String profileHref, | |||
ColorSpace profileCS, float[] colorValues) { | |||
//TODO this method is not referenced by FOP, can it be deleted? | |||
ColorExt ce = new ColorExt(red, green, blue, opacity); | |||
ce.rgbReplacementRed = -1; | |||
ce.rgbReplacementGreen = -1; | |||
ce.rgbReplacementBlue = -1; | |||
ce.iccProfileName = profileName; | |||
ce.iccProfileSrc = profileHref; | |||
ce.colorSpace = profileCS; | |||
ce.colorValues = colorValues; | |||
return ce; | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public int hashCode() { | |||
//implementation from the superclass should be good enough for our purposes | |||
return super.hashCode(); | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public boolean equals(Object obj) { | |||
if (this == obj) { | |||
return true; | |||
} | |||
if (!super.equals(obj)) { | |||
return false; | |||
} | |||
if (getClass() != obj.getClass()) { | |||
return false; | |||
} | |||
ColorExt other = (ColorExt)obj; | |||
//TODO maybe use super.getColorComponents() instead | |||
if (!Arrays.equals(colorValues, other.colorValues)) { | |||
return false; | |||
} | |||
if (iccProfileName == null) { | |||
if (other.iccProfileName != null) { | |||
return false; | |||
} | |||
} else if (!iccProfileName.equals(other.iccProfileName)) { | |||
return false; | |||
} | |||
if (iccProfileSrc == null) { | |||
if (other.iccProfileSrc != null) { | |||
return false; | |||
} | |||
} else if (!iccProfileSrc.equals(other.iccProfileSrc)) { | |||
return false; | |||
} | |||
if (Float.floatToIntBits(rgbReplacementBlue) | |||
!= Float.floatToIntBits(other.rgbReplacementBlue)) { | |||
return false; | |||
} | |||
if (Float.floatToIntBits(rgbReplacementGreen) | |||
!= Float.floatToIntBits(other.rgbReplacementGreen)) { | |||
return false; | |||
} | |||
if (Float.floatToIntBits(rgbReplacementRed) | |||
!= Float.floatToIntBits(other.rgbReplacementRed)) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
/** | |||
* Get ICC profile name | |||
* | |||
* @return ICC profile name | |||
*/ | |||
public String getIccProfileName() { | |||
return this.iccProfileName; | |||
} | |||
/** | |||
* Get ICC profile source | |||
* | |||
* @return ICC profile source | |||
*/ | |||
public String getIccProfileSrc() { | |||
return this.iccProfileSrc; | |||
} | |||
/** | |||
* @return the original ColorSpace | |||
*/ | |||
public ColorSpace getOrigColorSpace() { | |||
//TODO this method is probably unnecessary due to super.cs and getColorSpace() | |||
return this.colorSpace; | |||
} | |||
/** | |||
* Returns the original color values. | |||
* @return the original color values | |||
*/ | |||
public float[] getOriginalColorComponents() { | |||
//TODO this method is probably unnecessary due to super.fvalue and getColorComponents() | |||
float[] copy = new float[this.colorValues.length]; | |||
System.arraycopy(this.colorValues, 0, copy, 0, copy.length); | |||
return copy; | |||
} | |||
/** | |||
* Create string representation of fop-rgb-icc function call to map this | |||
* ColorExt settings | |||
* @return the string representing the internal fop-rgb-icc() function call | |||
*/ | |||
public String toFunctionCall() { | |||
StringBuffer sb = new StringBuffer(40); | |||
sb.append("fop-rgb-icc("); | |||
sb.append(this.rgbReplacementRed + ","); | |||
sb.append(this.rgbReplacementGreen + ","); | |||
sb.append(this.rgbReplacementBlue + ","); | |||
sb.append(this.iccProfileName + ","); | |||
if (this.iccProfileSrc != null) { | |||
sb.append("\"" + this.iccProfileSrc + "\""); | |||
} | |||
float[] colorComponents = this.getColorComponents(null); | |||
for (int ix = 0; ix < colorComponents.length; ix++) { | |||
sb.append(","); | |||
sb.append(colorComponents[ix]); | |||
} | |||
sb.append(")"); | |||
return sb.toString(); | |||
} | |||
} | |||
>>>>>>> .merge-right.r1069429 |
@@ -20,7 +20,6 @@ | |||
package org.apache.fop.util; | |||
import java.awt.color.ColorSpace; | |||
import java.awt.color.ICC_ColorSpace; | |||
import java.awt.color.ICC_Profile; | |||
import java.util.Collections; | |||
import java.util.Map; | |||
@@ -33,6 +32,9 @@ import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.java2d.color.profile.ColorProfileUtil; | |||
import org.apache.xmlgraphics.java2d.color.ICCColorSpaceWithIntent; | |||
import org.apache.xmlgraphics.java2d.color.RenderingIntent; | |||
/** | |||
* Map with cached ICC based ColorSpace objects. | |||
*/ | |||
@@ -61,13 +63,17 @@ public class ColorSpaceCache { | |||
* The FOP URI resolver is used to try and locate the ICC file. | |||
* If that fails null is returned. | |||
* | |||
* @param profileName the profile name | |||
* @param base a base URI to resolve relative URIs | |||
* @param iccProfileSrc ICC Profile source to return a ColorSpace for | |||
* @param renderingIntent overriding rendering intent | |||
* @return ICC ColorSpace object or null if ColorSpace could not be created | |||
*/ | |||
public ColorSpace get(String base, String iccProfileSrc) { | |||
public ColorSpace get(String profileName, String base, String iccProfileSrc, | |||
RenderingIntent renderingIntent) { | |||
String key = profileName + ":" + base + iccProfileSrc; | |||
ColorSpace colorSpace = null; | |||
if (!colorSpaceMap.containsKey(base + iccProfileSrc)) { | |||
if (!colorSpaceMap.containsKey(key)) { | |||
try { | |||
ICC_Profile iccProfile = null; | |||
// First attempt to use the FOP URI resolver to locate the ICC | |||
@@ -88,7 +94,8 @@ public class ColorSpaceCache { | |||
// iccProfile = ICC_Profile.getInstance(iccProfileSrc); | |||
} | |||
if (iccProfile != null) { | |||
colorSpace = new ICC_ColorSpace(iccProfile); | |||
colorSpace = new ICCColorSpaceWithIntent(iccProfile, renderingIntent, | |||
profileName, iccProfileSrc); | |||
} | |||
} catch (Exception e) { | |||
// Ignore exception - will be logged a bit further down | |||
@@ -97,14 +104,14 @@ public class ColorSpaceCache { | |||
if (colorSpace != null) { | |||
// Put in cache (not when VM resolved it as we can't control | |||
colorSpaceMap.put(base + iccProfileSrc, colorSpace); | |||
colorSpaceMap.put(key, colorSpace); | |||
} else { | |||
// TODO To avoid an excessive amount of warnings perhaps | |||
// register a null ColorMap in the colorSpaceMap | |||
log.warn("Color profile '" + iccProfileSrc + "' not found."); | |||
} | |||
} else { | |||
colorSpace = colorSpaceMap.get(base + iccProfileSrc); | |||
colorSpace = colorSpaceMap.get(key); | |||
} | |||
return colorSpace; | |||
} |
@@ -0,0 +1,85 @@ | |||
/* | |||
* 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.util; | |||
import java.awt.Color; | |||
import java.awt.color.ColorSpace; | |||
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; | |||
/** | |||
* This class is a {@link Color} subclass adding a fallback color that FOP uses to re-serialize | |||
* color specifications as textual functions. The fallback is otherwise not used in producing | |||
* output formats. | |||
*/ | |||
public class ColorWithFallback extends ColorWithAlternatives { | |||
private static final long serialVersionUID = 7913922854959637136L; | |||
private final Color fallback; | |||
/** | |||
* Creates a new color | |||
* @param cspace the color space of the primary color | |||
* @param components the color components | |||
* @param alpha the alpha component | |||
* @param alternativeColors the array of alternative colors if applicable (may be null) | |||
* @param fallback the fallback color (usually an sRGB color) | |||
*/ | |||
public ColorWithFallback(ColorSpace cspace, float[] components, float alpha, | |||
Color[] alternativeColors, Color fallback) { | |||
super(cspace, components, alpha, alternativeColors); | |||
this.fallback = fallback; | |||
} | |||
/** | |||
* Copy constructor adding a fallback color. | |||
* @param color the color to be duplicated | |||
* @param fallback the fallback color (usually an sRGB color) | |||
*/ | |||
public ColorWithFallback(Color color, Color fallback) { | |||
this(color.getColorSpace(), color.getColorComponents(null), | |||
getAlphaFloat(color), getAlternativeColors(color), fallback); | |||
} | |||
private static float getAlphaFloat(Color color) { | |||
float[] comps = color.getComponents(null); | |||
return comps[comps.length - 1]; //Alpha is on last component | |||
} | |||
private static Color[] getAlternativeColors(Color color) { | |||
if (color instanceof ColorWithAlternatives) { | |||
ColorWithAlternatives cwa = (ColorWithAlternatives)color; | |||
if (cwa.hasAlternativeColors()) { | |||
return cwa.getAlternativeColors(); | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* Returns the fallback color. | |||
* @return the fallback color | |||
*/ | |||
public Color getFallbackColor() { | |||
return this.fallback; | |||
} | |||
} |
@@ -59,6 +59,12 @@ | |||
documents. Example: the fix of marks layering will be such a case when it's done. | |||
--> | |||
<release version="FOP Trunk" date="TBD"> | |||
<action context="Renderers" dev="JM" type="add"> | |||
Added support for CIE Lab colors (from XSL-FO 2.0 WD). | |||
</action> | |||
<action context="Renderers" dev="JM" type="add" fixes-bug="49403" due-to="Patrick Jaromin"> | |||
Initial work on spot colors (aka named colors) for PDF output. | |||
</action> | |||
<action context="Renderers" dev="JM" type="fix" fixes-bug="50705" due-to="Mehdi Houshmand"> | |||
Fix to preserve the order of AFP TLEs and NOPs as given in the XSL-FO document. | |||
</action> |
@@ -23,11 +23,10 @@ import java.awt.Color; | |||
import junit.framework.TestCase; | |||
import org.apache.xmlgraphics.java2d.color.ColorSpaces; | |||
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; | |||
import org.apache.xmlgraphics.java2d.color.DeviceCMYKColorSpace; | |||
import org.apache.fop.fo.Constants; | |||
import org.apache.fop.util.ColorExt; | |||
import org.apache.fop.util.ColorUtil; | |||
/** | |||
@@ -51,10 +50,10 @@ public class BorderPropsTestCase extends TestCase { | |||
assertEquals(b1, b2); | |||
float[] cmyk = new float[] {1.0f, 1.0f, 0.5f, 1.0f}; | |||
DeviceCMYKColorSpace cmykCs = ColorSpaces.getDeviceCMYKColorSpace(); | |||
float[] rgb = cmykCs.toRGB(cmyk); | |||
col = ColorExt.createFromFoRgbIcc(rgb[0], rgb[1], rgb[2], | |||
"#CMYK", null, cmykCs, cmyk); | |||
col = DeviceCMYKColorSpace.createCMYKColor(cmyk); | |||
//Convert to sRGB with CMYK alternative as constructed by the cmyk() function | |||
float[] rgb = col.getRGBColorComponents(null); | |||
col = new ColorWithAlternatives(rgb[0], rgb[1], rgb[2], new Color[] {col}); | |||
b1 = new BorderProps(Constants.EN_INSET, 9999, | |||
col, BorderProps.SEPARATE); | |||
ser = b1.toString(); |
@@ -21,10 +21,14 @@ package org.apache.fop.util; | |||
import java.awt.Color; | |||
import java.awt.color.ColorSpace; | |||
import java.net.URI; | |||
import junit.framework.TestCase; | |||
import org.apache.xmlgraphics.java2d.color.ColorSpaces; | |||
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; | |||
import org.apache.xmlgraphics.java2d.color.NamedColorSpace; | |||
import org.apache.xmlgraphics.java2d.color.RenderingIntent; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.FopFactory; | |||
@@ -79,11 +83,14 @@ public class ColorUtilTestCase extends TestCase { | |||
assertEquals(col1, col2); | |||
col1 = ColorUtil.parseColorString(null, "fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.0,0.0,0.0,0.5)"); | |||
/* The following doesn't work since java.awt.Color from Sun doesn't round consistently | |||
col2 = ColorUtil.parseColorString(null, "cmyk(0.0,0.0,0.0,0.5)"); | |||
assertEquals(col1, col2); | |||
*/ | |||
col2 = ColorUtil.parseColorString(null, "fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.5,0.5,0.5,0.0)"); | |||
assertFalse(col1.equals(col2)); | |||
assertTrue(col1.equals(col2)); | |||
assertFalse(org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor(col1, col2)); | |||
} | |||
/** | |||
@@ -109,31 +116,39 @@ public class ColorUtilTestCase extends TestCase { | |||
*/ | |||
public void testRGBICC() throws Exception { | |||
FopFactory fopFactory = FopFactory.newInstance(); | |||
ColorSpace cs = fopFactory.getColorSpace(null, | |||
"src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm"); | |||
assertNotNull(cs); | |||
URI sRGBLoc = new URI( | |||
"file:src/java/org/apache/fop/pdf/sRGB%20Color%20Space%20Profile.icm"); | |||
ColorSpace cs = fopFactory.getColorSpaceCache().get( | |||
"sRGBAlt", null, sRGBLoc.toASCIIString(), RenderingIntent.AUTO); | |||
assertNotNull("Color profile not found", cs); | |||
FOUserAgent ua = fopFactory.newFOUserAgent(); | |||
ColorExt colActual; | |||
ColorWithFallback colActual; | |||
//fop-rgb-icc() is used instead of rgb-icc() inside FOP! | |||
String colSpec = "fop-rgb-icc(1.0,0.0,0.0,sRGBAlt," | |||
+ "\"src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm\",1.0,0.0,0.0)"; | |||
colActual = (ColorExt)ColorUtil.parseColorString(ua, colSpec); | |||
//assertEquals(255, colActual.getRed()); //253 is returned | |||
//assertEquals(24, colActual.getGreen()); //24 is returned | |||
+ "\"" + sRGBLoc.toASCIIString() + "\",1.0,0.0,0.0)"; | |||
colActual = (ColorWithFallback)ColorUtil.parseColorString(ua, colSpec); | |||
assertEquals(cs, colActual.getColorSpace()); | |||
assertEquals(255, colActual.getRed(), 2f); //Java 5: 253, Java 6: 255 | |||
assertEquals(0, colActual.getGreen(), 25f); //Java 5: 25, Java 6: 0 | |||
assertEquals(0, colActual.getBlue()); | |||
//I don't understand the difference. Maybe Java's sRGB and HP's sRGB are somehow not | |||
//equivalent. This is only going to be a problem if anyone actually makes use of the | |||
//RGB fallback in any renderer. | |||
//TODO Anyone know what's going on here? | |||
assertEquals(0, colActual.getBlue()); | |||
assertEquals(cs, colActual.getColorSpace()); | |||
float[] comps = colActual.getColorComponents(null); | |||
assertEquals(3, comps.length); | |||
assertEquals(1f, comps[0], 0); | |||
assertEquals(0f, comps[1], 0); | |||
assertEquals(0f, comps[2], 0); | |||
assertEquals(0, colActual.getAlternativeColors().length); | |||
Color fallback = colActual.getFallbackColor(); | |||
assertTrue(fallback.getColorSpace().isCS_sRGB()); | |||
assertEquals(255, fallback.getRed()); | |||
assertEquals(0, fallback.getGreen()); | |||
assertEquals(0, fallback.getBlue()); | |||
assertEquals(colSpec, ColorUtil.colorToString(colActual)); | |||
@@ -148,16 +163,17 @@ public class ColorUtilTestCase extends TestCase { | |||
* @throws Exception if an error occurs | |||
*/ | |||
public void testCMYK() throws Exception { | |||
ColorExt colActual; | |||
ColorWithAlternatives colActual; | |||
String colSpec; | |||
colSpec = "cmyk(0.0, 0.0, 1.0, 0.0)"; | |||
colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec); | |||
colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec); | |||
assertEquals(255, colActual.getRed()); | |||
assertEquals(255, colActual.getGreen()); | |||
assertEquals(0, colActual.getBlue()); | |||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), colActual.getColorSpace()); | |||
float[] comps = colActual.getColorComponents(null); | |||
Color alt = colActual.getAlternativeColors()[0]; | |||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace()); | |||
float[] comps = alt.getColorComponents(null); | |||
assertEquals(4, comps.length); | |||
assertEquals(0f, comps[0], 0); | |||
assertEquals(0f, comps[1], 0); | |||
@@ -167,12 +183,13 @@ public class ColorUtilTestCase extends TestCase { | |||
ColorUtil.colorToString(colActual)); | |||
colSpec = "cmyk(0.0274, 0.2196, 0.3216, 0.0)"; | |||
colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec); | |||
assertEquals(248, colActual.getRed()); | |||
assertEquals(199, colActual.getGreen()); | |||
assertEquals(172, colActual.getBlue()); | |||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), colActual.getColorSpace()); | |||
comps = colActual.getColorComponents(null); | |||
colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec); | |||
assertEquals(248, colActual.getRed(), 1); | |||
assertEquals(199, colActual.getGreen(), 1); | |||
assertEquals(172, colActual.getBlue(), 1); | |||
alt = colActual.getAlternativeColors()[0]; | |||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace()); | |||
comps = alt.getColorComponents(null); | |||
assertEquals(0.0274f, comps[0], 0.001); | |||
assertEquals(0.2196f, comps[1], 0.001); | |||
assertEquals(0.3216f, comps[2], 0.001); | |||
@@ -181,12 +198,13 @@ public class ColorUtilTestCase extends TestCase { | |||
ColorUtil.colorToString(colActual)); | |||
colSpec = "fop-rgb-icc(1.0,1.0,0.0,#CMYK,,0.0,0.0,1.0,0.0)"; | |||
colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec); | |||
colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec); | |||
assertEquals(255, colActual.getRed()); | |||
assertEquals(255, colActual.getGreen()); | |||
assertEquals(0, colActual.getBlue()); | |||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), colActual.getColorSpace()); | |||
comps = colActual.getColorComponents(null); | |||
alt = colActual.getAlternativeColors()[0]; | |||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace()); | |||
comps = alt.getColorComponents(null); | |||
assertEquals(4, comps.length); | |||
assertEquals(0f, comps[0], 0); | |||
assertEquals(0f, comps[1], 0); | |||
@@ -196,12 +214,13 @@ public class ColorUtilTestCase extends TestCase { | |||
ColorUtil.colorToString(colActual)); | |||
colSpec = "fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.0,0.0,0.0,0.5)"; | |||
colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec); | |||
assertEquals(127, colActual.getRed()); | |||
assertEquals(127, colActual.getGreen()); | |||
assertEquals(127, colActual.getBlue()); | |||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), colActual.getColorSpace()); | |||
comps = colActual.getColorComponents(null); | |||
colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec); | |||
assertEquals(127, colActual.getRed(), 1); | |||
assertEquals(127, colActual.getGreen(), 1); | |||
assertEquals(127, colActual.getBlue(), 1); | |||
alt = colActual.getAlternativeColors()[0]; | |||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace()); | |||
comps = alt.getColorComponents(null); | |||
assertEquals(4, comps.length); | |||
assertEquals(0f, comps[0], 0); | |||
assertEquals(0f, comps[1], 0); | |||
@@ -209,6 +228,97 @@ public class ColorUtilTestCase extends TestCase { | |||
assertEquals(0.5f, comps[3], 0); | |||
assertEquals("fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.0,0.0,0.0,0.5)", | |||
ColorUtil.colorToString(colActual)); | |||
//Verify that the cmyk() and fop-rgb-icc(#CMYK) functions have the same results | |||
ColorWithAlternatives colCMYK = (ColorWithAlternatives)ColorUtil.parseColorString( | |||
null, "cmyk(0,0,0,0.5)"); | |||
assertEquals(colCMYK.getAlternativeColors()[0], colActual.getAlternativeColors()[0]); | |||
//The following doesn't work: | |||
//assertEquals(colCMYK, colActual); | |||
//java.awt.Color does not consistenly calculate the int RGB values: | |||
//Color(ColorSpace cspace, float components[], float alpha): 0.5 --> 127 | |||
//Color(float r, float g, float b): 0.5 --> 128 | |||
if (!colCMYK.equals(colActual)) { | |||
System.out.println("Info: java.awt.Color does not consistently calculate" | |||
+ " int RGB values from float RGB values."); | |||
} | |||
} | |||
/** | |||
* Tests color for the #Separation pseudo-colorspace. | |||
* @throws Exception if an error occurs | |||
*/ | |||
public void testSeparationColor() throws Exception { | |||
ColorWithFallback colActual; | |||
String colSpec; | |||
colSpec = "fop-rgb-icc(1.0,0.8,0.0,#Separation,,Postgelb)"; | |||
colActual = (ColorWithFallback)ColorUtil.parseColorString(null, colSpec); | |||
assertEquals(255, colActual.getRed(), 5); | |||
assertEquals(204, colActual.getGreen(), 3); | |||
assertEquals(0, colActual.getBlue(), 12); | |||
//sRGB results differ between JDKs | |||
Color fallback = colActual.getFallbackColor(); | |||
assertEquals(255, fallback.getRed()); | |||
assertEquals(204, fallback.getGreen()); | |||
assertEquals(0, fallback.getBlue()); | |||
assertFalse(colActual.hasAlternativeColors()); | |||
assertTrue(colActual.getColorSpace() instanceof NamedColorSpace); | |||
NamedColorSpace ncs; | |||
ncs = (NamedColorSpace)colActual.getColorSpace(); | |||
assertEquals("Postgelb", ncs.getColorName()); | |||
float[] comps = colActual.getColorComponents(null); | |||
assertEquals(1, comps.length); | |||
assertEquals(1f, comps[0], 0); | |||
assertEquals(colSpec, ColorUtil.colorToString(colActual)); | |||
} | |||
/** | |||
* Tests the fop-rgb-named-color() function. | |||
* @throws Exception if an error occurs | |||
*/ | |||
public void testNamedColorProfile() throws Exception { | |||
FopFactory fopFactory = FopFactory.newInstance(); | |||
URI ncpLoc = new URI("file:test/resources/color/ncp-example.icc"); | |||
ColorSpace cs = fopFactory.getColorSpaceCache().get( | |||
"NCP", null, ncpLoc.toASCIIString(), RenderingIntent.AUTO); | |||
assertNotNull("Color profile not found", cs); | |||
FOUserAgent ua = fopFactory.newFOUserAgent(); | |||
ColorWithFallback colActual; | |||
//fop-rgb-named-color() is used instead of rgb-named-color() inside FOP! | |||
String colSpec = "fop-rgb-named-color(1.0,0.8,0.0,NCP," | |||
+ "\"" + ncpLoc.toASCIIString() + "\",Postgelb)"; | |||
colActual = (ColorWithFallback)ColorUtil.parseColorString(ua, colSpec); | |||
assertEquals(255, colActual.getRed(), 2); | |||
assertEquals(193, colActual.getGreen(), 2); | |||
assertEquals(0, colActual.getBlue()); | |||
Color fallback = colActual.getFallbackColor(); | |||
assertEquals(255, fallback.getRed()); | |||
assertEquals(204, fallback.getGreen()); | |||
assertEquals(0, fallback.getBlue()); | |||
assertEquals(ColorSpace.getInstance(ColorSpace.CS_sRGB), fallback.getColorSpace()); | |||
float[] comps = fallback.getColorComponents(null); | |||
assertEquals(3, comps.length); | |||
assertEquals(1f, comps[0], 0); | |||
assertEquals(0.8f, comps[1], 0); | |||
assertEquals(0f, comps[2], 0); | |||
assertTrue(colActual.getColorSpace() instanceof NamedColorSpace); | |||
NamedColorSpace ncs; | |||
ncs = (NamedColorSpace)colActual.getColorSpace(); | |||
assertEquals("Postgelb", ncs.getColorName()); | |||
comps = colActual.getColorComponents(null); | |||
assertEquals(1, comps.length); | |||
assertEquals(1f, comps[0], 0); | |||
assertEquals(colSpec, ColorUtil.colorToString(colActual)); | |||
} | |||
} |