]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
fop-rgb-icc() function did not make the round-trip which caused an error in the color...
authorJeremias Maerki <jeremias@apache.org>
Mon, 18 Feb 2008 15:02:39 +0000 (15:02 +0000)
committerJeremias Maerki <jeremias@apache.org>
Mon, 18 Feb 2008 15:02:39 +0000 (15:02 +0000)
Documented the cmyk() function.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@628775 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/trunk/extensions.xml
src/java/org/apache/fop/fo/expr/ICCColorFunction.java
src/java/org/apache/fop/util/ColorUtil.java
test/java/org/apache/fop/UtilityCodeTestSuite.java
test/java/org/apache/fop/traits/TraitColorTestCase.java [deleted file]
test/java/org/apache/fop/util/ColorUtilTestCase.java [new file with mode: 0644]
test/layoutengine/standard-testcases/color_1.xml

index fb3db86fe0d9b31518802ad98f56fea8ed29ffd3..483866e61d7895f12fa7ac485b0c76f90c047425 100644 (file)
@@ -210,6 +210,24 @@ to following pages. Here is an example of FO code creating such a table-header:<
           supported for PDF, PS and Java2D-based renderers.
         </note>
       </section>
+      <section id="color-functions">
+        <title>Color functions</title>
+        <p>
+          XSL-FO supports specifying color using the rgb(), rgb-icc() and system-color() functions.
+          Apache FOP provides additional color functions for special use cases. Please note that
+          using these functions compromises the interoperability of an FO document.
+        </p>
+        <section id="color-function-cmyk">
+          <title>cmyk()</title>
+          <p><code>color cmyk(numeric, numeric, numeric, numeric)</code></p>
+          <p>
+            This function will construct a color in device-specific CMYK color space. The numbers
+            must be between 0.0 and 1.0. For output formats that don't support device-specific
+            color space the CMYK value is converted to an sRGB value.
+          </p>
+        </section>
+      </section>
+      
     </section>
   </body>
 </document>
index 5bd9d145d0f8dbc5c2e176870c3c92796062379c..9444639a59fd603daa146c97044560650af352a7 100644 (file)
@@ -71,19 +71,31 @@ class ICCColorFunction extends FunctionBase {
         }
         String src = 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("Color values out of range. "
+                    + "Arguments to rgb-icc() must be [0..255] or [0%..100%]");
+        }
+        
         // rgb-icc is replaced with fop-rgb-icc which has an extra fifth 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-icc(");
