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>
}
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(")");
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;
* <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
//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);
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;) {
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
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;
/**
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));
+++ /dev/null
-/*
- * 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);
- }
-
-}
--- /dev/null
+/*
+ * 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));
+ }
+
+}
<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>
<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>
<!-- 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"/>