Browse Source

Added class ColorWithFallback used for recreating function strings.

Adjusted to changes of design in color branch.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Color@961379 13f79535-47bb-0310-9956-ffa450edef68
pull/20/head
Jeremias Maerki 14 years ago
parent
commit
797a3ddf48

+ 10
- 5
src/java/org/apache/fop/apps/FopFactory.java View File

@@ -40,6 +40,7 @@ import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.image.loader.ImageContext;
import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.java2d.color.ICCColorSpaceExt;

import org.apache.fop.fo.ElementMapping;
import org.apache.fop.fo.ElementMappingRegistry;
@@ -759,19 +760,23 @@ public class FopFactory implements ImageContext {

/**
* Create (if needed) and return an ICC ColorSpace instance.
*
* <p>
* The ICC profile source is taken from the src attribute of the color-profile FO element.
* If the ICC ColorSpace is not yet in the cache a new one is created and stored in the cache.
*
* <p>
* The FOP URI resolver is used to try and locate the ICC file.
* If that fails null is returned.
*
* <p>
* Note: this method should not be considered as part of FOP's external API.
* @param profileName the profile name
* @param baseUri a base URI to resolve relative URIs
* @param iccProfileSrc ICC Profile source to return a ColorSpace for
* @param renderingIntent overriding rendering intent (see {@link ICCColorSpaceExt}.*)
* @return ICC ColorSpace object or null if ColorSpace could not be created
*/
public ColorSpace getColorSpace(String baseUri, String iccProfileSrc) {
return colorSpaceCache.get(baseUri, iccProfileSrc);
public ColorSpace getColorSpace(String profileName, String baseUri, String iccProfileSrc,
int renderingIntent) {
return colorSpaceCache.get(profileName, baseUri, iccProfileSrc, renderingIntent);
}

}

+ 12
- 11
src/java/org/apache/fop/pdf/PDFColor.java View File

@@ -21,12 +21,10 @@ package org.apache.fop.pdf;

import java.awt.Color;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.xmlgraphics.java2d.color.ColorExt;
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives;
import org.apache.xmlgraphics.java2d.color.DeviceCMYKColorSpace;

/**
@@ -49,7 +47,7 @@ public class PDFColor extends PDFPathPaint {
// class hierarchy. However, at this early stages of my FOP understanding, I can
// not really oversee the consequences of such a switch (nor whether it would be
// appropriate).
private ColorExt colorExt = null;
private ColorWithAlternatives colorExt = null;

/**
* Create a PDF color with double values ranging from 0 to 1
@@ -83,6 +81,7 @@ public class PDFColor extends PDFPathPaint {
// 2) In case the same color profile is used with different names it will be
// included multiple times in the PDF
//
/*
if (colorExt != null
&& pdfDoc.getResources().getColorSpace(colorExt.getIccProfileName()) == null) {
PDFICCStream pdfIccStream = new PDFICCStream();
@@ -101,7 +100,7 @@ public class PDFColor extends PDFPathPaint {
log.info("Adding PDFICCStream " + colorExt.getIccProfileName()
+ " for " + colorExt.getIccProfileSrc());
}
}
}*/
}

