From ce1985d668d74d0b8a8d4c485ccd744a5d1ea5f0 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Tue, 29 Jun 2010 14:30:53 +0000 Subject: [PATCH] Added support for the rgb-named-color() function that is found in the current XSL 2.0 design notes. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Color@958992 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/fo/expr/NamedColorFunction.java | 112 ++++++++++++++++ .../apache/fop/fo/expr/PropertyParser.java | 1 + src/java/org/apache/fop/util/ColorUtil.java | 123 +++++++++++++++++- 3 files changed, 230 insertions(+), 6 deletions(-) create mode 100644 src/java/org/apache/fop/fo/expr/NamedColorFunction.java 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..91218deec 100644 --- a/src/java/org/apache/fop/fo/expr/PropertyParser.java +++ b/src/java/org/apache/fop/fo/expr/PropertyParser.java @@ -69,6 +69,7 @@ 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()); FUNCTION_TABLE.put("cmyk", new CMYKcolorFunction()); //non-standard!!! /** diff --git a/src/java/org/apache/fop/util/ColorUtil.java b/src/java/org/apache/fop/util/ColorUtil.java index 5b7202775..983b3c421 100644 --- a/src/java/org/apache/fop/util/ColorUtil.java +++ b/src/java/org/apache/fop/util/ColorUtil.java @@ -21,6 +21,8 @@ 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; @@ -32,6 +34,8 @@ import org.apache.xmlgraphics.java2d.color.ColorSpaces; import org.apache.xmlgraphics.java2d.color.DeviceCMYKColorSpace; import org.apache.xmlgraphics.java2d.color.ICCColor; import org.apache.xmlgraphics.java2d.color.NamedColorSpace; +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; @@ -124,6 +128,8 @@ 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("cmyk")) { parsedColor = parseAsCMYK(value); } @@ -366,12 +372,7 @@ 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 */ int componentStart = 4; @@ -417,6 +418,116 @@ public final class ColorUtil { return parsedColor; } + /** + * 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() function must have 6 arguments"); + } + + //Set up fallback sRGB value + float red = Float.parseFloat(args[0].trim()); + float green = Float.parseFloat(args[1].trim()); + float 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-named-color() must be [0..1]"); + } + Color sRGB = new ColorExt(red, green, blue, null); + + /* 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) { + colorSpace = (ICC_ColorSpace)foUserAgent.getFactory().getColorSpace( + foUserAgent.getBaseURL(), iccProfileSrc); + } + if (colorSpace != null) { + ICC_Profile profile = colorSpace.getProfile(); + if (NamedColorProfileParser.isNamedColorProfile(profile)) { + NamedColorProfileParser parser = new NamedColorProfileParser(); + NamedColorProfile ncp = parser.parseProfile(profile); + NamedColorSpace ncs = ncp.getNamedColor(colorName); + if (ncs != null) { + ICCColor iccColor = new ICCColor(ncs, + iccProfileName, iccProfileSrc, + new float[] {1.0f}, 1.0f); + parsedColor = new ColorExt(red, green, blue, new Color[] {iccColor}); + } 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; + } + + 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. * -- 2.39.5