Просмотр исходного кода

Added support for the #CMYK pseudo-profile supported by some commercial XSL implementations on the rgb-icc() function.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@815938 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_0
Jeremias Maerki 14 лет назад
Родитель
Сommit
19e71503b1

+ 17
- 0
src/documentation/content/xdocs/trunk/extensions.xml Просмотреть файл

@@ -226,6 +226,23 @@ to following pages. Here is an example of FO code creating such a table-header:<
color space the CMYK value is converted to an sRGB value.
</p>
</section>
<section id="pseudo-color-profiles">
<title>#CMYK pseudo-profile</title>
<p><code>color rgb-icc(numeric, numeric, numeric, #CMYK, numeric, numeric, numeric, numeric)</code></p>
<p>
The <code>rgb-icc</code> function will respond to a pseudo-profile called "#CMYK"
which indicates a device-specific CMYK color space. The "#CMYK" profile is implicitely
available and doesn't have to be (and cannot be) defined through an
<code>fo:color-profile</code> element. It is provided for compatibility with certain
commercial XSL-FO implementations. Please note that this is not part of the official
specification but rather a convention. The following two color specifications are
equivalent:
</p>
<ul>
<li><code>cmyk(0%,0%,20%,40%)</code></li>
<li><code>rgb-icc(153, 153, 102, #CMYK, 0, 0, 0.2, 0.4)</code></li>
</ul>
</section>
</section>
<section id="prepress">
<title>Prepress Support</title>

+ 8
- 5
src/java/org/apache/fop/fo/expr/ICCColorFunction.java Просмотреть файл

@@ -24,6 +24,7 @@ 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;
import org.apache.fop.util.ColorUtil;

/**
* Implements the rgb-icc() function.
@@ -63,13 +64,15 @@ class ICCColorFunction extends FunctionBase {
} else {
cp = decls.getColorProfile(colorProfileName);
if (cp == null) {
PropertyException pe = new PropertyException("The " + colorProfileName
+ " color profile was not declared");
pe.setPropertyInfo(pInfo);
throw pe;
if (!ColorUtil.isPseudoProfile(colorProfileName)) {
PropertyException pe = new PropertyException("The " + colorProfileName
+ " color profile was not declared");
pe.setPropertyInfo(pInfo);
throw pe;
}
}
}
String src = cp.getSrc();
String src = (cp != null ? cp.getSrc() : "");

float red = 0, green = 0, blue = 0;
red = args[0].getNumber().floatValue();

+ 14
- 5
src/java/org/apache/fop/fo/expr/PropertyTokenizer.java Просмотреть файл

@@ -243,15 +243,20 @@ class PropertyTokenizer {
}


private void nextColor () throws PropertyException {
private void nextColor() throws PropertyException {
if (exprIndex < exprLength
&& isHexDigit(expr.charAt(exprIndex))) {
++exprIndex;
scanHexDigits();
currentToken = TOK_COLORSPEC;
int len = exprIndex - currentTokenStartIndex - 1;
if (len % 3 == 0) {
currentToken = TOK_COLORSPEC;
} else {
scanRestOfName();
currentToken = TOK_NCNAME;
}
currentTokenValue = expr.substring(currentTokenStartIndex,
exprIndex);
// Probably should have some multiple of 3 for length!
return;
} else {
throw new PropertyException("illegal character '#'");
@@ -263,11 +268,15 @@ class PropertyTokenizer {
*/
private void scanName() {
if (exprIndex < exprLength && isNameStartChar(expr.charAt(exprIndex))) {
while (++exprIndex < exprLength
&& isNameChar(expr.charAt(exprIndex))) { }
scanRestOfName();
}
}

private void scanRestOfName() {
while (++exprIndex < exprLength
&& isNameChar(expr.charAt(exprIndex))) { }
}

/**
* Attempt to recognize a valid sequence of decimal DIGITS in the
* input expression.

+ 3
- 1
src/java/org/apache/fop/util/ColorExt.java Просмотреть файл

@@ -176,7 +176,9 @@ public final class ColorExt extends Color {
sb.append(this.rgbReplacementGreen + ",");
sb.append(this.rgbReplacementBlue + ",");
sb.append(this.iccProfileName + ",");
sb.append("\"" + this.iccProfileSrc + "\"");
if (this.iccProfileSrc != null) {
sb.append("\"" + this.iccProfileSrc + "\"");
}
float[] colorComponents = this.getColorComponents(null);
for (int ix = 0; ix < colorComponents.length; ix++) {
sb.append(",");

+ 63
- 18
src/java/org/apache/fop/util/ColorUtil.java Просмотреть файл

@@ -38,6 +38,9 @@ import org.apache.fop.fo.expr.PropertyException;
*/
public final class ColorUtil {

/** The name for the uncalibrated CMYK pseudo-profile */
public static final String CMYK_PSEUDO_PROFILE = "#CMYK";

/**
*
* keeps all the predefined and parsed colors.
@@ -319,26 +322,32 @@ public final class ColorUtil {
if (iccProfileName == null || "".equals(iccProfileName)) {
throw new PropertyException("ICC profile name missing");
}
/* Get and verify ICC profile source */
String iccProfileSrc = args[4].trim();
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);
ColorSpace colorSpace = null;
String iccProfileSrc = null;
if (isPseudoProfile(iccProfileName)) {
if (CMYK_PSEUDO_PROFILE.equalsIgnoreCase(iccProfileName)) {
colorSpace = CMYKColorSpace.getInstance();
} else {
assert false : "Incomplete implementation";
}
} else {
/* Get and verify ICC profile source */
iccProfileSrc = args[4].trim();
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;) {
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());
@@ -352,6 +361,11 @@ public final class ColorUtil {
+ "Fallback RGB arguments to fop-rgb-icc() must be [0..1]");
}

/* Ask FOP factory to get ColorSpace for the specified ICC profile source */
if (foUserAgent != null && iccProfileSrc != null) {
colorSpace = foUserAgent.getFactory().getColorSpace(
foUserAgent.getBaseURL(), iccProfileSrc);
}
if (colorSpace != null) {
// ColorSpace available - create ColorExt (keeps track of replacement rgb
// values for possible later colorTOsRGBString call
@@ -440,7 +454,7 @@ public final class ColorUtil {
CMYKColorSpace cmykCs = CMYKColorSpace.getInstance();
float[] rgb = cmykCs.toRGB(cmyk);
parsedColor = ColorExt.createFromFoRgbIcc(rgb[0], rgb[1], rgb[2],
null, "#CMYK", cmykCs, cmyk);
CMYK_PSEUDO_PROFILE, null, cmykCs, cmyk);
} catch (PropertyException pe) {
throw pe;
} catch (Exception e) {
@@ -465,13 +479,13 @@ public final class ColorUtil {
*/
public static String colorToString(Color color) {
ColorSpace cs = color.getColorSpace();
if (cs != null && cs.getType() == ColorSpace.TYPE_CMYK) {
if (color instanceof ColorExt) {
return ((ColorExt)color).toFunctionCall();
} 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 if (color instanceof ColorExt) {
return ((ColorExt)color).toFunctionCall();
} else {
StringBuffer sbuf = new StringBuffer();
sbuf.append('#');
@@ -681,4 +695,35 @@ public final class ColorUtil {
return new Color(cols[0], cols[1], cols[2], cols[3]);
}

/**
* Indicates whether the given color profile name is one of the pseudo-profiles supported
* by FOP (ex. #CMYK).
* @param colorProfileName the color profile name to check
* @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);
}

/**
* Indicates whether the color is a gray value.
* @param col the color
* @return true if it is a gray value
*/
public static boolean isGray(Color col) {
return (col.getRed() == col.getBlue() && col.getRed() == col.getGreen());
}

/**
* Creates an uncalibrary CMYK color with the given gray value.
* @param black the gray component (0 - 1)
* @return the CMYK color
*/
public static Color toCMYKGrayColor(float black) {
float[] cmyk = new float[] {0f, 0f, 0f, 1.0f - black};
CMYKColorSpace cmykCs = CMYKColorSpace.getInstance();
float[] rgb = cmykCs.toRGB(cmyk);
return ColorExt.createFromFoRgbIcc(rgb[0], rgb[1], rgb[2],
CMYK_PSEUDO_PROFILE, null, cmykCs, cmyk);
}
}

+ 4
- 0
status.xml Просмотреть файл

@@ -58,6 +58,10 @@
documents. Example: the fix of marks layering will be such a case when it's done.
-->
<release version="FOP Trunk" date="TBD">
<action context="Extensions" dev="JM" type="add">
Added support for the #CMYK pseudo-profile supported by some commercial XSL implementations
on the rgb-icc() function.
</action>
<action context="Layout" dev="VH" type="add" importance="high">
Added limited support for pages of different inline-progression-dimensions within a
page-sequence.

+ 19
- 2
test/java/org/apache/fop/util/ColorUtilTestCase.java Просмотреть файл

@@ -154,7 +154,8 @@ public class ColorUtilTestCase extends TestCase {
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));
assertEquals("fop-rgb-icc(1.0,1.0,0.0,#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);
@@ -167,7 +168,23 @@ public class ColorUtilTestCase extends TestCase {
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));
assertEquals("fop-rgb-icc(0.9726,0.7804,0.67840004,#CMYK,,0.0274,0.2196,0.3216,0.0)",
ColorUtil.colorToString(colActual));

colSpec = "fop-rgb-icc(1.0,1.0,0.0,#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());
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("fop-rgb-icc(1.0,1.0,0.0,#CMYK,,0.0,0.0,1.0,0.0)",
ColorUtil.colorToString(colActual));
}

}

+ 2
- 3
test/layoutengine/standard-testcases/color_1.xml Просмотреть файл

@@ -41,9 +41,7 @@
<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>
@@ -58,6 +56,7 @@
<eval expected="#ff8000" xpath="//block[3]//text/@color"/>
<eval expected="fop-rgb-icc(1.0,0.5,0.0,sRGB,&quot;../../../src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm&quot;,1.0,0.5,0.0)" xpath="//block[4]//text/@color"/>
<eval expected="#00ff00" xpath="//block[5]//text/@color"/>
<eval expected="cmyk(0.0,0.0,0.2,0.4)" xpath="//block[6]//text/@color"/>
<eval expected="fop-rgb-icc(0.6,0.6,0.48000002,#CMYK,,0.0,0.0,0.2,0.4)" xpath="//block[6]//text/@color"/>
<eval expected="fop-rgb-icc(0.6,0.6,0.48000002,#CMYK,,0.0,0.0,0.2,0.4)" xpath="//block[7]//text/@color"/>
</checks>
</testcase>

Загрузка…
Отмена
Сохранить