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-ffa450edef68pull/20/head
@@ -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); | |||
} | |||
} |
@@ -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 |
@@ -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); |
@@ -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; | |||
} |
@@ -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 | |||
*/ |
@@ -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; | |||
} | |||
} |
@@ -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(); |
@@ -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); | |||