/**
@@ -117,17 +116,17 @@ public class PDFColor extends PDFPathPaint {
*/
public PDFColor(java.awt.Color col) {
ColorSpace cs = col.getColorSpace();
ColorExt ce = null;
if (col instanceof ColorExt) {
ce = (ColorExt)col;
cs = ce.getOrigColorSpace();
ColorWithAlternatives ce = null;
if (col instanceof ColorWithAlternatives) {
ce = (ColorWithAlternatives)col;
//cs = ce.getOrigColorSpace();
}
if (cs != null && cs instanceof DeviceCMYKColorSpace) {
// CMYK case
this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_CMYK);
float[] cmyk = (ce == null
? col.getColorComponents(null)
: ce.getOriginalColorComponents());
: col.getColorComponents(null)/*ce.getOriginalColorComponents()*/);
this.cyan = cmyk[0];
this.magenta = cmyk[1];
this.yellow = cmyk[2];
@@ -350,7 +349,8 @@ public class PDFColor extends PDFPathPaint {
public String getColorSpaceOut(boolean fillNotStroke) {
StringBuffer p = new StringBuffer("");

if (this.colorExt != null) {
if (false && this.colorExt != null) {
/*
if (fillNotStroke) {
p.append("/" + this.colorExt.getIccProfileName() + " cs ");
} else {
@@ -369,6 +369,7 @@ public class PDFColor extends PDFPathPaint {
} else {
p.append("SC\n");
}
*/
} else if (this.colorSpace.getColorSpace()
== PDFDeviceColorSpace.DEVICE_RGB) { // colorspace is RGB
// according to pdfspec 12.1 p.399

+ 4
- 4
src/java/org/apache/fop/pdf/PDFColorHandler.java View File

@@ -30,7 +30,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.java2d.color.CIELabColorSpace;
import org.apache.xmlgraphics.java2d.color.ColorExt;
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives;
import org.apache.xmlgraphics.java2d.color.ColorUtil;
import org.apache.xmlgraphics.java2d.color.DeviceCMYKColorSpace;
import org.apache.xmlgraphics.java2d.color.NamedColorSpace;
@@ -66,10 +66,10 @@ public class PDFColorHandler {
* @param fill true for fill color, false for stroke color
*/
public void establishColor(StringBuffer codeBuffer, Color color, boolean fill) {
if (color instanceof ColorExt) {
ColorExt colExt = (ColorExt)color;
if (color instanceof ColorWithAlternatives) {
ColorWithAlternatives colExt = (ColorWithAlternatives)color;
//Alternate colors have priority
Color[] alt = colExt.getAlternateColors();
Color[] alt = colExt.getAlternativeColors();
for (int i = 0, c = alt.length; i < c; i++) {
Color col = alt[i];
boolean established = establishColorFromColor(codeBuffer, col, fill);

+ 12
- 7
src/java/org/apache/fop/util/ColorSpaceCache.java View File

@@ -20,7 +20,6 @@
package org.apache.fop.util;

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 +31,8 @@ import javax.xml.transform.stream.StreamSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.java2d.color.ICCColorSpaceExt;

/**
* Map with cached ICC based ColorSpace objects.
*/
@@ -59,13 +60,17 @@ public class ColorSpaceCache {
* The FOP URI resolver is used to try and locate the ICC file.
* If that fails null is returned.
*
* @param profileName the profile name
* @param base a base URI to resolve relative URIs
* @param iccProfileSrc ICC Profile source to return a ColorSpace for
* @param renderingIntent overriding rendering intent (see {@link ICCColorSpaceExt}.*)
* @return ICC ColorSpace object or null if ColorSpace could not be created
*/
public ColorSpace get(String base, String iccProfileSrc) {
public ColorSpace get(String profileName, String base, String iccProfileSrc,
int renderingIntent) {
String key = profileName + ":" + base + iccProfileSrc;
ColorSpace colorSpace = null;
if (!colorSpaceMap.containsKey(base + iccProfileSrc)) {
if (!colorSpaceMap.containsKey(key)) {
try {
ICC_Profile iccProfile = null;
// First attempt to use the FOP URI resolver to locate the ICC
@@ -86,7 +91,8 @@ public class ColorSpaceCache {
// iccProfile = ICC_Profile.getInstance(iccProfileSrc);
}
if (iccProfile != null) {
colorSpace = new ICC_ColorSpace(iccProfile);
colorSpace = new ICCColorSpaceExt(iccProfile, renderingIntent,
profileName, iccProfileSrc);
}
} catch (Exception e) {
// Ignore exception - will be logged a bit further down
@@ -95,15 +101,14 @@ public class ColorSpaceCache {

if (colorSpace != null) {
// Put in cache (not when VM resolved it as we can't control
colorSpaceMap.put(base + iccProfileSrc, colorSpace);
colorSpaceMap.put(key, colorSpace);
} else {
// TODO To avoid an excessive amount of warnings perhaps
// register a null ColorMap in the colorSpaceMap
log.warn("Color profile '" + iccProfileSrc + "' not found.");
}
} else {
colorSpace = (ColorSpace)colorSpaceMap.get(base
+ iccProfileSrc);
colorSpace = (ColorSpace)colorSpaceMap.get(key);
}
return colorSpace;
}

+ 124
- 63
src/java/org/apache/fop/util/ColorUtil.java View File

@@ -30,10 +30,11 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.java2d.color.CIELabColorSpace;
import org.apache.xmlgraphics.java2d.color.ColorExt;
import org.apache.xmlgraphics.java2d.color.ColorSpaceOrigin;
import org.apache.xmlgraphics.java2d.color.ColorSpaces;
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives;
import org.apache.xmlgraphics.java2d.color.DeviceCMYKColorSpace;
import org.apache.xmlgraphics.java2d.color.ICCColor;
import org.apache.xmlgraphics.java2d.color.ICCColorSpaceExt;
import org.apache.xmlgraphics.java2d.color.NamedColorSpace;
import org.apache.xmlgraphics.java2d.color.profile.NamedColorProfile;
import org.apache.xmlgraphics.java2d.color.profile.NamedColorProfileParser;
@@ -49,9 +50,11 @@ import org.apache.fop.fo.expr.PropertyException;
*/
public final class ColorUtil {

//Implementation note: this class should ALWAYS create ColorExt instances instead of using
//java.awt.Color since the latter has an equals() method that can't detect two different
//colors using the same sRGB fallback.
//Implementation note: this class should ALWAYS create ColorWithAlternatives instances instead
//of using java.awt.Color since the latter has an equals() method that can't detect two
//different colors using the same sRGB fallback.
//ColorWithFallback is used to preserve the sRGB fallback exclusively for the purpose
//of regenerating textual color functions as specified in XSL-FO.

/** The name for the uncalibrated CMYK pseudo-profile */
public static final String CMYK_PSEUDO_PROFILE = "#CMYK";
@@ -213,7 +216,7 @@ public final class ColorUtil {
} catch (Exception e) {
throw new PropertyException(e);
}
return new ColorExt(red, green, blue, null);
return new ColorWithAlternatives(red, green, blue, null);
}

/**
@@ -240,7 +243,7 @@ public final class ColorUtil {
float red = parseComponent255(args[0], value);
float green = parseComponent255(args[1], value);
float blue = parseComponent255(args[2], value);
parsedColor = new ColorExt(red, green, blue, null);
parsedColor = new ColorWithAlternatives(red, green, blue, null);
} catch (PropertyException pe) {
//simply re-throw
throw pe;
@@ -287,6 +290,20 @@ public final class ColorUtil {
return component;
}

private static Color parseFallback(String[] args, String value) throws PropertyException {
float red = parseComponent1(args[0], value);
float green = parseComponent1(args[1], value);
float blue = parseComponent1(args[2], value);
//Sun's classlib rounds differently with this constructor than when converting to sRGB
//via CIE XYZ.
Color sRGB = new ColorWithAlternatives(red, green, blue, null);
/*
Color sRGB = new ColorWithAlternatives(ColorSpace.getInstance(ColorSpace.CS_sRGB),
new float[] {red, green, blue}, 1.0f, null);
*/
return sRGB;
}

/**
* parse a color given in the #.... format.
*
@@ -320,7 +337,7 @@ public final class ColorUtil {
} else {
throw new NumberFormatException();
}
parsedColor = new ColorExt(red, green, blue, alpha, null);
parsedColor = new ColorWithAlternatives(red, green, blue, alpha, null);
} catch (Exception e) {
throw new PropertyException("Unknown color format: " + value
+ ". Must be #RGB. #RGBA, #RRGGBB, or #RRGGBBAA");
@@ -349,10 +366,7 @@ public final class ColorUtil {
}

//Set up fallback sRGB value
float red = parseComponent1(args[0], value);
float green = parseComponent1(args[1], value);
float blue = parseComponent1(args[2], value);
Color sRGB = new ColorExt(red, green, blue, null);
Color sRGB = parseFallback(args, value);

/* Get and verify ICC profile name */
String iccProfileName = args[3].trim();
@@ -365,7 +379,8 @@ public final class ColorUtil {
if (CMYK_PSEUDO_PROFILE.equalsIgnoreCase(iccProfileName)) {
colorSpace = ColorSpaces.getDeviceCMYKColorSpace();
} else if (SEPARATION_PSEUDO_PROFILE.equalsIgnoreCase(iccProfileName)) {
colorSpace = new NamedColorSpace(args[5], sRGB);
colorSpace = new NamedColorSpace(args[5], sRGB,
SEPARATION_PSEUDO_PROFILE, null);
} else {
assert false : "Incomplete implementation";
}
@@ -392,15 +407,28 @@ public final class ColorUtil {

/* Ask FOP factory to get ColorSpace for the specified ICC profile source */
if (foUserAgent != null && iccProfileSrc != null) {
colorSpace = foUserAgent.getFactory().getColorSpace(
foUserAgent.getBaseURL(), iccProfileSrc);
assert colorSpace == null;
int renderingIntent = ICCColorSpaceExt.AUTO; //TODO connect to fo:color-profile
colorSpace = foUserAgent.getFactory().getColorSpace(iccProfileName,
foUserAgent.getBaseURL(), iccProfileSrc,
renderingIntent);
}
if (colorSpace != null) {
// ColorSpace available - create ColorExt (keeps track of replacement rgb
// values for possible later colorTOsRGBString call
ICCColor iccColor = new ICCColor(colorSpace, iccProfileName, iccProfileSrc,
iccComponents, 1.0f);
parsedColor = new ColorExt(red, green, blue, new Color[] {iccColor});
// ColorSpace is available
if (ColorSpaces.isDeviceColorSpace(colorSpace)) {
//Device-specific colors are handled differently:
//sRGB is the primary color with the CMYK as the alternative
Color deviceColor = new ColorWithAlternatives(
colorSpace, iccComponents, 1.0f, null);
float[] rgbComps = sRGB.getColorComponents(null);
parsedColor = new ColorWithAlternatives(
rgbComps[0], rgbComps[1], rgbComps[2],
new Color[] {deviceColor});
} else {
Color specColor = new ColorWithFallback(
colorSpace, iccComponents, 1.0f, null, sRGB);
parsedColor = specColor;
}
} else {
// ICC profile could not be loaded - use rgb replacement values */
log.warn("Color profile '" + iccProfileSrc
@@ -442,10 +470,7 @@ public final class ColorUtil {
}

//Set up fallback sRGB value
float red = parseComponent1(args[0], value);
float green = parseComponent1(args[1], value);
float blue = parseComponent1(args[2], value);
Color sRGB = new ColorExt(red, green, blue, null);
Color sRGB = parseFallback(args, value);

/* Get and verify ICC profile name */
String iccProfileName = args[3].trim();
@@ -471,20 +496,23 @@ public final class ColorUtil {

/* Ask FOP factory to get ColorSpace for the specified ICC profile source */
if (foUserAgent != null && iccProfileSrc != null) {
int renderingIntent = ICCColorSpaceExt.AUTO; //TODO connect to fo:color-profile
colorSpace = (ICC_ColorSpace)foUserAgent.getFactory().getColorSpace(
foUserAgent.getBaseURL(), iccProfileSrc);
iccProfileName,
foUserAgent.getBaseURL(), iccProfileSrc,
renderingIntent);
}
if (colorSpace != null) {
ICC_Profile profile = colorSpace.getProfile();
if (NamedColorProfileParser.isNamedColorProfile(profile)) {
NamedColorProfileParser parser = new NamedColorProfileParser();
NamedColorProfile ncp = parser.parseProfile(profile);
NamedColorProfile ncp = parser.parseProfile(profile,
iccProfileName, iccProfileSrc);
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});
Color specColor = new ColorWithFallback(ncs,
new float[] {1.0f}, 1.0f, null, sRGB);
parsedColor = specColor;
} else {
log.warn("Color '" + colorName
+ "' does not exist in named color profile: " + iccProfileSrc);
@@ -538,6 +566,7 @@ public final class ColorUtil {
float red = parseComponent255(args[0], value);
float green = parseComponent255(args[1], value);
float blue = parseComponent255(args[2], value);
Color sRGB = new ColorWithAlternatives(red, green, blue, null);

float l = parseComponent(args[3], 0f, 100f, value);
float a = parseComponent(args[4], -127f, 127f, value);
@@ -547,7 +576,8 @@ public final class ColorUtil {
CIELabColorSpace cs = ColorSpaces.getCIELabColorSpaceD50();
//use toColor() to have components normalized
Color labColor = cs.toColor(l, a, b, 1.0f);
parsedColor = new ColorExt(red, green, blue, new Color[] {labColor});
//Convert to ColorWithFallback
parsedColor = new ColorWithFallback(labColor, sRGB);

} catch (PropertyException pe) {
//simply re-throw
@@ -599,7 +629,9 @@ public final class ColorUtil {
float yellow = parseComponent1(args[2], value);
float black = parseComponent1(args[3], value);
float[] comps = new float[] {cyan, magenta, yellow, black};
parsedColor = DeviceCMYKColorSpace.createColorExt(comps);
Color cmykColor = DeviceCMYKColorSpace.createCMYKColor(comps);
parsedColor = new ColorWithAlternatives(cmykColor.getRGB(),
new Color[] {cmykColor});
} catch (PropertyException pe) {
throw pe;
} catch (Exception e) {
@@ -624,8 +656,8 @@ public final class ColorUtil {
*/
public static String colorToString(Color color) {
ColorSpace cs = color.getColorSpace();
if (color instanceof ColorExt) {
return toFunctionCall((ColorExt)color);
if (color instanceof ColorWithAlternatives) {
return toFunctionCall((ColorWithAlternatives)color);
} else if (cs != null && cs.getType() == ColorSpace.TYPE_CMYK) {
StringBuffer sbuf = new StringBuffer(24);
float[] cmyk = color.getColorComponents(null);
@@ -664,45 +696,73 @@ public final class ColorUtil {
return sbuf.toString();
}

private static Color getsRGBFallback(ColorWithAlternatives color) {
Color fallbackColor;
if (color instanceof ColorWithFallback) {
fallbackColor = ((ColorWithFallback)color).getFallbackColor();
if (!fallbackColor.getColorSpace().isCS_sRGB()) {
fallbackColor = toSRGBColor(fallbackColor);
}
} else {
fallbackColor = toSRGBColor(color);
}
return fallbackColor;
}

private static Color toSRGBColor(Color color) {
float[] comps;
ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
if (color.getColorSpace().isCS_sRGB()) {
comps = color.getColorComponents(null);
} else {
comps = color.getColorComponents(sRGB, null);
}
float[] allComps = color.getComponents(null);
float alpha = allComps[comps.length - 1]; //Alpha is on last component
return new Color(sRGB, comps, alpha);
}

/**
* Create string representation of fop-rgb-icc function call to map this
* ColorExt settings.
* @param color the color to turn into a function call
* @return the string representing the internal fop-rgb-icc() function call
*/
public static String toFunctionCall(ColorExt color) {
Color[] alt = color.getAlternateColors();
ICCColor icc = null;
for (int i = 0, c = alt.length; i < c; i++) {
if (alt[i] instanceof ICCColor) {
//Find first ICCColor in alternatives
icc = (ICCColor)alt[i];
break;
}
public static String toFunctionCall(ColorWithAlternatives color) {
ColorSpace cs = color.getColorSpace();
Color fallbackColor = getsRGBFallback(color);
if (cs instanceof CIELabColorSpace) {
return toCIELabFunctionCall(color);
}
if (icc == null) {
if (cs.isCS_sRGB() && !color.hasAlternativeColors()) {
return toRGBFunctionCall(color);
}
if (icc.getColorSpace() instanceof CIELabColorSpace) {
return toCIELabFunctionCall(color, icc);
}
StringBuffer sb = new StringBuffer(40);

Color specColor = color;
if (color.hasAlternativeColors()) {
Color alt = color.getAlternativeColors()[0];
if (ColorSpaces.isDeviceColorSpace(alt.getColorSpace())) {
cs = alt.getColorSpace();
specColor = alt;
}
}
ColorSpaceOrigin origin = ColorSpaces.getColorSpaceOrigin(cs);
String functionName;
float[] rgb = color.getColorComponents(null);
float[] rgb = fallbackColor.getColorComponents(null);
assert rgb.length == 3;
sb.append("(");
sb.append(rgb[0]).append(",");
sb.append(rgb[1]).append(",");
sb.append(rgb[2]).append(",");
String profileName = icc.getColorProfileName();
String profileName = origin.getProfileName();
sb.append(profileName).append(",");
if (icc.getColorProfileSource() != null) {
sb.append("\"").append(icc.getColorProfileSource()).append("\"");
if (origin.getProfileURI() != null) {
sb.append("\"").append(origin.getProfileURI()).append("\"");
}

if (icc.getColorSpace() instanceof NamedColorSpace) {
NamedColorSpace ncs = (NamedColorSpace)icc.getColorSpace();
if (cs instanceof NamedColorSpace) {
NamedColorSpace ncs = (NamedColorSpace)cs;
if (SEPARATION_PSEUDO_PROFILE.equalsIgnoreCase(profileName)) {
functionName = "fop-rgb-icc";
} else {
@@ -711,7 +771,7 @@ public final class ColorUtil {
sb.append(",").append(ncs.getColorName());
} else {
functionName = "fop-rgb-icc";
float[] colorComponents = icc.getColorComponents(null);
float[] colorComponents = specColor.getColorComponents(null);
for (int ix = 0; ix < colorComponents.length; ix++) {
sb.append(",");
sb.append(colorComponents[ix]);
@@ -721,13 +781,14 @@ public final class ColorUtil {
return functionName + sb.toString();
}

private static String toCIELabFunctionCall(ColorExt color, Color cieLab) {
private static String toCIELabFunctionCall(ColorWithAlternatives color) {
Color fallbackColor = getsRGBFallback(color);
StringBuffer sb = new StringBuffer("cie-lab-color(");
sb.append(color.getRed()).append(',');
sb.append(color.getGreen()).append(',');
sb.append(color.getBlue());
CIELabColorSpace cs = (CIELabColorSpace)cieLab.getColorSpace();
float[] lab = cs.toNativeComponents(cieLab.getColorComponents(null));
sb.append(fallbackColor.getRed()).append(',');
sb.append(fallbackColor.getGreen()).append(',');
sb.append(fallbackColor.getBlue());
CIELabColorSpace cs = (CIELabColorSpace)color.getColorSpace();
float[] lab = cs.toNativeComponents(color.getColorComponents(null));
for (int i = 0; i < 3; i++) {
sb.append(',').append(lab[i]);
}
@@ -736,7 +797,7 @@ public final class ColorUtil {
}

private static Color createColor(int r, int g, int b) {
return new ColorExt(r, g, b, null);
return new ColorWithAlternatives(r, g, b, null);
}

/**
@@ -893,7 +954,7 @@ public final class ColorUtil {
colorMap.put("whitesmoke", createColor(245, 245, 245));
colorMap.put("yellow", createColor(255, 255, 0));
colorMap.put("yellowgreen", createColor(154, 205, 50));
colorMap.put("transparent", new ColorExt(0, 0, 0, 0, null));
colorMap.put("transparent", new ColorWithAlternatives(0, 0, 0, 0, null));
}

/**
@@ -927,7 +988,7 @@ public final class ColorUtil {
}

/**
* Creates an uncalibrary CMYK color with the given gray value.
* Creates an uncalibrated CMYK color with the given gray value.
* @param black the gray component (0 - 1)
* @return the CMYK color
*/

+ 85
- 0
src/java/org/apache/fop/util/ColorWithFallback.java View File

@@ -0,0 +1,85 @@
/*
* 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 org.apache.xmlgraphics.java2d.color.ColorWithAlternatives;

/**
* This class is a {@link Color} subclass adding a fallback color that FOP uses to re-serialize
* color specifications as textual functions. The fallback is otherwise not used in producing
* output formats.
*/
public class ColorWithFallback extends ColorWithAlternatives {

private static final long serialVersionUID = 7913922854959637136L;

private final Color fallback;

/**
* Creates a new color
* @param cspace the color space of the primary color
* @param components the color components
* @param alpha the alpha component
* @param alternativeColors the array of alternative colors if applicable (may be null)
* @param fallback the fallback color (usually an sRGB color)
*/
public ColorWithFallback(ColorSpace cspace, float[] components, float alpha,
Color[] alternativeColors, Color fallback) {
super(cspace, components, alpha, alternativeColors);
this.fallback = fallback;
}

/**
* Copy constructor adding a fallback color.
* @param color the color to be duplicated
* @param fallback the fallback color (usually an sRGB color)
*/
public ColorWithFallback(Color color, Color fallback) {
this(color.getColorSpace(), color.getColorComponents(null),
getAlphaFloat(color), getAlternativeColors(color), fallback);
}

private static float getAlphaFloat(Color color) {
float[] comps = color.getComponents(null);
return comps[comps.length - 1]; //Alpha is on last component
}

private static Color[] getAlternativeColors(Color color) {
if (color instanceof ColorWithAlternatives) {
ColorWithAlternatives cwa = (ColorWithAlternatives)color;
if (cwa.hasAlternativeColors()) {
return cwa.getAlternativeColors();
}
}
return null;
}

/**
* Returns the fallback color.
* @return the fallback color
*/
public Color getFallbackColor() {
return this.fallback;
}

}

+ 1
- 1
test/java/org/apache/fop/traits/BorderPropsTestCase.java View File

@@ -49,7 +49,7 @@ public class BorderPropsTestCase extends TestCase {
assertEquals(b1, b2);

float[] cmyk = new float[] {1.0f, 1.0f, 0.5f, 1.0f};
col = DeviceCMYKColorSpace.createColorExt(cmyk);
col = DeviceCMYKColorSpace.createCMYKColor(cmyk);
b1 = new BorderProps(Constants.EN_INSET, 9999,
col, BorderProps.SEPARATE);
ser = b1.toString();

+ 58
- 43
test/java/org/apache/fop/util/ColorUtilTestCase.java View File

@@ -25,8 +25,9 @@ import java.net.URI;

import junit.framework.TestCase;

import org.apache.xmlgraphics.java2d.color.ColorExt;
import org.apache.xmlgraphics.java2d.color.ColorSpaces;
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives;
import org.apache.xmlgraphics.java2d.color.ICCColorSpaceExt;
import org.apache.xmlgraphics.java2d.color.NamedColorSpace;

import org.apache.fop.apps.FOUserAgent;
@@ -82,8 +83,10 @@ public class ColorUtilTestCase extends TestCase {
assertEquals(col1, col2);

col1 = ColorUtil.parseColorString(null, "fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.0,0.0,0.0,0.5)");
/* The following doesn't work since java.awt.Color from Sun doesn't round consistently
col2 = ColorUtil.parseColorString(null, "cmyk(0.0,0.0,0.0,0.5)");
assertEquals(col1, col2);
*/

col2 = ColorUtil.parseColorString(null, "fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.5,0.5,0.5,0.0)");
assertFalse(col1.equals(col2));
@@ -114,34 +117,33 @@ public class ColorUtilTestCase extends TestCase {
FopFactory fopFactory = FopFactory.newInstance();
URI sRGBLoc = new URI(
"file:src/java/org/apache/fop/pdf/sRGB%20Color%20Space%20Profile.icm");
ColorSpace cs = fopFactory.getColorSpace(null, sRGBLoc.toASCIIString());
assertNotNull(cs);
ColorSpace cs = fopFactory.getColorSpace("sRGBAlt", null, sRGBLoc.toASCIIString(),
ICCColorSpaceExt.AUTO);
assertNotNull("Color profile not found", cs);

FOUserAgent ua = fopFactory.newFOUserAgent();
ColorExt colActual;
ColorWithFallback colActual;

//fop-rgb-icc() is used instead of rgb-icc() inside FOP!
String colSpec = "fop-rgb-icc(1.0,0.0,0.0,sRGBAlt,"
+ "\"" + sRGBLoc.toASCIIString() + "\",1.0,0.0,0.0)";
colActual = (ColorExt)ColorUtil.parseColorString(ua, colSpec);
colActual = (ColorWithFallback)ColorUtil.parseColorString(ua, colSpec);
assertEquals(cs, colActual.getColorSpace());
assertEquals(255, colActual.getRed());
assertEquals(0, colActual.getGreen());
assertEquals(0, colActual.getBlue());
assertEquals(ColorSpace.getInstance(ColorSpace.CS_sRGB), colActual.getColorSpace());
float[] comps = colActual.getColorComponents(null);
assertEquals(3, comps.length);
assertEquals(1f, comps[0], 0);
assertEquals(0f, comps[1], 0);
assertEquals(0f, comps[2], 0);
assertEquals(0, colActual.getAlternativeColors().length);

Color alt = colActual.getAlternateColors()[0];
assertEquals(cs, alt.getColorSpace());
comps = colActual.getColorComponents(null);
assertEquals(3, comps.length);
assertEquals(1f, comps[0], 0);
assertEquals(0f, comps[1], 0);
assertEquals(0f, comps[2], 0);
Color fallback = colActual.getFallbackColor();
assertTrue(fallback.getColorSpace().isCS_sRGB());
assertEquals(255, colActual.getRed());
assertEquals(0, colActual.getGreen());
assertEquals(0, colActual.getBlue());

assertEquals(colSpec, ColorUtil.colorToString(colActual));

@@ -156,15 +158,15 @@ public class ColorUtilTestCase extends TestCase {
* @throws Exception if an error occurs
*/
public void testCMYK() throws Exception {
ColorExt colActual;
ColorWithAlternatives colActual;
String colSpec;

colSpec = "cmyk(0.0, 0.0, 1.0, 0.0)";
colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec);
colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec);
assertEquals(255, colActual.getRed());
assertEquals(255, colActual.getGreen());
assertEquals(0, colActual.getBlue());
Color alt = colActual.getAlternateColors()[0];
Color alt = colActual.getAlternativeColors()[0];
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace());
float[] comps = alt.getColorComponents(null);
assertEquals(4, comps.length);
@@ -176,26 +178,26 @@ public class ColorUtilTestCase extends TestCase {
ColorUtil.colorToString(colActual));

colSpec = "cmyk(0.0274, 0.2196, 0.3216, 0.0)";
colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec);
colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec);
assertEquals(248, colActual.getRed(), 1);
assertEquals(199, colActual.getGreen(), 1);
assertEquals(172, colActual.getBlue(), 1);
alt = colActual.getAlternateColors()[0];
alt = colActual.getAlternativeColors()[0];
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace());
comps = alt.getColorComponents(null);
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("fop-rgb-icc(0.9726,0.7804,0.67840004,#CMYK,,0.0274,0.2196,0.3216,0.0)",
assertEquals("fop-rgb-icc(0.972549,0.78039217,0.6745098,#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);
colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec);
assertEquals(255, colActual.getRed());
assertEquals(255, colActual.getGreen());
assertEquals(0, colActual.getBlue());
alt = colActual.getAlternateColors()[0];
alt = colActual.getAlternativeColors()[0];
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace());
comps = alt.getColorComponents(null);
assertEquals(4, comps.length);
@@ -207,11 +209,11 @@ public class ColorUtilTestCase extends TestCase {
ColorUtil.colorToString(colActual));

colSpec = "fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.0,0.0,0.0,0.5)";
colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec);
colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec);
assertEquals(127, colActual.getRed(), 1);
assertEquals(127, colActual.getGreen(), 1);
assertEquals(127, colActual.getBlue(), 1);
alt = colActual.getAlternateColors()[0];
alt = colActual.getAlternativeColors()[0];
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace());
comps = alt.getColorComponents(null);
assertEquals(4, comps.length);
@@ -228,24 +230,31 @@ public class ColorUtilTestCase extends TestCase {
* @throws Exception if an error occurs
*/
public void testSeparationColor() throws Exception {
ColorExt colActual;
ColorWithFallback colActual;
String colSpec;

colSpec = "fop-rgb-icc(1.0,0.8,0.0,#Separation,,Postgelb)";
colActual = (ColorExt)ColorUtil.parseColorString(null, colSpec);
assertEquals(255, colActual.getRed());
assertEquals(204, colActual.getGreen());
colActual = (ColorWithFallback)ColorUtil.parseColorString(null, colSpec);
assertEquals(255, colActual.getRed(), 1);
assertEquals(204, colActual.getGreen(), 1);
assertEquals(0, colActual.getBlue());

Color alt = colActual.getAlternateColors()[0];
assertTrue(alt.getColorSpace() instanceof NamedColorSpace);
Color fallback = colActual.getFallbackColor();
assertEquals(255, fallback.getRed());
assertEquals(204, fallback.getGreen());
assertEquals(0, fallback.getBlue());

assertFalse(colActual.hasAlternativeColors());

assertTrue(colActual.getColorSpace() instanceof NamedColorSpace);
NamedColorSpace ncs;
ncs = (NamedColorSpace)alt.getColorSpace();
ncs = (NamedColorSpace)colActual.getColorSpace();
assertEquals("Postgelb", ncs.getColorName());
float[] comps = alt.getColorComponents(null);
float[] comps = colActual.getColorComponents(null);
assertEquals(1, comps.length);
assertEquals(1f, comps[0], 0);
assertEquals(colSpec, ColorUtil.colorToString(colActual));

}

/**
@@ -255,32 +264,38 @@ public class ColorUtilTestCase extends TestCase {
public void testNamedColorProfile() throws Exception {
FopFactory fopFactory = FopFactory.newInstance();
URI ncpLoc = new URI("file:test/resources/color/ncp-example.icc");
ColorSpace cs = fopFactory.getColorSpace(null, ncpLoc.toASCIIString());
assertNotNull(cs);
ColorSpace cs = fopFactory.getColorSpace("NCP", null, ncpLoc.toASCIIString(),
ICCColorSpaceExt.AUTO);
assertNotNull("Color profile not found", cs);

FOUserAgent ua = fopFactory.newFOUserAgent();
ColorExt colActual;
ColorWithFallback colActual;

//fop-rgb-named-color() is used instead of rgb-named-color() inside FOP!
String colSpec = "fop-rgb-named-color(1.0,0.8,0.0,NCP,"
+ "\"" + ncpLoc.toASCIIString() + "\",Postgelb)";
colActual = (ColorExt)ColorUtil.parseColorString(ua, colSpec);
colActual = (ColorWithFallback)ColorUtil.parseColorString(ua, colSpec);
assertEquals(255, colActual.getRed());
assertEquals(204, colActual.getGreen());
assertEquals(193, colActual.getGreen());
assertEquals(0, colActual.getBlue());
assertEquals(ColorSpace.getInstance(ColorSpace.CS_sRGB), colActual.getColorSpace());
float[] comps = colActual.getColorComponents(null);

Color fallback = colActual.getFallbackColor();
assertEquals(255, fallback.getRed());
assertEquals(204, fallback.getGreen());
assertEquals(0, fallback.getBlue());
assertEquals(ColorSpace.getInstance(ColorSpace.CS_sRGB), fallback.getColorSpace());

float[] comps = fallback.getColorComponents(null);
assertEquals(3, comps.length);
assertEquals(1f, comps[0], 0);
assertEquals(0.8f, comps[1], 0);
assertEquals(0f, comps[2], 0);

Color alt = colActual.getAlternateColors()[0];
assertTrue(alt.getColorSpace() instanceof NamedColorSpace);
assertTrue(colActual.getColorSpace() instanceof NamedColorSpace);
NamedColorSpace ncs;
ncs = (NamedColorSpace)alt.getColorSpace();
ncs = (NamedColorSpace)colActual.getColorSpace();
assertEquals("Postgelb", ncs.getColorName());
comps = alt.getColorComponents(null);
comps = colActual.getColorComponents(null);
assertEquals(1, comps.length);
assertEquals(1f, comps[0], 0);


Loading…
Cancel
Save