diff options
-rw-r--r-- | src/java/org/apache/fop/util/ColorUtil.java | 284 | ||||
-rw-r--r-- | test/layoutengine/standard-testcases/color_1.xml | 5 |
2 files changed, 135 insertions, 154 deletions
diff --git a/src/java/org/apache/fop/util/ColorUtil.java b/src/java/org/apache/fop/util/ColorUtil.java index 37762b1e8..bb014b2af 100644 --- a/src/java/org/apache/fop/util/ColorUtil.java +++ b/src/java/org/apache/fop/util/ColorUtil.java @@ -22,10 +22,7 @@ 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; @@ -167,30 +164,28 @@ public final class ColorUtil { try { if (poss != -1 && pose != -1) { value = value.substring(poss + 1, pose); - StringTokenizer st = new StringTokenizer(value, ","); - if (st.hasMoreTokens()) { - String str = st.nextToken().trim(); - red = Float.parseFloat(str.substring(2)) / 255f; + String[] args = value.split(","); + if (args.length != 3) { + throw new PropertyException( + "Invalid number of arguments for a java.awt.Color: " + value); } - if (st.hasMoreTokens()) { - String str = st.nextToken().trim(); - green = Float.parseFloat(str.substring(2)) / 255f; - } - if (st.hasMoreTokens()) { - String str = st.nextToken().trim(); - blue = Float.parseFloat(str.substring(2)) / 255f; - } else { - throw new NumberFormatException(); - } - if ((red < 0.0 || red > 1.0) || (green < 0.0 || green > 1.0) + + red = Float.parseFloat(args[0].trim().substring(2)) / 255f; + green = Float.parseFloat(args[1].trim().substring(2)) / 255f; + blue = Float.parseFloat(args[2].trim().substring(2)) / 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"); } } else { - throw new NullPointerException(); + throw new IllegalArgumentException( + "Invalid format for a java.awt.Color: " + value); } + } catch (PropertyException pe) { + throw pe; } catch (Exception e) { - throw new PropertyException("Unknown color format: " + value); + throw new PropertyException(e); } return new Color(red, green, blue); } @@ -210,44 +205,46 @@ public final class ColorUtil { int pose = value.indexOf(")"); if (poss != -1 && pose != -1) { value = value.substring(poss + 1, pose); - StringTokenizer st = new StringTokenizer(value, ","); try { + String[] args = value.split(","); + if (args.length != 3) { + throw new PropertyException( + "Invalid number of arguments: rgb(" + value + ")"); + } float red = 0.0f, green = 0.0f, blue = 0.0f; - if (st.hasMoreTokens()) { - String str = st.nextToken().trim(); - if (str.endsWith("%")) { - red = Float.parseFloat(str.substring(0, - str.length() - 1)) / 100.0f; - } else { - red = Float.parseFloat(str) / 255f; - } + String str = args[0].trim(); + if (str.endsWith("%")) { + red = Float.parseFloat(str.substring(0, + str.length() - 1)) / 100f; + } else { + red = Float.parseFloat(str) / 255f; } - if (st.hasMoreTokens()) { - String str = st.nextToken().trim(); - if (str.endsWith("%")) { - green = Float.parseFloat(str.substring(0, - str.length() - 1)) / 100.0f; - } else { - green = 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; } - if (st.hasMoreTokens()) { - String str = st.nextToken().trim(); - if (str.endsWith("%")) { - blue = Float.parseFloat(str.substring(0, - str.length() - 1)) / 100.0f; - } else { - blue = 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) + 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); + } catch (PropertyException pe) { + //simply re-throw + throw pe; } catch (Exception e) { - throw new PropertyException( - "Arguments to rgb() must be [0..255] or [0%..100%]"); + //wrap in a PropertyException + throw new PropertyException(e); } } else { throw new PropertyException("Unknown color format: " + value @@ -269,29 +266,28 @@ public final class ColorUtil { Color parsedColor = null; try { int len = value.length(); - if ((len >= 4) && (len <= 5)) { - // note: divide by 15 so F = FF = 1 and so on - float red = Integer.parseInt(value.substring(1, 2), 16) / 15f; - float green = Integer.parseInt(value.substring(2, 3), 16) / 15f; - float blue = Integer.parseInt(value.substring(3, 4), 16) / 15f; - float alpha = 1.0f; - if (len == 5) { - alpha = Integer.parseInt(value.substring(4), 16) / 15f; - } - parsedColor = new Color(red, green, blue, alpha); + int alpha; + if (len == 5 || len == 9) { + alpha = Integer.parseInt( + value.substring((len == 5) ? 3 : 7), 16); + } else { + alpha = 0xFF; + } + int red = 0, green = 0, blue = 0; + if ((len == 4) || (len == 5)) { + //multiply by 0x11 = 17 = 255/15 + red = Integer.parseInt(value.substring(1, 2), 16) * 0x11; + green = Integer.parseInt(value.substring(2, 3), 16) * 0x11; + blue = Integer.parseInt(value.substring(3, 4), 16) *0X11; } else if ((len == 7) || (len == 9)) { - int red = Integer.parseInt(value.substring(1, 3), 16); - int green = Integer.parseInt(value.substring(3, 5), 16); - int blue = Integer.parseInt(value.substring(5, 7), 16); - int alpha = 255; - if (len == 9) { - alpha = Integer.parseInt(value.substring(7), 16); - } - parsedColor = new Color(red, green, blue, alpha); + red = Integer.parseInt(value.substring(1, 3), 16); + green = Integer.parseInt(value.substring(3, 5), 16); + blue = Integer.parseInt(value.substring(5, 7), 16); } else { throw new NumberFormatException(); } - } catch (NumberFormatException e) { + parsedColor = new Color(red, green, blue, alpha); + } catch (Exception e) { throw new PropertyException("Unknown color format: " + value + ". Must be #RGB. #RGBA, #RRGGBB, or #RRGGBBAA"); } @@ -311,79 +307,65 @@ public final class ColorUtil { int poss = value.indexOf("("); int pose = value.indexOf(")"); if (poss != -1 && pose != -1) { - value = value.substring(poss + 1, pose); - StringTokenizer st = new StringTokenizer(value, ","); + String[] args = value.substring(poss + 1, pose).split(","); + 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 (args.length < 5) { + throw new PropertyException("Too few arguments for rgb-icc() function"); } - 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) { + String iccProfileName = args[3].trim(); + if (iccProfileName == null || "".equals(iccProfileName)) { 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) { + String iccProfileSrc = args[4].trim(); + if (iccProfileSrc == null || "".equals(iccProfileSrc)) { 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(); + float[] iccComponents = new float[args.length - 5]; + for (int ix = 4; ++ix < args.length;) { + iccComponents[ix - 5] = Float.parseFloat(args[ix].trim()); } /* Ask FOP factory to get ColorSpace for the specified ICC profile source */ ColorSpace colorSpace = (foUserAgent != null ? foUserAgent.getFactory().getColorSpace( foUserAgent.getBaseURL(), iccProfileSrc) : null); + + 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 > 255) + || (green < 0 || green > 255) + || (blue < 0 || blue > 255)) { + throw new PropertyException("Color values out of range. " + + "Arguments to rgb-icc() must be [0..255] or [0%..100%]"); + } + if (colorSpace != null) { // ColorSpace available - create ColorExt (keeps track of replacement rgb // values for possible later colorTOsRGBString call - parsedColor = ColorExt.createFromFoRgbIcc(red, green, blue, + parsedColor = ColorExt.createFromFoRgbIcc(red/255, green/255, blue/255, 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); + parsedColor = new Color((int)red, (int)green, (int)blue); } + } catch (PropertyException pe) { + //simply re-throw + throw pe; } catch (Exception e) { - throw new PropertyException( - "Arguments to rgb-icc() must be [0..255] or [0%..100%]"); + //wrap in a PropertyException + throw new PropertyException(e); } } else { throw new PropertyException("Unknown color format: " + value - + ". Must be fop-rgb-icc(r,g,b,NCNAME,\"src\",....)"); + + ". Must be fop-rgb-icc(r,g,b,NCNAME,src,....)"); } return parsedColor; } @@ -403,61 +385,58 @@ public final class ColorUtil { int pose = value.indexOf(")"); if (poss != -1 && pose != -1) { value = value.substring(poss + 1, pose); - StringTokenizer st = new StringTokenizer(value, ","); + String[] args = value.split(","); try { + if (args.length != 4) { + throw new PropertyException( + "Invalid number of arguments: cmyk(" + value + ")"); + } 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); - } + 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); } - 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); - } + str = args[2].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("%")) { - 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 (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"); + 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}; CMYKColorSpace cmykCs = CMYKColorSpace.getInstance(); float[] rgb = cmykCs.toRGB(cmyk); parsedColor = ColorExt.createFromFoRgbIcc(rgb[0], rgb[1], rgb[2], null, "#CMYK", cmykCs, cmyk); - - + } catch (PropertyException pe) { + throw pe; } catch (Exception e) { - throw new PropertyException( - "Arguments to cmyk() must be in the range [0%-100%] or [0.0-1.0]"); + throw new PropertyException(e); } } else { throw new PropertyException("Unknown color format: " + value @@ -668,7 +647,6 @@ public final class ColorUtil { 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)); } diff --git a/test/layoutengine/standard-testcases/color_1.xml b/test/layoutengine/standard-testcases/color_1.xml index 1e4e96cc8..55ab47b01 100644 --- a/test/layoutengine/standard-testcases/color_1.xml +++ b/test/layoutengine/standard-testcases/color_1.xml @@ -26,7 +26,7 @@ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-family="Gladiator"> <fo:layout-master-set> <fo:simple-page-master master-name="normal" page-width="5in" page-height="5in"> - <fo:region-body/> + <fo:region-body background-color="rgb-icc(100%,0%,0%,sRGB,1,0.5,0)" /> </fo:simple-page-master> </fo:layout-master-set> <fo:declarations> @@ -47,6 +47,9 @@ </fo> <checks> <!-- Check page --> + <!-- Special case? rgb-icc() used before fo:declarations + Revert to sRGB fallback for now --> + <eval expected="color=#ff0000" xpath="//regionViewport[1]/@background" /> <eval expected="#ff0000" xpath="//block[1]//text/@color"/> <eval expected="#ff8000" xpath="//block[2]//text/@color"/> <eval expected="#ff8000" xpath="//block[3]//text/@color"/> |