aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/util
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2006-11-13 10:08:19 +0000
committerJeremias Maerki <jeremias@apache.org>2006-11-13 10:08:19 +0000
commita625241b1f303263e20c221b6059082140603867 (patch)
tree1b93f85fff796eb8e1d90391257c409a203afdee /src/java/org/apache/fop/util
parent3c09dd0bd232edd1c8a988dac28f2d9f6124a009 (diff)
downloadxmlgraphics-fop-a625241b1f303263e20c221b6059082140603867.tar.gz
xmlgraphics-fop-a625241b1f303263e20c221b6059082140603867.zip
Bugzilla #40729:
Support for the rgb-icc() function and for a proprietary cmyk() function (for device CMYK colors only through the PDF renderer so far). Submitted by: Peter Coppens <pc.subscriptions.at.gmail.com> Patch slightly modified to comply with our Java conventions, plus some minor editing. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@474225 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/util')
-rw-r--r--src/java/org/apache/fop/util/CMYKColorSpace.java5
-rw-r--r--src/java/org/apache/fop/util/ColorExt.java189
-rw-r--r--src/java/org/apache/fop/util/ColorUtil.java256
3 files changed, 418 insertions, 32 deletions
diff --git a/src/java/org/apache/fop/util/CMYKColorSpace.java b/src/java/org/apache/fop/util/CMYKColorSpace.java
index 00a3f32a2..655c0b3d9 100644
--- a/src/java/org/apache/fop/util/CMYKColorSpace.java
+++ b/src/java/org/apache/fop/util/CMYKColorSpace.java
@@ -51,7 +51,10 @@ public class CMYKColorSpace extends ColorSpace {
* @see java.awt.color.ColorSpace#toRGB(float[])
*/
public float[] toRGB(float[] colorvalue) {
- throw new UnsupportedOperationException("NYI");
+ return new float [] {
+ (1 - colorvalue[0]) * (1 - colorvalue[3]),
+ (1 - colorvalue[1]) * (1 - colorvalue[3]),
+ (1 - colorvalue[2]) * (1 - colorvalue[3])};
}
/**
diff --git a/src/java/org/apache/fop/util/ColorExt.java b/src/java/org/apache/fop/util/ColorExt.java
new file mode 100644
index 000000000..bd2c95a33
--- /dev/null
+++ b/src/java/org/apache/fop/util/ColorExt.java
@@ -0,0 +1,189 @@
+/*
+ * 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;
+
+/**
+ * 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.
+ */
+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(float red, float green,
+ float blue, float opacity, String profileName, String profileHref,
+ ColorSpace profileCS, float[] colorValues) {
+ 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;
+
+ }
+
+ /**
+ * 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() {
+ return this.colorSpace;
+ }
+
+ /**
+ * @return the original color values
+ */
+ public float[] getOriginalColorComponents() {
+ return this.colorValues;
+ }
+
+ /**
+ * 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 + ",");
+ 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();
+ }
+
+}
diff --git a/src/java/org/apache/fop/util/ColorUtil.java b/src/java/org/apache/fop/util/ColorUtil.java
index 652924025..37762b1e8 100644
--- a/src/java/org/apache/fop/util/ColorUtil.java
+++ b/src/java/org/apache/fop/util/ColorUtil.java
@@ -20,10 +20,16 @@
package org.apache.fop.util;
import java.awt.Color;
+import java.awt.color.ColorSpace;
import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.expr.PropertyException;
/**
@@ -31,19 +37,21 @@ import org.apache.fop.fo.expr.PropertyException;
* <p>
* This class supports parsing string values into color values and creating
* color values for strings. It provides a list of standard color names.
- * <p>
- * TODO: Add support for color Profiles.
*/
public final class ColorUtil {
/**
+ *
* 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.
*/
private static Map colorMap = null;
-
+
+ /** Logger instance */
+ protected static Log log = LogFactory.getLog(ColorUtil.class);
+
static {
initializeColorMap();
}
@@ -68,8 +76,11 @@ public final class ColorUtil {
* <li>system-color(colorname)</li>
* <li>transparent</li>
* <li>colorname</li>
+ * <li>fop-rgb-icc</li>
+ * <li>cmyk</li>
* </ul>
*
+ * @param foUserAgent FOUserAgent object
* @param value
* the string to parse.
* @return a Color representing the string if possible
@@ -77,7 +88,8 @@ public final class ColorUtil {
* if the string is not parsable or does not follow any of the
* given formats.
*/
- public static Color parseColorString(String value) throws PropertyException {
+ public static Color parseColorString(FOUserAgent foUserAgent, String value)
+ throws PropertyException {
if (value == null) {
return null;
}
@@ -96,18 +108,23 @@ public final class ColorUtil {
parsedColor = parseAsJavaAWTColor(value);
} else if (value.startsWith("system-color(")) {
parsedColor = parseAsSystemColor(value);
+ } else if (value.startsWith("fop-rgb-icc")) {
+ parsedColor = parseAsFopRgbIcc(foUserAgent, value);
+ } else if (value.startsWith("cmyk")) {
+ parsedColor = parseAsCMYK(value);
}
-
+
if (parsedColor == null) {
- throw new PropertyException("Unkown Color: " + value);
+ throw new PropertyException("Unknown Color: " + value);
}
colorMap.put(value, parsedColor);
}
- // TODO: Check if this is really necessary
- return new Color(parsedColor.getRed(), parsedColor.getGreen(),
- parsedColor.getBlue(), parsedColor.getAlpha());
+ // 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;
}
/**
@@ -282,6 +299,174 @@ public final class ColorUtil {
}
/**
+ * Parse a color specified using the fop-rgb-icc() function.
+ *
+ * @param value the function call
+ * @return a color if possible
+ * @throws PropertyException if the format is wrong.
+ */
+ private static Color parseAsFopRgbIcc(FOUserAgent foUserAgent, String value)
+ throws PropertyException {
+ Color parsedColor;
+ int poss = value.indexOf("(");
+ int pose = value.indexOf(")");
+ if (poss != -1 && pose != -1) {
+ value = value.substring(poss + 1, pose);
+ StringTokenizer st = new StringTokenizer(value, ",");
+ try {
+ float red = 0.0f, green = 0.0f, blue = 0.0f;
+ if (st.hasMoreTokens()) {
+ String str = st.nextToken().trim();
+ red = Float.parseFloat(str);
+ }
+ if (st.hasMoreTokens()) {
+ String str = st.nextToken().trim();
+ green = Float.parseFloat(str);
+ }
+ if (st.hasMoreTokens()) {
+ String str = st.nextToken().trim();
+ blue = Float.parseFloat(str);
+ }
+ /* Verify rgb replacement arguments */
+ 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");
+ }
+ /* Get and verify ICC profile name */
+ String iccProfileName = null;
+ if (st.hasMoreTokens()) {
+ iccProfileName = st.nextToken().trim();
+ }
+ if (iccProfileName == null || iccProfileName.length() == 0) {
+ throw new PropertyException("ICC profile name missing");
+ }
+ /* Get and verify ICC profile source */
+ String iccProfileSrc = null;
+ if (st.hasMoreTokens()) {
+ iccProfileSrc = st.nextToken().trim();
+ // Strip quotes
+ iccProfileSrc = iccProfileSrc.substring(1, iccProfileSrc.length() - 1);
+ }
+ if (iccProfileSrc == null || iccProfileSrc.length() == 0) {
+ throw new PropertyException("ICC profile source missing");
+ }
+ /* ICC profile arguments */
+ List iccArgList = new LinkedList();
+ while (st.hasMoreTokens()) {
+ String str = st.nextToken().trim();
+ iccArgList.add(new Float(str));
+ }
+ /* Copy ICC profile arguments from list to array */
+ float[] iccComponents = new float[iccArgList.size()];
+ for (int ix = 0; ix < iccArgList.size(); ix++) {
+ iccComponents[ix] = ((Float)iccArgList.get(ix)).floatValue();
+ }
+ /* Ask FOP factory to get ColorSpace for the specified ICC profile source */
+ ColorSpace colorSpace = (foUserAgent != null
+ ? foUserAgent.getFactory().getColorSpace(
+ foUserAgent.getBaseURL(), iccProfileSrc) : null);
+ 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);
+ } 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(red, green, blue);
+ }
+ } catch (Exception e) {
+ throw new PropertyException(
+ "Arguments to rgb-icc() must be [0..255] or [0%..100%]");
+ }
+ } else {
+ throw new PropertyException("Unknown color format: " + value
+ + ". Must be fop-rgb-icc(r,g,b,NCNAME,\"src\",....)");
+ }
+ return parsedColor;
+ }
+
+ /**
+ * Parse a color given with the cmyk() function.
+ *
+ * @param value
+ * the complete line
+ * @return a color if possible
+ * @throws PropertyException
+ * if the format is wrong.
+ */
+ private static Color parseAsCMYK(String value) throws PropertyException {
+ Color parsedColor;
+ int poss = value.indexOf("(");
+ int pose = value.indexOf(")");
+ if (poss != -1 && pose != -1) {
+ value = value.substring(poss + 1, pose);
+ StringTokenizer st = new StringTokenizer(value, ",");
+ try {
+ float cyan = 0.0f, magenta = 0.0f, yellow = 0.0f, black = 0.0f;
+ if (st.hasMoreTokens()) {
+ String str = st.nextToken().trim();
+ if (str.endsWith("%")) {
+ cyan = Float.parseFloat(str.substring(0,
+ str.length() - 1)) / 100.0f;
+ } else {
+ cyan = Float.parseFloat(str);
+ }
+ }
+ if (st.hasMoreTokens()) {
+ String str = st.nextToken().trim();
+ if (str.endsWith("%")) {
+ magenta = Float.parseFloat(str.substring(0,
+ str.length() - 1)) / 100.0f;
+ } else {
+ magenta = Float.parseFloat(str);
+ }
+ }
+ if (st.hasMoreTokens()) {
+ String str = st.nextToken().trim();
+ if (str.endsWith("%")) {
+ yellow = Float.parseFloat(str.substring(0,
+ str.length() - 1)) / 100.0f;
+ } else {
+ yellow = Float.parseFloat(str);
+ }
+ }
+ if (st.hasMoreTokens()) {
+ String str = st.nextToken().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");
+ }
+ float[] cmyk = new float[] {cyan, magenta, yellow, black};
+ CMYKColorSpace cmykCs = CMYKColorSpace.getInstance();
+ float[] rgb = cmykCs.toRGB(cmyk);
+ parsedColor = ColorExt.createFromFoRgbIcc(rgb[0], rgb[1], rgb[2],
+ null, "#CMYK", cmykCs, cmyk);
+
+
+ } catch (Exception e) {
+ throw new PropertyException(
+ "Arguments to cmyk() must be in the range [0%-100%] or [0.0-1.0]");
+ }
+ } else {
+ throw new PropertyException("Unknown color format: " + value
+ + ". Must be cmyk(c,m,y,k)");
+ }
+ return parsedColor;
+ }
+
+ /**
* Creates a re-parsable string representation of the given color.
* <p>
* First, the color will be converted into the sRGB colorspace. It will then
@@ -291,33 +476,42 @@ public final class ColorUtil {
* the color to represent.
* @return a re-parsable string representadion.
*/
- public static String colorTOsRGBString(Color color) {
- StringBuffer sbuf = new StringBuffer(10);
- 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());
+ public static String colorToString(Color color) {
+ ColorSpace cs = color.getColorSpace();
+ 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 if (color instanceof ColorExt) {
+ return ((ColorExt)color).toFunctionCall();
+ } else {
+ 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);
+ }
+ return sbuf.toString();
}
- return sbuf.toString();
-
}
/**