-        for (int ix = 0; ix < args.length; ix++) {
+        sb.append(red / 255f);
+        sb.append(',').append(green / 255f);
+        sb.append(',').append(blue / 255f);
+        for (int ix = 3; ix < args.length; ix++) {
             if (ix == 3) {
                 sb.append(',').append(colorProfileName); 
                 sb.append(',').append(src); 
             } else {
-                if (ix > 0) {
-                    sb.append(',');
-                }
-                sb.append(args[ix]);
+                sb.append(',').append(args[ix]);
             }
         }
         sb.append(")");
index bb014b2af9c1bbfba124f9297a65db4dfc392b57..fbfc68c3654160d6bb5ffa3480d8f805782372e7 100644 (file)
@@ -26,6 +26,7 @@ import java.util.Map;
 
 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;
 
@@ -73,8 +74,8 @@ public final class ColorUtil {
      * <li>system-color(colorname)</li>
      * <li>transparent</li>
      * <li>colorname</li>
-     * <li>fop-rgb-icc</li>
-     * <li>cmyk</li>
+     * <li>fop-rgb-icc(r,g,b,cs,cs-src,[num]+) (r/g/b: 0..1, num: 0..1)</li>
+     * <li>cmyk(c,m,y,k) (0..1)</li>
      * </ul>
      * 
      * @param foUserAgent FOUserAgent object  
@@ -278,7 +279,7 @@ public final class ColorUtil {
                 //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;
+                blue = Integer.parseInt(value.substring(3, 4), 16) * 0X11;
             } else if ((len == 7) || (len == 9)) {
                 red = Integer.parseInt(value.substring(1, 3), 16);
                 green = Integer.parseInt(value.substring(3, 5), 16);
@@ -323,6 +324,12 @@ 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);
+                }
                 /* ICC profile arguments */
                 float[] iccComponents = new float[args.length - 5];
                 for (int ix = 4; ++ix < args.length;) {
@@ -336,25 +343,26 @@ public final class ColorUtil {
                 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());;
+                blue = Float.parseFloat(args[2].trim());
                 /* Verify rgb replacement arguments */
-                if ((red < 0 || red > 255
-                        || (green < 0 || green > 255
-                        || (blue < 0 || blue > 255)) {
+                if ((red < 0 || red > 1
+                        || (green < 0 || green > 1
+                        || (blue < 0 || blue > 1)) {
                     throw new PropertyException("Color values out of range. "
-                            + "Arguments to rgb-icc() must be [0..255] or [0%..100%]");
+                            + "Fallback RGB arguments to fop-rgb-icc() must be [0..1]");
                 }
 
                 if (colorSpace != null) {
                     // ColorSpace available - create ColorExt (keeps track of replacement rgb 
                     // values for possible later colorTOsRGBString call
-                    parsedColor = ColorExt.createFromFoRgbIcc(red/255, green/255, blue/255
+                    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((int)red, (int)green, (int)blue);
+                    parsedColor = new Color(Math.round(red * 255),
+                            Math.round(green * 255), Math.round(blue * 255));
                 }
             } catch (PropertyException pe) {
                 //simply re-throw
index 19d7d02664bae3a696a8f71f1c4bad21e64f3caf..86a3469ceb86b2a4d09a7aafa2651b28f21f7fc9 100644 (file)
@@ -24,10 +24,10 @@ import junit.framework.TestSuite;
 
 import org.apache.fop.pdf.PDFObjectTestCase;
 import org.apache.fop.traits.BorderPropsTestCase;
-import org.apache.fop.traits.TraitColorTestCase;
 import org.apache.fop.util.DataURIResolverTestCase;
 import org.apache.fop.util.ElementListUtilsTestCase;
 import org.apache.fop.util.PDFNumberTestCase;
+import org.apache.fop.util.ColorUtilTestCase;
 import org.apache.fop.util.UnitConvTestCase;
 
 /**
@@ -46,7 +46,7 @@ public class UtilityCodeTestSuite {
         suite.addTest(new TestSuite(PDFNumberTestCase.class));
         suite.addTest(new TestSuite(PDFObjectTestCase.class));
         suite.addTest(new TestSuite(UnitConvTestCase.class));
-        suite.addTest(new TestSuite(TraitColorTestCase.class));
+        suite.addTest(new TestSuite(ColorUtilTestCase.class));
         suite.addTest(new TestSuite(BorderPropsTestCase.class));
         suite.addTest(new TestSuite(ElementListUtilsTestCase.class));
         suite.addTest(new TestSuite(DataURIResolverTestCase.class));
diff --git a/test/java/org/apache/fop/traits/TraitColorTestCase.java b/test/java/org/apache/fop/traits/TraitColorTestCase.java
deleted file mode 100644 (file)
index 90f73dc..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.traits;
-
-import java.awt.Color;
-
-import junit.framework.TestCase;
-
-import org.apache.fop.util.ColorUtil;
-
-/**
- * Tests the Trait.Color class.
- * TODO: This actually tests the ColorUtil class now.
- */
-public class TraitColorTestCase extends TestCase {
-
-    /**
-     * Test serialization to String.
-     * @throws Exception if an error occurs
-     */
-    public void testSerialization() throws Exception {
-        Color col = new Color(1.0f, 1.0f, 0.5f, 1.0f);
-        String s = ColorUtil.colorToString(col);
-        
-        //This is what the old color spit out. Now it is 80 due to rounding 
-        //assertEquals("#ffff7f", s);
-        assertEquals("#ffff80", s);
-        
-        col = new Color(1.0f, 0.0f, 0.0f, 0.8f);
-        s = ColorUtil.colorToString(col);
-        assertEquals("#ff0000cc", s);
-    }
-    
-    /**
-     * Test deserialization from String.
-     * @throws Exception if an error occurs
-     */
-    public void testDeserialization() throws Exception {
-        Color col = ColorUtil.parseColorString(null, "#ffff7f");
-        assertEquals(255, col.getRed());
-        assertEquals(255, col.getGreen());
-        assertEquals(127, col.getBlue());
-        assertEquals(255, col.getAlpha());
-
-        col = ColorUtil.parseColorString(null, "#ff0000cc");
-        assertEquals(255, col.getRed());
-        assertEquals(0, col.getGreen());
-        assertEquals(0, col.getBlue());
-        assertEquals(204, col.getAlpha());
-    }
-    
-    /**
-     * Test equals().
-     * @throws Exception if an error occurs
-     */
-    public void testEquals() throws Exception {
-        Color col1 = ColorUtil.parseColorString(null, "#ff0000cc");
-        Color col2 = ColorUtil.parseColorString(null, "#ff0000cc");
-        assertEquals(col1, col2);
-    }
-    
-}
diff --git a/test/java/org/apache/fop/util/ColorUtilTestCase.java b/test/java/org/apache/fop/util/ColorUtilTestCase.java
new file mode 100644 (file)
index 0000000..bdeca43
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * 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 junit.framework.TestCase;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.apps.FopFactory;
+
+/**
+ * Tests the ColorUtil class.
+ */
+public class ColorUtilTestCase extends TestCase {
+
+    /**
+     * Test serialization to String.
+     * @throws Exception if an error occurs
+     */
+    public void testSerialization() throws Exception {
+        Color col = new Color(1.0f, 1.0f, 0.5f, 1.0f);
+        String s = ColorUtil.colorToString(col);
+        
+        //This is what the old color spit out. Now it is 80 due to rounding 
+        //assertEquals("#ffff7f", s);
+        assertEquals("#ffff80", s);
+        
+        col = new Color(1.0f, 0.0f, 0.0f, 0.8f);
+        s = ColorUtil.colorToString(col);
+        assertEquals("#ff0000cc", s);
+    }
+    
+    /**
+     * Test deserialization from String.
+     * @throws Exception if an error occurs
+     */
+    public void testDeserialization() throws Exception {
+        Color col = ColorUtil.parseColorString(null, "#ffff7f");
+        assertEquals(255, col.getRed());
+        assertEquals(255, col.getGreen());
+        assertEquals(127, col.getBlue());
+        assertEquals(255, col.getAlpha());
+
+        col = ColorUtil.parseColorString(null, "#ff0000cc");
+        assertEquals(255, col.getRed());
+        assertEquals(0, col.getGreen());
+        assertEquals(0, col.getBlue());
+        assertEquals(204, col.getAlpha());
+    }
+    
+    /**
+     * Test equals().
+     * @throws Exception if an error occurs
+     */
+    public void testEquals() throws Exception {
+        Color col1 = ColorUtil.parseColorString(null, "#ff0000cc");
+        Color col2 = ColorUtil.parseColorString(null, "#ff0000cc");
+        assertEquals(col1, col2);
+    }
+    
+    /**
+     * Tests the rgb() function.
+     * @throws Exception if an error occurs
+     */
+    public void testRGB() throws Exception {
+        FopFactory fopFactory = FopFactory.newInstance();
+        FOUserAgent ua = fopFactory.newFOUserAgent();
+        Color colActual;
+        
+        colActual = ColorUtil.parseColorString(ua, "rgb(255, 40, 0)");
+        assertEquals(255, colActual.getRed());
+        assertEquals(40, colActual.getGreen());
+        assertEquals(0, colActual.getBlue());
+        assertEquals(255, colActual.getAlpha());
+        assertEquals(ColorSpace.getInstance(ColorSpace.CS_sRGB), colActual.getColorSpace());
+    }
+    
+    /**
+     * Tests the fop-rgb-icc() function.
+     * @throws Exception if an error occurs
+     */
+    public void testRGBICC() throws Exception {
+        FopFactory fopFactory = FopFactory.newInstance();
+        ColorSpace cs = fopFactory.getColorSpace(null,
+                "src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm");
+        assertNotNull(cs);
+        
+        
+        FOUserAgent ua = fopFactory.newFOUserAgent();
+        ColorExt colActual;
+        
+        //fop-rgb-icc() is used instead of rgb-icc() inside FOP!
+        String colSpec = "fop-rgb-icc(1.0,0.0,0.0,sRGBAlt,"
+            + "\"src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm\",1.0,0.0,0.0)";
+        colActual = (ColorExt)ColorUtil.parseColorString(ua, colSpec);
+        //assertEquals(255, colActual.getRed()); //253 is returned
+        //assertEquals(24, colActual.getGreen()); //24 is returned
+        //I don't understand the difference. Maybe Java's sRGB and HP's sRGB are somehow not
+        //equivalent. This is only going to be a problem if anyone actually makes use of the
+        //RGB fallback in any renderer.
+        //TODO Anyone know what's going on here?
+        assertEquals(0, colActual.getBlue());
+        assertEquals(cs, colActual.getColorSpace());
+        float[] comps = colActual.getOriginalColorComponents();
+        assertEquals(3, comps.length);
+        assertEquals(1f, comps[0], 0);
+        assertEquals(0f, comps[1], 0);
+        assertEquals(0f, comps[2], 0);
+        
+        assertEquals(colSpec, ColorUtil.colorToString(colActual));
+
+        colSpec = "fop-rgb-icc(1.0,0.5,0.0,blah,"
+            + "\"invalid.icm\",1.0,0.5,0.0,0.15)";
+        Color colFallback = ColorUtil.parseColorString(ua, colSpec);
+        assertEquals(new Color(1.0f, 0.5f, 0.0f), colFallback);
+    }
+    
+    /**
+     * Tests the cmyk() function.
+     * @throws Exception if an error occurs
+     */
+    public void testCMYK() throws Exception {
+        ColorExt colActual;
+        String colSpec;
+        
+        colSpec = "cmyk(0.0, 0.0, 1.0, 0.0)";
+        colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec);
+        assertEquals(255, colActual.getRed());
+        assertEquals(255, colActual.getGreen());
+        assertEquals(0, colActual.getBlue());
+        assertEquals(CMYKColorSpace.getInstance(), colActual.getColorSpace());
+        float[] comps = colActual.getOriginalColorComponents();
+        assertEquals(4, comps.length);
+        assertEquals(0f, comps[0], 0);
+        assertEquals(0f, comps[1], 0);
+        assertEquals(1f, comps[2], 0);
+        assertEquals(0f, comps[3], 0);
+        assertEquals("cmyk(0.0,0.0,1.0,0.0)", ColorUtil.colorToString(colActual));
+        
+        colSpec = "cmyk(0.0274, 0.2196, 0.3216, 0.0)";
+        colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec);
+        assertEquals(248, colActual.getRed());
+        assertEquals(199, colActual.getGreen());
+        assertEquals(172, colActual.getBlue());
+        assertEquals(CMYKColorSpace.getInstance(), colActual.getColorSpace());
+        comps = colActual.getOriginalColorComponents();
+        assertEquals(0.0274f, comps[0], 0.001);
+        assertEquals(0.2196f, comps[1], 0.001);
+        assertEquals(0.3216f, comps[2], 0.001);
+        assertEquals(0f, comps[3], 0);
+        assertEquals("cmyk(0.0274,0.2196,0.3216,0.0)", ColorUtil.colorToString(colActual));
+    }
+    
+}
index 55ab47b0120b70d58454170101c02decb8e1bc80..0eb08f8b1404a56f773310bee8bd8cbf166e2d87 100644 (file)
@@ -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 background-color="rgb-icc(100%,0%,0%,sRGB,1,0.5,0)" />
+          <fo:region-body background-color="rgb-icc(100%,80%,80%,sRGB,1,0.8,0.8)" />
         </fo:simple-page-master>
       </fo:layout-master-set>
       <fo:declarations>
@@ -41,6 +41,9 @@
           <fo:block color="rgb-icc(100%,50%,0%, sRGB, 1, 0.5, 0)">color "rgb-icc(100%,50%,0%, sRGB, 1, 0.5, 0)"</fo:block>
           <fo:block color="rgb-icc(0%,100%,0%, unknown, 1, 0.5, 0)">color "rgb-icc(0%,100%,0%, unknown, 1, 0.5, 0)"</fo:block>
           <fo:block color="cmyk(0%,0%,20%,40%)">color "cmyk(0%,0%,20%,40%)" (Khaki)</fo:block>
+          <!-- NYI
+          <fo:block color="rgb-icc(153, 153, 102, #CMYK, 0, 0, 0.2, 0.4)">color "rgb-icc(153, 153, 102, #CMYK, 0, 0, 0.2, 0.4)" (Khaki)</fo:block>
+          -->
         </fo:flow>
       </fo:page-sequence>
     </fo:root>
@@ -49,7 +52,7 @@
     <!-- 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="color=#ffcccc" 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"/>