diff options
author | Jeremias Maerki <jeremias@apache.org> | 2011-02-10 15:58:57 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2011-02-10 15:58:57 +0000 |
commit | 3df0d00cdc96c2283046fe200f85d12bb85687c3 (patch) | |
tree | 62f91c73633d70b31ef9f1e32598225a2f37d8aa /src/java/org/apache/fop/util | |
parent | f1269cc280b846cd6da396177bc74c4c9808579e (diff) | |
parent | 1c11bf98135675a9d6b6acac4fd7856a5dde8751 (diff) | |
download | xmlgraphics-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/util')
-rw-r--r-- | src/java/org/apache/fop/util/AbstractPaintingState.java | 10 | ||||
-rw-r--r-- | src/java/org/apache/fop/util/ColorExt.java | 259 | ||||
-rw-r--r-- | src/java/org/apache/fop/util/ColorSpaceCache.java | 19 | ||||
-rw-r--r-- | src/java/org/apache/fop/util/ColorUtil.java | 840 | ||||
-rw-r--r-- | src/java/org/apache/fop/util/ColorWithFallback.java | 85 |
5 files changed, 922 insertions, 291 deletions
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; + } + +} |