aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2011-02-10 15:58:57 +0000
committerJeremias Maerki <jeremias@apache.org>2011-02-10 15:58:57 +0000
commit3df0d00cdc96c2283046fe200f85d12bb85687c3 (patch)
tree62f91c73633d70b31ef9f1e32598225a2f37d8aa /src/java/org/apache/fop
parentf1269cc280b846cd6da396177bc74c4c9808579e (diff)
parent1c11bf98135675a9d6b6acac4fd7856a5dde8751 (diff)
downloadxmlgraphics-fop-3df0d00cdc96c2283046fe200f85d12bb85687c3.tar.gz
xmlgraphics-fop-3df0d00cdc96c2283046fe200f85d12bb85687c3.zip
Re-integrate/merge Temp_Color branch into Trunk.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1069439 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop')
-rw-r--r--src/java/org/apache/fop/afp/goca/GraphicsSetProcessColor.java90
-rw-r--r--src/java/org/apache/fop/afp/modca/GraphicsObject.java9
-rw-r--r--src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java34
-rw-r--r--src/java/org/apache/fop/apps/FopFactory.java36
-rw-r--r--src/java/org/apache/fop/fo/expr/CIELabColorFunction.java94
-rw-r--r--src/java/org/apache/fop/fo/expr/NamedColorFunction.java112
-rw-r--r--src/java/org/apache/fop/fo/expr/PropertyParser.java2
-rw-r--r--src/java/org/apache/fop/fo/expr/PropertyTokenizer.java5
-rw-r--r--src/java/org/apache/fop/fo/properties/ColorProperty.java9
-rw-r--r--src/java/org/apache/fop/pdf/PDFCIELabColorSpace.java91
-rw-r--r--src/java/org/apache/fop/pdf/PDFColor.java103
-rw-r--r--src/java/org/apache/fop/pdf/PDFColorHandler.java231
-rw-r--r--src/java/org/apache/fop/pdf/PDFDeviceColorSpace.java26
-rw-r--r--src/java/org/apache/fop/pdf/PDFDocument.java16
-rw-r--r--src/java/org/apache/fop/pdf/PDFFactory.java73
-rw-r--r--src/java/org/apache/fop/pdf/PDFName.java23
-rw-r--r--src/java/org/apache/fop/pdf/PDFPaintingState.java20
-rw-r--r--src/java/org/apache/fop/pdf/PDFResources.java117
-rw-r--r--src/java/org/apache/fop/pdf/PDFSeparationColorSpace.java88
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFSerializer.java15
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFState.java4
-rw-r--r--src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java15
-rw-r--r--src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java4
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFContentGenerator.java13
-rw-r--r--src/java/org/apache/fop/render/xml/XMLRenderer.java36
-rw-r--r--src/java/org/apache/fop/svg/PDFBridgeContext.java15
-rw-r--r--src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java17
-rw-r--r--src/java/org/apache/fop/svg/PDFGraphics2D.java62
-rw-r--r--src/java/org/apache/fop/traits/BorderProps.java6
-rw-r--r--src/java/org/apache/fop/util/AbstractPaintingState.java10
-rw-r--r--src/java/org/apache/fop/util/ColorExt.java259
-rw-r--r--src/java/org/apache/fop/util/ColorSpaceCache.java19
-rw-r--r--src/java/org/apache/fop/util/ColorUtil.java840
-rw-r--r--src/java/org/apache/fop/util/ColorWithFallback.java85
34 files changed, 1993 insertions, 586 deletions
diff --git a/src/java/org/apache/fop/afp/goca/GraphicsSetProcessColor.java b/src/java/org/apache/fop/afp/goca/GraphicsSetProcessColor.java
index aba02f76c..07d6c78af 100644
--- a/src/java/org/apache/fop/afp/goca/GraphicsSetProcessColor.java
+++ b/src/java/org/apache/fop/afp/goca/GraphicsSetProcessColor.java
@@ -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 + ")";
}
diff --git a/src/java/org/apache/fop/afp/modca/GraphicsObject.java b/src/java/org/apache/fop/afp/modca/GraphicsObject.java
index 0c3781be1..c94ad5ffc 100644
--- a/src/java/org/apache/fop/afp/modca/GraphicsObject.java
+++ b/src/java/org/apache/fop/afp/modca/GraphicsObject.java
@@ -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);
diff --git a/src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java b/src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
index e583b81e6..2962dc76c 100644
--- a/src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
+++ b/src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
@@ -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
diff --git a/src/java/org/apache/fop/apps/FopFactory.java b/src/java/org/apache/fop/apps/FopFactory.java
index 181bc85da..2aca8bf99 100644
--- a/src/java/org/apache/fop/apps/FopFactory.java
+++ b/src/java/org/apache/fop/apps/FopFactory.java
@@ -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;
}
}
diff --git a/src/java/org/apache/fop/fo/expr/CIELabColorFunction.java b/src/java/org/apache/fop/fo/expr/CIELabColorFunction.java
new file mode 100644
index 000000000..d027a9571
--- /dev/null
+++ b/src/java/org/apache/fop/fo/expr/CIELabColorFunction.java
@@ -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;
+ }
+
+ }
+
+}
diff --git a/src/java/org/apache/fop/fo/expr/NamedColorFunction.java b/src/java/org/apache/fop/fo/expr/NamedColorFunction.java
new file mode 100644
index 000000000..2bceec8dc
--- /dev/null
+++ b/src/java/org/apache/fop/fo/expr/NamedColorFunction.java
@@ -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;
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/fo/expr/PropertyParser.java b/src/java/org/apache/fop/fo/expr/PropertyParser.java
index 87f640651..9ef45befe 100644
--- a/src/java/org/apache/fop/fo/expr/PropertyParser.java
+++ b/src/java/org/apache/fop/fo/expr/PropertyParser.java
@@ -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!!!
/**
diff --git a/src/java/org/apache/fop/fo/expr/PropertyTokenizer.java b/src/java/org/apache/fop/fo/expr/PropertyTokenizer.java
index 3008dbebe..89a387753 100644
--- a/src/java/org/apache/fop/fo/expr/PropertyTokenizer.java
+++ b/src/java/org/apache/fop/fo/expr/PropertyTokenizer.java
@@ -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;
}
diff --git a/src/java/org/apache/fop/fo/properties/ColorProperty.java b/src/java/org/apache/fop/fo/properties/ColorProperty.java
index 293f31577..0550ce684 100644
--- a/src/java/org/apache/fop/fo/properties/ColorProperty.java
+++ b/src/java/org/apache/fop/fo/properties/ColorProperty.java
@@ -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();
}
diff --git a/src/java/org/apache/fop/pdf/PDFCIELabColorSpace.java b/src/java/org/apache/fop/pdf/PDFCIELabColorSpace.java
new file mode 100644
index 000000000..4d1d7f7ff
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFCIELabColorSpace.java
@@ -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;
+ }
+
+}
diff --git a/src/java/org/apache/fop/pdf/PDFColor.java b/src/java/org/apache/fop/pdf/PDFColor.java
index 2dc1da1ea..781012cfa 100644
--- a/src/java/org/apache/fop/pdf/PDFColor.java
+++ b/src/java/org/apache/fop/pdf/PDFColor.java
@@ -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
@@ -69,81 +62,27 @@ public class PDFColor extends PDFPathPaint {
}
/**
- * 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
diff --git a/src/java/org/apache/fop/pdf/PDFColorHandler.java b/src/java/org/apache/fop/pdf/PDFColorHandler.java
new file mode 100644
index 000000000..76a6cab78
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFColorHandler.java
@@ -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");
+ }
+
+}
diff --git a/src/java/org/apache/fop/pdf/PDFDeviceColorSpace.java b/src/java/org/apache/fop/pdf/PDFDeviceColorSpace.java
index 6ccfd39f5..b18c3ac9e 100644
--- a/src/java/org/apache/fop/pdf/PDFDeviceColorSpace.java
+++ b/src/java/org/apache/fop/pdf/PDFDeviceColorSpace.java
@@ -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;
+ }
+
}
diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java
index a17c8c4df..9268ae921 100644
--- a/src/java/org/apache/fop/pdf/PDFDocument.java
+++ b/src/java/org/apache/fop/pdf/PDFDocument.java
@@ -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;
diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java
index 752d14207..23542a49e 100644
--- a/src/java/org/apache/fop/pdf/PDFFactory.java
+++ b/src/java/org/apache/fop/pdf/PDFFactory.java
@@ -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 ============ */
/**
@@ -1782,6 +1795,38 @@ public class PDFFactory {
}
/**
+ * 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).
*
* @param values the int array values
diff --git a/src/java/org/apache/fop/pdf/PDFName.java b/src/java/org/apache/fop/pdf/PDFName.java
index 3f9af7669..e40a12f13 100644
--- a/src/java/org/apache/fop/pdf/PDFName.java
+++ b/src/java/org/apache/fop/pdf/PDFName.java
@@ -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);
diff --git a/src/java/org/apache/fop/pdf/PDFPaintingState.java b/src/java/org/apache/fop/pdf/PDFPaintingState.java
index ebe2b383b..29d022f61 100644
--- a/src/java/org/apache/fop/pdf/PDFPaintingState.java
+++ b/src/java/org/apache/fop/pdf/PDFPaintingState.java
@@ -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();
}
diff --git a/src/java/org/apache/fop/pdf/PDFResources.java b/src/java/org/apache/fop/pdf/PDFResources.java
index 99a42433c..317f703e1 100644
--- a/src/java/org/apache/fop/pdf/PDFResources.java
+++ b/src/java/org/apache/fop/pdf/PDFResources.java
@@ -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();
}
}
diff --git a/src/java/org/apache/fop/pdf/PDFSeparationColorSpace.java b/src/java/org/apache/fop/pdf/PDFSeparationColorSpace.java
new file mode 100644
index 000000000..d364eccbc
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFSeparationColorSpace.java
@@ -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;
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java
index edeef9766..3e178d3cb 100644
--- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java
+++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java
@@ -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));
diff --git a/src/java/org/apache/fop/render/intermediate/IFState.java b/src/java/org/apache/fop/render/intermediate/IFState.java
index c13382192..4d8325d3e 100644
--- a/src/java/org/apache/fop/render/intermediate/IFState.java
+++ b/src/java/org/apache/fop/render/intermediate/IFState.java
@@ -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;
diff --git a/src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java b/src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java
index a40ee1d5c..b0c003b91 100644
--- a/src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java
+++ b/src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java
@@ -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: "
diff --git a/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java b/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java
index 9e20886e0..d076e6ab9 100644
--- a/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java
+++ b/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java
@@ -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
diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
index 074faa5d3..7cc9b7003 100644
--- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
+++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
@@ -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);
}
diff --git a/src/java/org/apache/fop/render/xml/XMLRenderer.java b/src/java/org/apache/fop/render/xml/XMLRenderer.java
index c283dbd98..85995e8b2 100644
--- a/src/java/org/apache/fop/render/xml/XMLRenderer.java
+++ b/src/java/org/apache/fop/render/xml/XMLRenderer.java
@@ -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);
diff --git a/src/java/org/apache/fop/svg/PDFBridgeContext.java b/src/java/org/apache/fop/svg/PDFBridgeContext.java
index a38465ed4..4a6e6e275 100644
--- a/src/java/org/apache/fop/svg/PDFBridgeContext.java
+++ b/src/java/org/apache/fop/svg/PDFBridgeContext.java
@@ -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(),
diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java
index db1d9e2de..829d8972d 100644
--- a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java
+++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java
@@ -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());
}
/**
diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java
index 7c8d4a6b9..e93914258 100644
--- a/src/java/org/apache/fop/svg/PDFGraphics2D.java
+++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java
@@ -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();
diff --git a/src/java/org/apache/fop/traits/BorderProps.java b/src/java/org/apache/fop/traits/BorderProps.java
index a76c6e8a3..ae7a9a434 100644
--- a/src/java/org/apache/fop/traits/BorderProps.java
+++ b/src/java/org/apache/fop/traits/BorderProps.java
@@ -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('(');
diff --git a/src/java/org/apache/fop/util/AbstractPaintingState.java b/src/java/org/apache/fop/util/AbstractPaintingState.java
index 5944b546c..96c3633e6 100644
--- a/src/java/org/apache/fop/util/AbstractPaintingState.java
+++ b/src/java/org/apache/fop/util/AbstractPaintingState.java
@@ -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
diff --git a/src/java/org/apache/fop/util/ColorExt.java b/src/java/org/apache/fop/util/ColorExt.java
index 30f6e9fc3..9d4c9b9d3 100644
--- a/src/java/org/apache/fop/util/ColorExt.java
+++ b/src/java/org/apache/fop/util/ColorExt.java
@@ -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
diff --git a/src/java/org/apache/fop/util/ColorSpaceCache.java b/src/java/org/apache/fop/util/ColorSpaceCache.java
index 63d8746f7..63db937a0 100644
--- a/src/java/org/apache/fop/util/ColorSpaceCache.java
+++ b/src/java/org/apache/fop/util/ColorSpaceCache.java
@@ -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;
}
diff --git a/src/java/org/apache/fop/util/ColorUtil.java b/src/java/org/apache/fop/util/ColorUtil.java
index 674079369..e1454a545 100644
--- a/src/java/org/apache/fop/util/ColorUtil.java
+++ b/src/java/org/apache/fop/util/ColorUtil.java
@@ -21,14 +21,23 @@ package org.apache.fop.util;
import java.awt.Color;
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;
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.ColorSpaceOrigin;
import org.apache.xmlgraphics.java2d.color.ColorSpaces;
+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.RenderingIntent;
+import org.apache.xmlgraphics.java2d.color.profile.NamedColorProfile;
+import org.apache.xmlgraphics.java2d.color.profile.NamedColorProfileParser;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.expr.PropertyException;
@@ -41,15 +50,22 @@ import org.apache.fop.fo.expr.PropertyException;
*/
public final class ColorUtil {
+ //ColorWithFallback is used to preserve the sRGB fallback exclusively for the purpose
+ //of regenerating textual color functions as specified in XSL-FO.
+
/** The name for the uncalibrated CMYK pseudo-profile */
public static final String CMYK_PSEUDO_PROFILE = "#CMYK";
+ /** The name for the Separation pseudo-profile used for spot colors */
+ public static final String SEPARATION_PSEUDO_PROFILE = "#Separation";
+
/**
- *
- * keeps all the predefined and parsed colors.
+ * Keeps all the predefined and parsed colors.
* <p>
* This map is used to predefine given colors, as well as speeding up
* parsing of already parsed colors.
+ * <p>
+ * Important: The use of this color map assumes that all Color instances are immutable!
*/
private static Map<String, Color> colorMap = null;
@@ -98,7 +114,7 @@ public final class ColorUtil {
return null;
}
- Color parsedColor = (Color) colorMap.get(value.toLowerCase());
+ Color parsedColor = colorMap.get(value.toLowerCase());
if (parsedColor == null) {
if (value.startsWith("#")) {
@@ -114,6 +130,10 @@ public final class ColorUtil {
parsedColor = parseAsSystemColor(value);
} else if (value.startsWith("fop-rgb-icc")) {
parsedColor = parseAsFopRgbIcc(foUserAgent, value);
+ } else if (value.startsWith("fop-rgb-named-color")) {
+ parsedColor = parseAsFopRgbNamedColor(foUserAgent, value);
+ } else if (value.startsWith("cie-lab-color")) {
+ parsedColor = parseAsCIELabColor(foUserAgent, value);
} else if (value.startsWith("cmyk")) {
parsedColor = parseAsCMYK(value);
}
@@ -125,9 +145,6 @@ public final class ColorUtil {
colorMap.put(value, parsedColor);
}
- // TODO - Returned Color object can be one from the static colorMap cache.
- // That means it should be treated as read only for the rest of its lifetime.
- // Not sure that is the case though.
return parsedColor;
}
@@ -150,7 +167,7 @@ public final class ColorUtil {
throw new PropertyException("Unknown color format: " + value
+ ". Must be system-color(x)");
}
- return (Color) colorMap.get(value);
+ return colorMap.get(value);
}
/**
@@ -218,34 +235,14 @@ public final class ColorUtil {
throw new PropertyException(
"Invalid number of arguments: rgb(" + value + ")");
}
- float red = 0.0f, green = 0.0f, blue = 0.0f;
- String str = args[0].trim();
- if (str.endsWith("%")) {
- red = Float.parseFloat(str.substring(0,
- str.length() - 1)) / 100f;
- } else {
- red = Float.parseFloat(str) / 255f;
- }
- str = args[1].trim();
- if (str.endsWith("%")) {
- green = Float.parseFloat(str.substring(0,
- str.length() - 1)) / 100f;
- } else {
- green = Float.parseFloat(str) / 255f;
- }
- str = args[2].trim();
- if (str.endsWith("%")) {
- blue = Float.parseFloat(str.substring(0,
- str.length() - 1)) / 100f;
- } else {
- blue = Float.parseFloat(str) / 255f;
- }
- if ((red < 0.0 || red > 1.0)
- || (green < 0.0 || green > 1.0)
- || (blue < 0.0 || blue > 1.0)) {
- throw new PropertyException("Color values out of range");
- }
- parsedColor = new Color(red, green, blue);
+ float red = parseComponent255(args[0], value);
+ float green = parseComponent255(args[1], value);
+ float blue = parseComponent255(args[2], value);
+ //Convert to ints to synchronize the behaviour with toRGBFunctionCall()
+ int r = (int)(red * 255 + 0.5);
+ int g = (int)(green * 255 + 0.5);
+ int b = (int)(blue * 255 + 0.5);
+ parsedColor = new Color(r, g, b);
} catch (PropertyException pe) {
//simply re-throw
throw pe;
@@ -260,8 +257,50 @@ public final class ColorUtil {
return parsedColor;
}
+ private static float parseComponent255(String str, String function)
+ throws PropertyException {
+ float component;
+ str = str.trim();
+ if (str.endsWith("%")) {
+ component = Float.parseFloat(str.substring(0,
+ str.length() - 1)) / 100f;
+ } else {
+ component = Float.parseFloat(str) / 255f;
+ }
+ if ((component < 0.0 || component > 1.0)) {
+ throw new PropertyException("Color value out of range for " + function + ": "
+ + str + ". Valid range: [0..255] or [0%..100%]");
+ }
+ return component;
+ }
+
+ private static float parseComponent1(String argument, String function)
+ throws PropertyException {
+ return parseComponent(argument, 0f, 1f, function);
+ }
+
+ private static float parseComponent(String argument, float min, float max, String function)
+ throws PropertyException {
+ float component = Float.parseFloat(argument.trim());
+ if ((component < min || component > max)) {
+ throw new PropertyException("Color value out of range for " + function + ": "
+ + argument + ". Valid range: [" + min + ".." + max + "]");
+ }
+ return component;
+ }
+
+ private static Color parseFallback(String[] args, String value) throws PropertyException {
+ float red = parseComponent1(args[0], value);
+ float green = parseComponent1(args[1], value);
+ float blue = parseComponent1(args[2], value);
+ //Sun's classlib rounds differently with this constructor than when converting to sRGB
+ //via CIE XYZ.
+ Color sRGB = new Color(red, green, blue);
+ return sRGB;
+ }
+
/**
- * parse a color given in the #.... format.
+ * Parse a color given in the #.... format.
*
* @param value
* the complete line
@@ -320,6 +359,10 @@ public final class ColorUtil {
if (args.length < 5) {
throw new PropertyException("Too few arguments for rgb-icc() function");
}
+
+ //Set up fallback sRGB value
+ Color sRGB = parseFallback(args, value);
+
/* Get and verify ICC profile name */
String iccProfileName = args[3].trim();
if (iccProfileName == null || "".equals(iccProfileName)) {
@@ -330,6 +373,9 @@ public final class ColorUtil {
if (isPseudoProfile(iccProfileName)) {
if (CMYK_PSEUDO_PROFILE.equalsIgnoreCase(iccProfileName)) {
colorSpace = ColorSpaces.getDeviceCMYKColorSpace();
+ } else if (SEPARATION_PSEUDO_PROFILE.equalsIgnoreCase(iccProfileName)) {
+ colorSpace = new NamedColorSpace(args[5], sRGB,
+ SEPARATION_PSEUDO_PROFILE, null);
} else {
assert false : "Incomplete implementation";
}
@@ -339,47 +385,51 @@ public final class ColorUtil {
if (iccProfileSrc == null || "".equals(iccProfileSrc)) {
throw new PropertyException("ICC profile source missing");
}
- if (iccProfileSrc.startsWith("\"") || iccProfileSrc.startsWith("'")) {
- iccProfileSrc = iccProfileSrc.substring(1);
- }
- if (iccProfileSrc.endsWith("\"") || iccProfileSrc.endsWith("'")) {
- iccProfileSrc = iccProfileSrc.substring(0, iccProfileSrc.length() - 1);
- }
+ iccProfileSrc = unescapeString(iccProfileSrc);
}
/* ICC profile arguments */
- float[] iccComponents = new float[args.length - 5];
- for (int ix = 4; ++ix < args.length;) {
- iccComponents[ix - 5] = Float.parseFloat(args[ix].trim());
+ int componentStart = 4;
+ if (colorSpace instanceof NamedColorSpace) {
+ componentStart++;
}
-
- float red = 0, green = 0, blue = 0;
- red = Float.parseFloat(args[0].trim());
- green = Float.parseFloat(args[1].trim());
- blue = Float.parseFloat(args[2].trim());
- /* Verify rgb replacement arguments */
- if ((red < 0 || red > 1)
- || (green < 0 || green > 1)
- || (blue < 0 || blue > 1)) {
- throw new PropertyException("Color values out of range. "
- + "Fallback RGB arguments to fop-rgb-icc() must be [0..1]");
+ float[] iccComponents = new float[args.length - componentStart - 1];
+ for (int ix = componentStart; ++ix < args.length;) {
+ iccComponents[ix - componentStart - 1] = Float.parseFloat(args[ix].trim());
+ }
+ if (colorSpace instanceof NamedColorSpace && iccComponents.length == 0) {
+ iccComponents = new float[] {1.0f}; //full tint if not specified
}
/* Ask FOP factory to get ColorSpace for the specified ICC profile source */
if (foUserAgent != null && iccProfileSrc != null) {
- colorSpace = foUserAgent.getFactory().getColorSpace(
- foUserAgent.getBaseURL(), iccProfileSrc);
+ assert colorSpace == null;
+ RenderingIntent renderingIntent = RenderingIntent.AUTO;
+ //TODO connect to fo:color-profile/@rendering-intent
+ colorSpace = foUserAgent.getFactory().getColorSpaceCache().get(
+ iccProfileName,
+ foUserAgent.getBaseURL(), iccProfileSrc,
+ renderingIntent);
}
if (colorSpace != null) {
- // ColorSpace available - create ColorExt (keeps track of replacement rgb
- // values for possible later colorTOsRGBString call
- parsedColor = ColorExt.createFromFoRgbIcc(red, green, blue,
- iccProfileName, iccProfileSrc, colorSpace, iccComponents);
+ // ColorSpace is available
+ if (ColorSpaces.isDeviceColorSpace(colorSpace)) {
+ //Device-specific colors are handled differently:
+ //sRGB is the primary color with the CMYK as the alternative
+ Color deviceColor = new Color(colorSpace, iccComponents, 1.0f);
+ float[] rgbComps = sRGB.getRGBColorComponents(null);
+ parsedColor = new ColorWithAlternatives(
+ rgbComps[0], rgbComps[1], rgbComps[2],
+ new Color[] {deviceColor});
+ } else {
+ Color specColor = new ColorWithFallback(
+ colorSpace, iccComponents, 1.0f, null, sRGB);
+ parsedColor = specColor;
+ }
} else {
// ICC profile could not be loaded - use rgb replacement values */
log.warn("Color profile '" + iccProfileSrc
- + "' not found. Using rgb replacement values.");
- parsedColor = new Color(Math.round(red * 255),
- Math.round(green * 255), Math.round(blue * 255));
+ + "' not found. Using sRGB replacement values.");
+ parsedColor = sRGB;
}
} catch (PropertyException pe) {
//simply re-throw
@@ -396,6 +446,161 @@ public final class ColorUtil {
}
/**
+ * Parse a color specified using the fop-rgb-named-color() function.
+ *
+ * @param value the function call
+ * @return a color if possible
+ * @throws PropertyException if the format is wrong.
+ */
+ private static Color parseAsFopRgbNamedColor(FOUserAgent foUserAgent, String value)
+ throws PropertyException {
+ Color parsedColor;
+ int poss = value.indexOf("(");
+ int pose = value.indexOf(")");
+ if (poss != -1 && pose != -1) {
+ String[] args = value.substring(poss + 1, pose).split(",");
+
+ try {
+ if (args.length != 6) {
+ throw new PropertyException("rgb-named-color() function must have 6 arguments");
+ }
+
+ //Set up fallback sRGB value
+ Color sRGB = parseFallback(args, value);
+
+ /* Get and verify ICC profile name */
+ String iccProfileName = args[3].trim();
+ if (iccProfileName == null || "".equals(iccProfileName)) {
+ throw new PropertyException("ICC profile name missing");
+ }
+ ICC_ColorSpace colorSpace = null;
+ String iccProfileSrc = null;
+ if (isPseudoProfile(iccProfileName)) {
+ throw new IllegalArgumentException(
+ "Pseudo-profiles are not allowed with fop-rgb-named-color()");
+ } else {
+ /* Get and verify ICC profile source */
+ iccProfileSrc = args[4].trim();
+ if (iccProfileSrc == null || "".equals(iccProfileSrc)) {
+ throw new PropertyException("ICC profile source missing");
+ }
+ iccProfileSrc = unescapeString(iccProfileSrc);
+ }
+
+ // color name
+ String colorName = unescapeString(args[5].trim());
+
+ /* Ask FOP factory to get ColorSpace for the specified ICC profile source */
+ if (foUserAgent != null && iccProfileSrc != null) {
+ RenderingIntent renderingIntent = RenderingIntent.AUTO;
+ //TODO connect to fo:color-profile/@rendering-intent
+ colorSpace = (ICC_ColorSpace)foUserAgent.getFactory().getColorSpaceCache().get(
+ iccProfileName,
+ foUserAgent.getBaseURL(), iccProfileSrc,
+ renderingIntent);
+ }
+ if (colorSpace != null) {
+ ICC_Profile profile = colorSpace.getProfile();
+ if (NamedColorProfileParser.isNamedColorProfile(profile)) {
+ NamedColorProfileParser parser = new NamedColorProfileParser();
+ NamedColorProfile ncp = parser.parseProfile(profile,
+ iccProfileName, iccProfileSrc);
+ NamedColorSpace ncs = ncp.getNamedColor(colorName);
+ if (ncs != null) {
+ Color specColor = new ColorWithFallback(ncs,
+ new float[] {1.0f}, 1.0f, null, sRGB);
+ parsedColor = specColor;
+ } else {
+ log.warn("Color '" + colorName
+ + "' does not exist in named color profile: " + iccProfileSrc);
+ parsedColor = sRGB;
+ }
+ } else {
+ log.warn("ICC profile is no named color profile: " + iccProfileSrc);
+ parsedColor = sRGB;
+ }
+ } else {
+ // ICC profile could not be loaded - use rgb replacement values */
+ log.warn("Color profile '" + iccProfileSrc
+ + "' not found. Using sRGB replacement values.");
+ parsedColor = sRGB;
+ }
+ } catch (PropertyException pe) {
+ //simply re-throw
+ throw pe;
+ } catch (Exception e) {
+ //wrap in a PropertyException
+ throw new PropertyException(e);
+ }
+ } else {
+ throw new PropertyException("Unknown color format: " + value
+ + ". Must be fop-rgb-named-color(r,g,b,NCNAME,src,color-name)");
+ }
+ return parsedColor;
+ }
+
+ /**
+ * Parse a color specified using the cie-lab-color() function.
+ *
+ * @param value the function call
+ * @return a color if possible
+ * @throws PropertyException if the format is wrong.
+ */
+ private static Color parseAsCIELabColor(FOUserAgent foUserAgent, String value)
+ throws PropertyException {
+ Color parsedColor;
+ int poss = value.indexOf("(");
+ int pose = value.indexOf(")");
+ if (poss != -1 && pose != -1) {
+ String[] args = value.substring(poss + 1, pose).split(",");
+
+ try {
+ if (args.length != 6) {
+ throw new PropertyException("cie-lab-color() function must have 6 arguments");
+ }
+
+ //Set up fallback sRGB value
+ float red = parseComponent255(args[0], value);
+ float green = parseComponent255(args[1], value);
+ float blue = parseComponent255(args[2], value);
+ Color sRGB = new Color(red, green, blue);
+
+ float l = parseComponent(args[3], 0f, 100f, value);
+ float a = parseComponent(args[4], -127f, 127f, value);
+ float b = parseComponent(args[5], -127f, 127f, value);
+
+ //Assuming the XSL-FO spec uses the D50 white point
+ CIELabColorSpace cs = ColorSpaces.getCIELabColorSpaceD50();
+ //use toColor() to have components normalized
+ Color labColor = cs.toColor(l, a, b, 1.0f);
+ //Convert to ColorWithFallback
+ parsedColor = new ColorWithFallback(labColor, sRGB);
+
+ } catch (PropertyException pe) {
+ //simply re-throw
+ throw pe;
+ } catch (Exception e) {
+ //wrap in a PropertyException
+ throw new PropertyException(e);
+ }
+ } else {
+ throw new PropertyException("Unknown color format: " + value
+ + ". Must be cie-lab-color(r,g,b,Lightness,a-value,b-value)");
+ }
+ return parsedColor;
+ }
+
+ private static String unescapeString(String iccProfileSrc) {
+ if (iccProfileSrc.startsWith("\"") || iccProfileSrc.startsWith("'")) {
+ iccProfileSrc = iccProfileSrc.substring(1);
+ }
+ if (iccProfileSrc.endsWith("\"") || iccProfileSrc.endsWith("'")) {
+ iccProfileSrc = iccProfileSrc.substring(0, iccProfileSrc.length() - 1);
+ }
+ return iccProfileSrc;
+ }
+
+ /**
* Parse a color given with the cmyk() function.
*
* @param value
@@ -416,48 +621,15 @@ public final class ColorUtil {
throw new PropertyException(
"Invalid number of arguments: cmyk(" + value + ")");
}
- float cyan = 0.0f, magenta = 0.0f, yellow = 0.0f, black = 0.0f;
- String str = args[0].trim();
- if (str.endsWith("%")) {
- cyan = Float.parseFloat(str.substring(0,
- str.length() - 1)) / 100.0f;
- } else {
- cyan = Float.parseFloat(str);
- }
- str = args[1].trim();
- if (str.endsWith("%")) {
- magenta = Float.parseFloat(str.substring(0,
- str.length() - 1)) / 100.0f;
- } else {
- magenta = Float.parseFloat(str);
- }
- str = args[2].trim();
- if (str.endsWith("%")) {
- yellow = Float.parseFloat(str.substring(0,
- str.length() - 1)) / 100.0f;
- } else {
- yellow = Float.parseFloat(str);
- }
- str = args[3].trim();
- if (str.endsWith("%")) {
- black = Float.parseFloat(str.substring(0,
- str.length() - 1)) / 100.0f;
- } else {
- black = Float.parseFloat(str);
- }
-
- if ((cyan < 0.0 || cyan > 1.0)
- || (magenta < 0.0 || magenta > 1.0)
- || (yellow < 0.0 || yellow > 1.0)
- || (black < 0.0 || black > 1.0)) {
- throw new PropertyException("Color values out of range"
- + "Arguments to cmyk() must be in the range [0%-100%] or [0.0-1.0]");
- }
- float[] cmyk = new float[] {cyan, magenta, yellow, black};
- DeviceCMYKColorSpace cmykCs = ColorSpaces.getDeviceCMYKColorSpace();
- float[] rgb = cmykCs.toRGB(cmyk);
- parsedColor = ColorExt.createFromFoRgbIcc(rgb[0], rgb[1], rgb[2],
- CMYK_PSEUDO_PROFILE, null, cmykCs, cmyk);
+ float cyan = parseComponent1(args[0], value);
+ float magenta = parseComponent1(args[1], value);
+ float yellow = parseComponent1(args[2], value);
+ float black = parseComponent1(args[3], value);
+ float[] comps = new float[] {cyan, magenta, yellow, black};
+ Color cmykColor = DeviceCMYKColorSpace.createCMYKColor(comps);
+ float[] rgbComps = cmykColor.getRGBColorComponents(null);
+ parsedColor = new ColorWithAlternatives(rgbComps[0], rgbComps[1], rgbComps[2],
+ new Color[] {cmykColor});
} catch (PropertyException pe) {
throw pe;
} catch (Exception e) {
@@ -482,40 +654,146 @@ public final class ColorUtil {
*/
public static String colorToString(Color color) {
ColorSpace cs = color.getColorSpace();
- if (color instanceof ColorExt) {
- return ((ColorExt)color).toFunctionCall();
+ if (color instanceof ColorWithAlternatives) {
+ return toFunctionCall((ColorWithAlternatives)color);
} else if (cs != null && cs.getType() == ColorSpace.TYPE_CMYK) {
StringBuffer sbuf = new StringBuffer(24);
float[] cmyk = color.getColorComponents(null);
sbuf.append("cmyk(" + cmyk[0] + "," + cmyk[1] + "," + cmyk[2] + "," + cmyk[3] + ")");
return sbuf.toString();
} else {
- StringBuffer sbuf = new StringBuffer();
- sbuf.append('#');
- String s = Integer.toHexString(color.getRed());
+ return toRGBFunctionCall(color);
+ }
+ }
+
+ private static String toRGBFunctionCall(Color color) {
+ StringBuffer sbuf = new StringBuffer();
+ sbuf.append('#');
+ String s = Integer.toHexString(color.getRed());
+ if (s.length() == 1) {
+ sbuf.append('0');
+ }
+ sbuf.append(s);
+ s = Integer.toHexString(color.getGreen());
+ if (s.length() == 1) {
+ sbuf.append('0');
+ }
+ sbuf.append(s);
+ s = Integer.toHexString(color.getBlue());
+ if (s.length() == 1) {
+ sbuf.append('0');
+ }
+ sbuf.append(s);
+ if (color.getAlpha() != 255) {
+ s = Integer.toHexString(color.getAlpha());
if (s.length() == 1) {
sbuf.append('0');
}
sbuf.append(s);
- s = Integer.toHexString(color.getGreen());
- if (s.length() == 1) {
- sbuf.append('0');
+ }
+ return sbuf.toString();
+ }
+
+ private static Color getsRGBFallback(ColorWithAlternatives color) {
+ Color fallbackColor;
+ if (color instanceof ColorWithFallback) {
+ fallbackColor = ((ColorWithFallback)color).getFallbackColor();
+ if (!fallbackColor.getColorSpace().isCS_sRGB()) {
+ fallbackColor = toSRGBColor(fallbackColor);
}
- sbuf.append(s);
- s = Integer.toHexString(color.getBlue());
- if (s.length() == 1) {
- sbuf.append('0');
+ } else {
+ fallbackColor = toSRGBColor(color);
+ }
+ return fallbackColor;
+ }
+
+ private static Color toSRGBColor(Color color) {
+ float[] comps;
+ ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+ comps = color.getRGBColorComponents(null);
+ float[] allComps = color.getComponents(null);
+ float alpha = allComps[allComps.length - 1]; //Alpha is on last component
+ return new Color(sRGB, comps, alpha);
+ }
+
+ /**
+ * Create string representation of a fop-rgb-icc (or fop-rgb-named-color) function call from
+ * the given color.
+ * @param color the color to turn into a function call
+ * @return the string representing the internal fop-rgb-icc() or fop-rgb-named-color()
+ * function call
+ */
+ private static String toFunctionCall(ColorWithAlternatives color) {
+ ColorSpace cs = color.getColorSpace();
+ if (cs.isCS_sRGB() && !color.hasAlternativeColors()) {
+ return toRGBFunctionCall(color);
+ }
+ if (cs instanceof CIELabColorSpace) {
+ return toCIELabFunctionCall(color);
+ }
+
+ Color specColor = color;
+ if (color.hasAlternativeColors()) {
+ Color alt = color.getAlternativeColors()[0];
+ if (ColorSpaces.isDeviceColorSpace(alt.getColorSpace())) {
+ cs = alt.getColorSpace();
+ specColor = alt;
}
- sbuf.append(s);
- if (color.getAlpha() != 255) {
- s = Integer.toHexString(color.getAlpha());
- if (s.length() == 1) {
- sbuf.append('0');
- }
- sbuf.append(s);
+ }
+ ColorSpaceOrigin origin = ColorSpaces.getColorSpaceOrigin(cs);
+ String functionName;
+
+ Color fallbackColor = getsRGBFallback(color);
+ float[] rgb = fallbackColor.getColorComponents(null);
+ assert rgb.length == 3;
+ StringBuffer sb = new StringBuffer(40);
+ sb.append("(");
+ sb.append(rgb[0]).append(",");
+ sb.append(rgb[1]).append(",");
+ sb.append(rgb[2]).append(",");
+ String profileName = origin.getProfileName();
+ sb.append(profileName).append(",");
+ if (origin.getProfileURI() != null) {
+ sb.append("\"").append(origin.getProfileURI()).append("\"");
+ }
+
+ if (cs instanceof NamedColorSpace) {
+ NamedColorSpace ncs = (NamedColorSpace)cs;
+ if (SEPARATION_PSEUDO_PROFILE.equalsIgnoreCase(profileName)) {
+ functionName = "fop-rgb-icc";
+ } else {
+ functionName = "fop-rgb-named-color";
+ }
+ sb.append(",").append(ncs.getColorName());
+ } else {
+ functionName = "fop-rgb-icc";
+ float[] colorComponents = specColor.getColorComponents(null);
+ for (int ix = 0; ix < colorComponents.length; ix++) {
+ sb.append(",");
+ sb.append(colorComponents[ix]);
}
- return sbuf.toString();
}
+ sb.append(")");
+ return functionName + sb.toString();
+ }
+
+ private static String toCIELabFunctionCall(ColorWithAlternatives color) {
+ Color fallbackColor = getsRGBFallback(color);
+ StringBuffer sb = new StringBuffer("cie-lab-color(");
+ sb.append(fallbackColor.getRed()).append(',');
+ sb.append(fallbackColor.getGreen()).append(',');
+ sb.append(fallbackColor.getBlue());
+ CIELabColorSpace cs = (CIELabColorSpace)color.getColorSpace();
+ float[] lab = cs.toNativeComponents(color.getColorComponents(null));
+ for (int i = 0; i < 3; i++) {
+ sb.append(',').append(lab[i]);
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+
+ private static Color createColor(int r, int g, int b) {
+ return new Color(r, g, b);
}
/**
@@ -524,155 +802,155 @@ public final class ColorUtil {
private static void initializeColorMap() { // CSOK: MethodLength
colorMap = Collections.synchronizedMap(new java.util.HashMap<String, Color>());
- colorMap.put("aliceblue", new Color(240, 248, 255));
- colorMap.put("antiquewhite", new Color(250, 235, 215));
- colorMap.put("aqua", new Color(0, 255, 255));
- colorMap.put("aquamarine", new Color(127, 255, 212));
- colorMap.put("azure", new Color(240, 255, 255));
- colorMap.put("beige", new Color(245, 245, 220));
- colorMap.put("bisque", new Color(255, 228, 196));
- colorMap.put("black", new Color(0, 0, 0));
- colorMap.put("blanchedalmond", new Color(255, 235, 205));
- colorMap.put("blue", new Color(0, 0, 255));
- colorMap.put("blueviolet", new Color(138, 43, 226));
- colorMap.put("brown", new Color(165, 42, 42));
- colorMap.put("burlywood", new Color(222, 184, 135));
- colorMap.put("cadetblue", new Color(95, 158, 160));
- colorMap.put("chartreuse", new Color(127, 255, 0));
- colorMap.put("chocolate", new Color(210, 105, 30));
- colorMap.put("coral", new Color(255, 127, 80));
- colorMap.put("cornflowerblue", new Color(100, 149, 237));
- colorMap.put("cornsilk", new Color(255, 248, 220));
- colorMap.put("crimson", new Color(220, 20, 60));
- colorMap.put("cyan", new Color(0, 255, 255));
- colorMap.put("darkblue", new Color(0, 0, 139));
- colorMap.put("darkcyan", new Color(0, 139, 139));
- colorMap.put("darkgoldenrod", new Color(184, 134, 11));
- colorMap.put("darkgray", new Color(169, 169, 169));
- colorMap.put("darkgreen", new Color(0, 100, 0));
- colorMap.put("darkgrey", new Color(169, 169, 169));
- colorMap.put("darkkhaki", new Color(189, 183, 107));
- colorMap.put("darkmagenta", new Color(139, 0, 139));
- colorMap.put("darkolivegreen", new Color(85, 107, 47));
- colorMap.put("darkorange", new Color(255, 140, 0));
- colorMap.put("darkorchid", new Color(153, 50, 204));
- colorMap.put("darkred", new Color(139, 0, 0));
- colorMap.put("darksalmon", new Color(233, 150, 122));
- colorMap.put("darkseagreen", new Color(143, 188, 143));
- colorMap.put("darkslateblue", new Color(72, 61, 139));
- colorMap.put("darkslategray", new Color(47, 79, 79));
- colorMap.put("darkslategrey", new Color(47, 79, 79));
- colorMap.put("darkturquoise", new Color(0, 206, 209));
- colorMap.put("darkviolet", new Color(148, 0, 211));
- colorMap.put("deeppink", new Color(255, 20, 147));
- colorMap.put("deepskyblue", new Color(0, 191, 255));
- colorMap.put("dimgray", new Color(105, 105, 105));
- colorMap.put("dimgrey", new Color(105, 105, 105));
- colorMap.put("dodgerblue", new Color(30, 144, 255));
- colorMap.put("firebrick", new Color(178, 34, 34));
- colorMap.put("floralwhite", new Color(255, 250, 240));
- colorMap.put("forestgreen", new Color(34, 139, 34));
- colorMap.put("fuchsia", new Color(255, 0, 255));
- colorMap.put("gainsboro", new Color(220, 220, 220));
- colorMap.put("ghostwhite", new Color(248, 248, 255));
- colorMap.put("gold", new Color(255, 215, 0));
- colorMap.put("goldenrod", new Color(218, 165, 32));
- colorMap.put("gray", new Color(128, 128, 128));
- colorMap.put("green", new Color(0, 128, 0));
- colorMap.put("greenyellow", new Color(173, 255, 47));
- colorMap.put("grey", new Color(128, 128, 128));
- colorMap.put("honeydew", new Color(240, 255, 240));
- colorMap.put("hotpink", new Color(255, 105, 180));
- colorMap.put("indianred", new Color(205, 92, 92));
- colorMap.put("indigo", new Color(75, 0, 130));
- colorMap.put("ivory", new Color(255, 255, 240));
- colorMap.put("khaki", new Color(240, 230, 140));
- colorMap.put("lavender", new Color(230, 230, 250));
- colorMap.put("lavenderblush", new Color(255, 240, 245));
- colorMap.put("lawngreen", new Color(124, 252, 0));
- colorMap.put("lemonchiffon", new Color(255, 250, 205));
- colorMap.put("lightblue", new Color(173, 216, 230));
- colorMap.put("lightcoral", new Color(240, 128, 128));
- colorMap.put("lightcyan", new Color(224, 255, 255));
- colorMap.put("lightgoldenrodyellow", new Color(250, 250, 210));
- colorMap.put("lightgray", new Color(211, 211, 211));
- colorMap.put("lightgreen", new Color(144, 238, 144));
- colorMap.put("lightgrey", new Color(211, 211, 211));
- colorMap.put("lightpink", new Color(255, 182, 193));
- colorMap.put("lightsalmon", new Color(255, 160, 122));
- colorMap.put("lightseagreen", new Color(32, 178, 170));
- colorMap.put("lightskyblue", new Color(135, 206, 250));
- colorMap.put("lightslategray", new Color(119, 136, 153));
- colorMap.put("lightslategrey", new Color(119, 136, 153));
- colorMap.put("lightsteelblue", new Color(176, 196, 222));
- colorMap.put("lightyellow", new Color(255, 255, 224));
- colorMap.put("lime", new Color(0, 255, 0));
- colorMap.put("limegreen", new Color(50, 205, 50));
- colorMap.put("linen", new Color(250, 240, 230));
- colorMap.put("magenta", new Color(255, 0, 255));
- colorMap.put("maroon", new Color(128, 0, 0));
- colorMap.put("mediumaquamarine", new Color(102, 205, 170));
- colorMap.put("mediumblue", new Color(0, 0, 205));
- colorMap.put("mediumorchid", new Color(186, 85, 211));
- colorMap.put("mediumpurple", new Color(147, 112, 219));
- colorMap.put("mediumseagreen", new Color(60, 179, 113));
- colorMap.put("mediumslateblue", new Color(123, 104, 238));
- colorMap.put("mediumspringgreen", new Color(0, 250, 154));
- colorMap.put("mediumturquoise", new Color(72, 209, 204));
- colorMap.put("mediumvioletred", new Color(199, 21, 133));
- colorMap.put("midnightblue", new Color(25, 25, 112));
- colorMap.put("mintcream", new Color(245, 255, 250));
- colorMap.put("mistyrose", new Color(255, 228, 225));
- colorMap.put("moccasin", new Color(255, 228, 181));
- colorMap.put("navajowhite", new Color(255, 222, 173));
- colorMap.put("navy", new Color(0, 0, 128));
- colorMap.put("oldlace", new Color(253, 245, 230));
- colorMap.put("olive", new Color(128, 128, 0));
- colorMap.put("olivedrab", new Color(107, 142, 35));
- colorMap.put("orange", new Color(255, 165, 0));
- colorMap.put("orangered", new Color(255, 69, 0));
- colorMap.put("orchid", new Color(218, 112, 214));
- colorMap.put("palegoldenrod", new Color(238, 232, 170));
- colorMap.put("palegreen", new Color(152, 251, 152));
- colorMap.put("paleturquoise", new Color(175, 238, 238));
- colorMap.put("palevioletred", new Color(219, 112, 147));
- colorMap.put("papayawhip", new Color(255, 239, 213));
- colorMap.put("peachpuff", new Color(255, 218, 185));
- colorMap.put("peru", new Color(205, 133, 63));
- colorMap.put("pink", new Color(255, 192, 203));
- colorMap.put("plum ", new Color(221, 160, 221));
- colorMap.put("plum", new Color(221, 160, 221));
- colorMap.put("powderblue", new Color(176, 224, 230));
- colorMap.put("purple", new Color(128, 0, 128));
- colorMap.put("red", new Color(255, 0, 0));
- colorMap.put("rosybrown", new Color(188, 143, 143));
- colorMap.put("royalblue", new Color(65, 105, 225));
- colorMap.put("saddlebrown", new Color(139, 69, 19));
- colorMap.put("salmon", new Color(250, 128, 114));
- colorMap.put("sandybrown", new Color(244, 164, 96));
- colorMap.put("seagreen", new Color(46, 139, 87));
- colorMap.put("seashell", new Color(255, 245, 238));
- colorMap.put("sienna", new Color(160, 82, 45));
- colorMap.put("silver", new Color(192, 192, 192));
- colorMap.put("skyblue", new Color(135, 206, 235));
- colorMap.put("slateblue", new Color(106, 90, 205));
- colorMap.put("slategray", new Color(112, 128, 144));
- colorMap.put("slategrey", new Color(112, 128, 144));
- colorMap.put("snow", new Color(255, 250, 250));
- colorMap.put("springgreen", new Color(0, 255, 127));
- colorMap.put("steelblue", new Color(70, 130, 180));
- colorMap.put("tan", new Color(210, 180, 140));
- colorMap.put("teal", new Color(0, 128, 128));
- colorMap.put("thistle", new Color(216, 191, 216));
- colorMap.put("tomato", new Color(255, 99, 71));
- colorMap.put("turquoise", new Color(64, 224, 208));
- colorMap.put("violet", new Color(238, 130, 238));
- colorMap.put("wheat", new Color(245, 222, 179));
- colorMap.put("white", new Color(255, 255, 255));
- colorMap.put("whitesmoke", new Color(245, 245, 245));
- colorMap.put("yellow", new Color(255, 255, 0));
- colorMap.put("yellowgreen", new Color(154, 205, 50));
- colorMap.put("transparent", new Color(0, 0, 0, 0));
+ colorMap.put("aliceblue", createColor(240, 248, 255));
+ colorMap.put("antiquewhite", createColor(250, 235, 215));
+ colorMap.put("aqua", createColor(0, 255, 255));
+ colorMap.put("aquamarine", createColor(127, 255, 212));
+ colorMap.put("azure", createColor(240, 255, 255));
+ colorMap.put("beige", createColor(245, 245, 220));
+ colorMap.put("bisque", createColor(255, 228, 196));
+ colorMap.put("black", createColor(0, 0, 0));
+ colorMap.put("blanchedalmond", createColor(255, 235, 205));
+ colorMap.put("blue", createColor(0, 0, 255));
+ colorMap.put("blueviolet", createColor(138, 43, 226));
+ colorMap.put("brown", createColor(165, 42, 42));
+ colorMap.put("burlywood", createColor(222, 184, 135));
+ colorMap.put("cadetblue", createColor(95, 158, 160));
+ colorMap.put("chartreuse", createColor(127, 255, 0));
+ colorMap.put("chocolate", createColor(210, 105, 30));
+ colorMap.put("coral", createColor(255, 127, 80));
+ colorMap.put("cornflowerblue", createColor(100, 149, 237));
+ colorMap.put("cornsilk", createColor(255, 248, 220));
+ colorMap.put("crimson", createColor(220, 20, 60));
+ colorMap.put("cyan", createColor(0, 255, 255));
+ colorMap.put("darkblue", createColor(0, 0, 139));
+ colorMap.put("darkcyan", createColor(0, 139, 139));
+ colorMap.put("darkgoldenrod", createColor(184, 134, 11));
+ colorMap.put("darkgray", createColor(169, 169, 169));
+ colorMap.put("darkgreen", createColor(0, 100, 0));
+ colorMap.put("darkgrey", createColor(169, 169, 169));
+ colorMap.put("darkkhaki", createColor(189, 183, 107));
+ colorMap.put("darkmagenta", createColor(139, 0, 139));
+ colorMap.put("darkolivegreen", createColor(85, 107, 47));
+ colorMap.put("darkorange", createColor(255, 140, 0));
+ colorMap.put("darkorchid", createColor(153, 50, 204));
+ colorMap.put("darkred", createColor(139, 0, 0));
+ colorMap.put("darksalmon", createColor(233, 150, 122));
+ colorMap.put("darkseagreen", createColor(143, 188, 143));
+ colorMap.put("darkslateblue", createColor(72, 61, 139));
+ colorMap.put("darkslategray", createColor(47, 79, 79));
+ colorMap.put("darkslategrey", createColor(47, 79, 79));
+ colorMap.put("darkturquoise", createColor(0, 206, 209));
+ colorMap.put("darkviolet", createColor(148, 0, 211));
+ colorMap.put("deeppink", createColor(255, 20, 147));
+ colorMap.put("deepskyblue", createColor(0, 191, 255));
+ colorMap.put("dimgray", createColor(105, 105, 105));
+ colorMap.put("dimgrey", createColor(105, 105, 105));
+ colorMap.put("dodgerblue", createColor(30, 144, 255));
+ colorMap.put("firebrick", createColor(178, 34, 34));
+ colorMap.put("floralwhite", createColor(255, 250, 240));
+ colorMap.put("forestgreen", createColor(34, 139, 34));
+ colorMap.put("fuchsia", createColor(255, 0, 255));
+ colorMap.put("gainsboro", createColor(220, 220, 220));
+ colorMap.put("ghostwhite", createColor(248, 248, 255));
+ colorMap.put("gold", createColor(255, 215, 0));
+ colorMap.put("goldenrod", createColor(218, 165, 32));
+ colorMap.put("gray", createColor(128, 128, 128));
+ colorMap.put("green", createColor(0, 128, 0));
+ colorMap.put("greenyellow", createColor(173, 255, 47));
+ colorMap.put("grey", createColor(128, 128, 128));
+ colorMap.put("honeydew", createColor(240, 255, 240));
+ colorMap.put("hotpink", createColor(255, 105, 180));
+ colorMap.put("indianred", createColor(205, 92, 92));
+ colorMap.put("indigo", createColor(75, 0, 130));
+ colorMap.put("ivory", createColor(255, 255, 240));
+ colorMap.put("khaki", createColor(240, 230, 140));
+ colorMap.put("lavender", createColor(230, 230, 250));
+ colorMap.put("lavenderblush", createColor(255, 240, 245));
+ colorMap.put("lawngreen", createColor(124, 252, 0));
+ colorMap.put("lemonchiffon", createColor(255, 250, 205));
+ colorMap.put("lightblue", createColor(173, 216, 230));
+ colorMap.put("lightcoral", createColor(240, 128, 128));
+ colorMap.put("lightcyan", createColor(224, 255, 255));
+ colorMap.put("lightgoldenrodyellow", createColor(250, 250, 210));
+ colorMap.put("lightgray", createColor(211, 211, 211));
+ colorMap.put("lightgreen", createColor(144, 238, 144));
+ colorMap.put("lightgrey", createColor(211, 211, 211));
+ colorMap.put("lightpink", createColor(255, 182, 193));
+ colorMap.put("lightsalmon", createColor(255, 160, 122));
+ colorMap.put("lightseagreen", createColor(32, 178, 170));
+ colorMap.put("lightskyblue", createColor(135, 206, 250));
+ colorMap.put("lightslategray", createColor(119, 136, 153));
+ colorMap.put("lightslategrey", createColor(119, 136, 153));
+ colorMap.put("lightsteelblue", createColor(176, 196, 222));
+ colorMap.put("lightyellow", createColor(255, 255, 224));
+ colorMap.put("lime", createColor(0, 255, 0));
+ colorMap.put("limegreen", createColor(50, 205, 50));
+ colorMap.put("linen", createColor(250, 240, 230));
+ colorMap.put("magenta", createColor(255, 0, 255));
+ colorMap.put("maroon", createColor(128, 0, 0));
+ colorMap.put("mediumaquamarine", createColor(102, 205, 170));
+ colorMap.put("mediumblue", createColor(0, 0, 205));
+ colorMap.put("mediumorchid", createColor(186, 85, 211));
+ colorMap.put("mediumpurple", createColor(147, 112, 219));
+ colorMap.put("mediumseagreen", createColor(60, 179, 113));
+ colorMap.put("mediumslateblue", createColor(123, 104, 238));
+ colorMap.put("mediumspringgreen", createColor(0, 250, 154));
+ colorMap.put("mediumturquoise", createColor(72, 209, 204));
+ colorMap.put("mediumvioletred", createColor(199, 21, 133));
+ colorMap.put("midnightblue", createColor(25, 25, 112));
+ colorMap.put("mintcream", createColor(245, 255, 250));
+ colorMap.put("mistyrose", createColor(255, 228, 225));
+ colorMap.put("moccasin", createColor(255, 228, 181));
+ colorMap.put("navajowhite", createColor(255, 222, 173));
+ colorMap.put("navy", createColor(0, 0, 128));
+ colorMap.put("oldlace", createColor(253, 245, 230));
+ colorMap.put("olive", createColor(128, 128, 0));
+ colorMap.put("olivedrab", createColor(107, 142, 35));
+ colorMap.put("orange", createColor(255, 165, 0));
+ colorMap.put("orangered", createColor(255, 69, 0));
+ colorMap.put("orchid", createColor(218, 112, 214));
+ colorMap.put("palegoldenrod", createColor(238, 232, 170));
+ colorMap.put("palegreen", createColor(152, 251, 152));
+ colorMap.put("paleturquoise", createColor(175, 238, 238));
+ colorMap.put("palevioletred", createColor(219, 112, 147));
+ colorMap.put("papayawhip", createColor(255, 239, 213));
+ colorMap.put("peachpuff", createColor(255, 218, 185));
+ colorMap.put("peru", createColor(205, 133, 63));
+ colorMap.put("pink", createColor(255, 192, 203));
+ colorMap.put("plum ", createColor(221, 160, 221));
+ colorMap.put("plum", createColor(221, 160, 221));
+ colorMap.put("powderblue", createColor(176, 224, 230));
+ colorMap.put("purple", createColor(128, 0, 128));
+ colorMap.put("red", createColor(255, 0, 0));
+ colorMap.put("rosybrown", createColor(188, 143, 143));
+ colorMap.put("royalblue", createColor(65, 105, 225));
+ colorMap.put("saddlebrown", createColor(139, 69, 19));
+ colorMap.put("salmon", createColor(250, 128, 114));
+ colorMap.put("sandybrown", createColor(244, 164, 96));
+ colorMap.put("seagreen", createColor(46, 139, 87));
+ colorMap.put("seashell", createColor(255, 245, 238));
+ colorMap.put("sienna", createColor(160, 82, 45));
+ colorMap.put("silver", createColor(192, 192, 192));
+ colorMap.put("skyblue", createColor(135, 206, 235));
+ colorMap.put("slateblue", createColor(106, 90, 205));
+ colorMap.put("slategray", createColor(112, 128, 144));
+ colorMap.put("slategrey", createColor(112, 128, 144));
+ colorMap.put("snow", createColor(255, 250, 250));
+ colorMap.put("springgreen", createColor(0, 255, 127));
+ colorMap.put("steelblue", createColor(70, 130, 180));
+ colorMap.put("tan", createColor(210, 180, 140));
+ colorMap.put("teal", createColor(0, 128, 128));
+ colorMap.put("thistle", createColor(216, 191, 216));
+ colorMap.put("tomato", createColor(255, 99, 71));
+ colorMap.put("turquoise", createColor(64, 224, 208));
+ colorMap.put("violet", createColor(238, 130, 238));
+ colorMap.put("wheat", createColor(245, 222, 179));
+ colorMap.put("white", createColor(255, 255, 255));
+ colorMap.put("whitesmoke", createColor(245, 245, 245));
+ colorMap.put("yellow", createColor(255, 255, 0));
+ colorMap.put("yellowgreen", createColor(154, 205, 50));
+ colorMap.put("transparent", new ColorWithAlternatives(0, 0, 0, 0, null));
}
/**
@@ -692,7 +970,8 @@ public final class ColorUtil {
* @return true if the color profile name is of a built-in pseudo-profile
*/
public static boolean isPseudoProfile(String colorProfileName) {
- return CMYK_PSEUDO_PROFILE.equalsIgnoreCase(colorProfileName);
+ return CMYK_PSEUDO_PROFILE.equalsIgnoreCase(colorProfileName)
+ || SEPARATION_PSEUDO_PROFILE.equalsIgnoreCase(colorProfileName);
}
/**
@@ -710,11 +989,6 @@ public final class ColorUtil {
* @return the CMYK color
*/
public static Color toCMYKGrayColor(float black) {
- float[] cmyk = new float[] {0f, 0f, 0f, 1.0f - black};
- DeviceCMYKColorSpace cmykCs = ColorSpaces.getDeviceCMYKColorSpace();
- float[] rgb = cmykCs.toRGB(cmyk);
- return ColorExt.createFromFoRgbIcc(rgb[0], rgb[1], rgb[2],
- CMYK_PSEUDO_PROFILE, null, cmykCs, cmyk);
+ return org.apache.xmlgraphics.java2d.color.ColorUtil.toCMYKGrayColor(black);
}
-
}
diff --git a/src/java/org/apache/fop/util/ColorWithFallback.java b/src/java/org/apache/fop/util/ColorWithFallback.java
new file mode 100644
index 000000000..0ec560367
--- /dev/null
+++ b/src/java/org/apache/fop/util/ColorWithFallback.java
@@ -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;
+ }
+
+}