git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1069439 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_1rc1old
import java.awt.Color; | import java.awt.Color; | ||||
import java.awt.color.ColorSpace; | import java.awt.color.ColorSpace; | ||||
import java.io.DataOutput; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import org.apache.commons.io.output.ByteArrayOutputStream; | |||||
import org.apache.xmlgraphics.java2d.color.CIELabColorSpace; | |||||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||||
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; | |||||
/** | /** | ||||
* Sets the current processing color for the following GOCA structured fields | * Sets the current processing color for the following GOCA structured fields | ||||
*/ | */ | ||||
* X'08' CIELAB | * X'08' CIELAB | ||||
* X'40' Standard OCA color space | * X'40' Standard OCA color space | ||||
*/ | */ | ||||
private static final byte RGB = 0x01, CMYK = 0x04; | |||||
private static final byte RGB = 0x01, CMYK = 0x04, CIELAB = 0x08; | |||||
private final Color color; | private final Color color; | ||||
private final float[] colorComponents; | |||||
private final int componentsSize; | |||||
/** | /** | ||||
* Main constructor | * Main constructor | ||||
* | * | ||||
* @param color | |||||
* the color to set | |||||
* @param color the color to set | |||||
*/ | */ | ||||
public GraphicsSetProcessColor(Color color) { | public GraphicsSetProcessColor(Color color) { | ||||
this.color = color; | |||||
this.colorComponents = color.getColorComponents(null); | |||||
if (color instanceof ColorWithAlternatives) { | |||||
ColorWithAlternatives cwa = (ColorWithAlternatives)color; | |||||
Color alt = cwa.getFirstAlternativeOfType(ColorSpace.TYPE_CMYK); | |||||
if (alt != null) { | |||||
this.color = alt; | |||||
this.componentsSize = 4; | |||||
return; | |||||
} | |||||
} | |||||
ColorSpace cs = color.getColorSpace(); | |||||
int colSpaceType = cs.getType(); | |||||
if (colSpaceType == ColorSpace.TYPE_CMYK) { | |||||
this.color = color; | |||||
} else if (cs instanceof CIELabColorSpace) { | |||||
//TODO Convert between illuminants if not D50 according to rendering intents | |||||
//Right now, we're assuming D50 as the GOCA spec requires. | |||||
this.color = color; | |||||
//16bit components didn't work, and 8-bit sadly has reduced accuracy. | |||||
} else { | |||||
if (!color.getColorSpace().isCS_sRGB()) { | |||||
this.color = ColorUtil.toSRGBColor(color); | |||||
} else { | |||||
this.color = color; | |||||
} | |||||
} | |||||
this.componentsSize = this.color.getColorSpace().getNumComponents(); | |||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public int getDataLength() { | public int getDataLength() { | ||||
return 12 + colorComponents.length; | |||||
return 12 + this.componentsSize; | |||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
byte getOrderCode() { | byte getOrderCode() { | ||||
return (byte) 0xB2; | return (byte) 0xB2; | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public void writeToStream(OutputStream os) throws IOException { | public void writeToStream(OutputStream os) throws IOException { | ||||
float[] colorComponents = color.getColorComponents(null); | |||||
// COLSPCE | // COLSPCE | ||||
byte colspace; | byte colspace; | ||||
int colSpaceType = color.getColorSpace().getType(); | |||||
ColorSpace cs = color.getColorSpace(); | |||||
int colSpaceType = cs.getType(); | |||||
ByteArrayOutputStream baout = new ByteArrayOutputStream(); | |||||
byte[] colsizes; | |||||
if (colSpaceType == ColorSpace.TYPE_CMYK) { | if (colSpaceType == ColorSpace.TYPE_CMYK) { | ||||
colspace = CMYK; | colspace = CMYK; | ||||
colsizes = new byte[] {0x08, 0x08, 0x08, 0x08}; | |||||
for (int i = 0; i < colorComponents.length; i++) { | |||||
baout.write(Math.round(colorComponents[i] * 255)); | |||||
} | |||||
} else if (colSpaceType == ColorSpace.TYPE_RGB) { | } else if (colSpaceType == ColorSpace.TYPE_RGB) { | ||||
colspace = RGB; | colspace = RGB; | ||||
colsizes = new byte[] {0x08, 0x08, 0x08, 0x00}; | |||||
for (int i = 0; i < colorComponents.length; i++) { | |||||
baout.write(Math.round(colorComponents[i] * 255)); | |||||
} | |||||
} else if (cs instanceof CIELabColorSpace) { | |||||
colspace = CIELAB; | |||||
colsizes = new byte[] {0x08, 0x08, 0x08, 0x00}; | |||||
DataOutput dout = new java.io.DataOutputStream(baout); | |||||
//According to GOCA, I'd expect the multiplicator below to be 255f, not 100f | |||||
//But only IBM AFP Workbench seems to support Lab colors and it requires "c * 100f" | |||||
int l = Math.round(colorComponents[0] * 100f); | |||||
int a = Math.round(colorComponents[1] * 255f) - 128; | |||||
int b = Math.round(colorComponents[2] * 255f) - 128; | |||||
dout.writeByte(l); | |||||
dout.writeByte(a); | |||||
dout.writeByte(b); | |||||
} else { | } else { | ||||
LOG.error("unsupported colorspace " + colSpaceType); | |||||
colspace = RGB; | |||||
} | |||||
// COLSIZE(S) | |||||
byte[] colsizes = new byte[] {0x00, 0x00, 0x00, 0x00}; | |||||
for (int i = 0; i < colorComponents.length; i++) { | |||||
colsizes[i] = (byte) 8; | |||||
throw new IllegalStateException(); | |||||
} | } | ||||
int len = getDataLength(); | int len = getDataLength(); | ||||
byte[] data = new byte[len]; | |||||
byte[] data = new byte[12]; | |||||
data[0] = getOrderCode(); // GSPCOL order code | data[0] = getOrderCode(); // GSPCOL order code | ||||
data[1] = (byte) (len - 2); // LEN | data[1] = (byte) (len - 2); // LEN | ||||
data[2] = 0x00; // reserved; must be zero | data[2] = 0x00; // reserved; must be zero | ||||
data[10] = colsizes[2]; | data[10] = colsizes[2]; | ||||
data[11] = colsizes[3]; | data[11] = colsizes[3]; | ||||
// COLVALUE(S) | |||||
for (int i = 0; i < colorComponents.length; i++) { | |||||
data[i + 12] = (byte) (colorComponents[i] * 255); | |||||
} | |||||
os.write(data); | os.write(data); | ||||
baout.writeTo(os); | |||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public String toString() { | public String toString() { | ||||
return "GraphicsSetProcessColor(col=" + color + ")"; | return "GraphicsSetProcessColor(col=" + color + ")"; | ||||
} | } |
import java.util.List; | import java.util.List; | ||||
import org.apache.xmlgraphics.java2d.color.ColorConverter; | import org.apache.xmlgraphics.java2d.color.ColorConverter; | ||||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||||
import org.apache.fop.afp.AFPDataObjectInfo; | import org.apache.fop.afp.AFPDataObjectInfo; | ||||
import org.apache.fop.afp.AFPObjectAreaInfo; | import org.apache.fop.afp.AFPObjectAreaInfo; | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void setViewport(AFPDataObjectInfo dataObjectInfo) { | public void setViewport(AFPDataObjectInfo dataObjectInfo) { | ||||
super.setViewport(dataObjectInfo); | super.setViewport(dataObjectInfo); | ||||
* @param color the active color to use | * @param color the active color to use | ||||
*/ | */ | ||||
public void setColor(Color color) { | public void setColor(Color color) { | ||||
if (!color.equals(graphicsState.color)) { | |||||
if (!ColorUtil.isSameColor(color, graphicsState.color)) { | |||||
addObject(new GraphicsSetProcessColor(colorConverter.convert(color))); | addObject(new GraphicsSetProcessColor(colorConverter.convert(color))); | ||||
graphicsState.color = color; | graphicsState.color = color; | ||||
} | } | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public String toString() { | public String toString() { | ||||
return "GraphicsObject: " + getName(); | return "GraphicsObject: " + getName(); | ||||
} | } | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void setComplete(boolean complete) { | public void setComplete(boolean complete) { | ||||
Iterator it = objects.iterator(); | Iterator it = objects.iterator(); | ||||
while (it.hasNext()) { | while (it.hasNext()) { | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
protected void writeStart(OutputStream os) throws IOException { | protected void writeStart(OutputStream os) throws IOException { | ||||
super.writeStart(os); | super.writeStart(os); | ||||
byte[] data = new byte[17]; | byte[] data = new byte[17]; | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
protected void writeContent(OutputStream os) throws IOException { | protected void writeContent(OutputStream os) throws IOException { | ||||
super.writeContent(os); | super.writeContent(os); | ||||
writeObjects(objects, os); | writeObjects(objects, os); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
protected void writeEnd(OutputStream os) throws IOException { | protected void writeEnd(OutputStream os) throws IOException { | ||||
byte[] data = new byte[17]; | byte[] data = new byte[17]; | ||||
copySF(data, Type.END, Category.GRAPHICS); | copySF(data, Type.END, Category.GRAPHICS); |
import org.apache.commons.io.output.ByteArrayOutputStream; | import org.apache.commons.io.output.ByteArrayOutputStream; | ||||
import org.apache.xmlgraphics.java2d.color.CIELabColorSpace; | |||||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||||
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; | |||||
/** | /** | ||||
* Generator class for PTOCA data structures. | * Generator class for PTOCA data structures. | ||||
*/ | */ | ||||
* @throws IOException if an I/O error occurs | * @throws IOException if an I/O error occurs | ||||
*/ | */ | ||||
public void setExtendedTextColor(Color col) throws IOException { | public void setExtendedTextColor(Color col) throws IOException { | ||||
if (col.equals(currentColor)) { | |||||
if (ColorUtil.isSameColor(col, currentColor)) { | |||||
return; | return; | ||||
} | } | ||||
if (col instanceof ColorWithAlternatives) { | |||||
ColorWithAlternatives cwa = (ColorWithAlternatives)col; | |||||
Color alt = cwa.getFirstAlternativeOfType(ColorSpace.TYPE_CMYK); | |||||
if (alt != null) { | |||||
col = alt; | |||||
} | |||||
} | |||||
ColorSpace cs = col.getColorSpace(); | |||||
newControlSequence(); | newControlSequence(); | ||||
if (col.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { | if (col.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { | ||||
writeByte(0x00); // Reserved; must be zero | writeByte(0x00); // Reserved; must be zero | ||||
int component = Math.round(comps[i] * 255); | int component = Math.round(comps[i] * 255); | ||||
writeByte(component); | writeByte(component); | ||||
} | } | ||||
} else if (cs instanceof CIELabColorSpace) { | |||||
writeByte(0x00); // Reserved; must be zero | |||||
writeByte(0x08); // Color space - 0x08 = CIELAB | |||||
writeByte(0x00); // Reserved; must be zero | |||||
writeByte(0x00); // Reserved; must be zero | |||||
writeByte(0x00); // Reserved; must be zero | |||||
writeByte(0x00); // Reserved; must be zero | |||||
writeByte(8); // Number of bits in component 1 | |||||
writeByte(8); // Number of bits in component 2 | |||||
writeByte(8); // Number of bits in component 3 | |||||
writeByte(0); // Number of bits in component 4 | |||||
//Sadly, 16 bit components don't seem to work | |||||
float[] colorComponents = col.getColorComponents(null); | |||||
int l = Math.round(colorComponents[0] * 255f); | |||||
int a = Math.round(colorComponents[1] * 255f) - 128; | |||||
int b = Math.round(colorComponents[2] * 255f) - 128; | |||||
writeByte(l); // L* | |||||
writeByte(a); // a* | |||||
writeByte(b); // b* | |||||
} else { | } else { | ||||
writeByte(0x00); // Reserved; must be zero | writeByte(0x00); // Reserved; must be zero | ||||
writeByte(0x01); // Color space - 0x01 = RGB | writeByte(0x01); // Color space - 0x01 = RGB |
package org.apache.fop.apps; | package org.apache.fop.apps; | ||||
import java.awt.color.ColorSpace; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
/** Optional overriding LayoutManagerMaker */ | /** Optional overriding LayoutManagerMaker */ | ||||
private LayoutManagerMaker lmMakerOverride = null; | private LayoutManagerMaker lmMakerOverride = null; | ||||
private Set ignoredNamespaces; | |||||
private Set<String> ignoredNamespaces; | |||||
private FOURIResolver foURIResolver; | private FOURIResolver foURIResolver; | ||||
this.fontManager = new FontManager() { | this.fontManager = new FontManager() { | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void setFontBaseURL(String fontBase) throws MalformedURLException { | public void setFontBaseURL(String fontBase) throws MalformedURLException { | ||||
super.setFontBaseURL(getFOURIResolver().checkBaseURL(fontBase)); | super.setFontBaseURL(getFOURIResolver().checkBaseURL(fontBase)); | ||||
} | } | ||||
this.rendererFactory = new RendererFactory(); | this.rendererFactory = new RendererFactory(); | ||||
this.xmlHandlers = new XMLHandlerRegistry(); | this.xmlHandlers = new XMLHandlerRegistry(); | ||||
this.imageHandlers = new ImageHandlerRegistry(); | this.imageHandlers = new ImageHandlerRegistry(); | ||||
this.ignoredNamespaces = new java.util.HashSet(); | |||||
this.ignoredNamespaces = new java.util.HashSet<String>(); | |||||
} | } | ||||
/** | /** | ||||
* @throws MalformedURLException if there's a problem with a file URL | * @throws MalformedURLException if there's a problem with a file URL | ||||
* @deprecated use getFontManager().setFontBaseURL(fontBase) instead | * @deprecated use getFontManager().setFontBaseURL(fontBase) instead | ||||
*/ | */ | ||||
@Deprecated | |||||
public void setFontBaseURL(String fontBase) throws MalformedURLException { | public void setFontBaseURL(String fontBase) throws MalformedURLException { | ||||
getFontManager().setFontBaseURL(fontBase); | getFontManager().setFontBaseURL(fontBase); | ||||
} | } | ||||
* @return the font base URL | * @return the font base URL | ||||
* @deprecated use getFontManager().setFontBaseURL(fontBase) instead | * @deprecated use getFontManager().setFontBaseURL(fontBase) instead | ||||
*/ | */ | ||||
@Deprecated | |||||
public String getFontBaseURL() { | public String getFontBaseURL() { | ||||
return getFontManager().getFontBaseURL(); | return getFontManager().getFontBaseURL(); | ||||
} | } | ||||
* @return true if kerning on base 14 fonts is enabled | * @return true if kerning on base 14 fonts is enabled | ||||
* @deprecated use getFontManager().isBase14KerningEnabled() instead | * @deprecated use getFontManager().isBase14KerningEnabled() instead | ||||
*/ | */ | ||||
@Deprecated | |||||
public boolean isBase14KerningEnabled() { | public boolean isBase14KerningEnabled() { | ||||
return getFontManager().isBase14KerningEnabled(); | return getFontManager().isBase14KerningEnabled(); | ||||
} | } | ||||
* @param value true if kerning should be activated | * @param value true if kerning should be activated | ||||
* @deprecated use getFontManager().setBase14KerningEnabled(boolean) instead | * @deprecated use getFontManager().setBase14KerningEnabled(boolean) instead | ||||
*/ | */ | ||||
@Deprecated | |||||
public void setBase14KerningEnabled(boolean value) { | public void setBase14KerningEnabled(boolean value) { | ||||
getFontManager().setBase14KerningEnabled(value); | getFontManager().setBase14KerningEnabled(value); | ||||
} | } | ||||
* namespace is in the ignored set. | * namespace is in the ignored set. | ||||
* @param namespaceURIs the namespace URIs | * @param namespaceURIs the namespace URIs | ||||
*/ | */ | ||||
public void ignoreNamespaces(Collection namespaceURIs) { | |||||
public void ignoreNamespaces(Collection<String> namespaceURIs) { | |||||
this.ignoredNamespaces.addAll(namespaceURIs); | this.ignoredNamespaces.addAll(namespaceURIs); | ||||
} | } | ||||
} | } | ||||
/** @return the set of namespaces that are ignored by FOP */ | /** @return the set of namespaces that are ignored by FOP */ | ||||
public Set getIgnoredNamespace() { | |||||
public Set<String> getIgnoredNamespace() { | |||||
return Collections.unmodifiableSet(this.ignoredNamespaces); | return Collections.unmodifiableSet(this.ignoredNamespaces); | ||||
} | } | ||||
* @param useCache use cache or not | * @param useCache use cache or not | ||||
* @deprecated use getFontManager().setUseCache(boolean) instead | * @deprecated use getFontManager().setUseCache(boolean) instead | ||||
*/ | */ | ||||
@Deprecated | |||||
public void setUseCache(boolean useCache) { | public void setUseCache(boolean useCache) { | ||||
getFontManager().setUseCache(useCache); | getFontManager().setUseCache(useCache); | ||||
} | } | ||||
* @return whether this factory is uses the cache | * @return whether this factory is uses the cache | ||||
* @deprecated use getFontManager().useCache() instead | * @deprecated use getFontManager().useCache() instead | ||||
*/ | */ | ||||
@Deprecated | |||||
public boolean useCache() { | public boolean useCache() { | ||||
return getFontManager().useCache(); | return getFontManager().useCache(); | ||||
} | } | ||||
* @return the font cache | * @return the font cache | ||||
* @deprecated use getFontManager().getFontCache() instead | * @deprecated use getFontManager().getFontCache() instead | ||||
*/ | */ | ||||
@Deprecated | |||||
public FontCache getFontCache() { | public FontCache getFontCache() { | ||||
return getFontManager().getFontCache(); | return getFontManager().getFontCache(); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Create (if needed) and return an ICC ColorSpace instance. | |||||
* | |||||
* 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. | |||||
* | |||||
* The FOP URI resolver is used to try and locate the ICC file. | |||||
* If that fails null is returned. | |||||
* | |||||
* @param baseUri a base URI to resolve relative URIs | |||||
* @param iccProfileSrc ICC Profile source to return a ColorSpace for | |||||
* @return ICC ColorSpace object or null if ColorSpace could not be created | |||||
* Returns the color space cache for this instance. | |||||
* <p> | |||||
* Note: this method should not be considered as part of FOP's external API. | |||||
* @return the color space cache | |||||
*/ | */ | ||||
public ColorSpace getColorSpace(String baseUri, String iccProfileSrc) { | |||||
return colorSpaceCache.get(baseUri, iccProfileSrc); | |||||
public ColorSpaceCache getColorSpaceCache() { | |||||
return this.colorSpaceCache; | |||||
} | } | ||||
} | } |
/* | |||||
* 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.fo.expr; | |||||
import org.apache.fop.apps.FOUserAgent; | |||||
import org.apache.fop.datatypes.PercentBase; | |||||
import org.apache.fop.datatypes.PercentBaseContext; | |||||
import org.apache.fop.fo.properties.ColorProperty; | |||||
import org.apache.fop.fo.properties.Property; | |||||
/** | |||||
* Implements the cie-lab-color() function. | |||||
* @since XSL-FO 2.0 | |||||
*/ | |||||
class CIELabColorFunction extends FunctionBase { | |||||
/** | |||||
* cie-lab-color() takes 2 times 3 arguments. | |||||
* {@inheritDoc} | |||||
*/ | |||||
public int nbArgs() { | |||||
return 2 * 3; | |||||
} | |||||
public PercentBase getPercentBase() { | |||||
return new CIELabPercentBase(); | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public Property eval(Property[] args, | |||||
PropertyInfo pInfo) throws PropertyException { | |||||
float red = args[0].getNumber().floatValue(); | |||||
float green = args[1].getNumber().floatValue(); | |||||
float blue = args[2].getNumber().floatValue(); | |||||
/* Verify sRGB replacement arguments */ | |||||
if ((red < 0 || red > 255) | |||||
|| (green < 0 || green > 255) | |||||
|| (blue < 0 || blue > 255)) { | |||||
throw new PropertyException("sRGB color values out of range. " | |||||
+ "Arguments to cie-lab-color() must be [0..255] or [0%..100%]"); | |||||
} | |||||
float l = args[3].getNumber().floatValue(); | |||||
float a = args[4].getNumber().floatValue(); | |||||
float b = args[5].getNumber().floatValue(); | |||||
if (l < 0 || l > 100) { | |||||
throw new PropertyException("L* value out of range. Valid range: [0..100]"); | |||||
} | |||||
if (a < -127 || a > 127 || b < -127 || b > 127) { | |||||
throw new PropertyException("a* and b* values out of range. Valid range: [-127..+127]"); | |||||
} | |||||
StringBuffer sb = new StringBuffer(); | |||||
sb.append("cie-lab-color(" + red + "," + green + "," + blue + "," | |||||
+ l + "," + a + "," + b + ")"); | |||||
FOUserAgent ua = (pInfo == null) | |||||
? null | |||||
: (pInfo.getFO() == null ? null : pInfo.getFO().getUserAgent()); | |||||
return ColorProperty.getInstance(ua, sb.toString()); | |||||
} | |||||
private static class CIELabPercentBase implements PercentBase { | |||||
public int getDimension() { | |||||
return 0; | |||||
} | |||||
public double getBaseValue() { | |||||
return 1.0f; | |||||
} | |||||
public int getBaseLength(PercentBaseContext context) { | |||||
return 0; | |||||
} | |||||
} | |||||
} |
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
/* $Id$ */ | |||||
package org.apache.fop.fo.expr; | |||||
import org.apache.fop.datatypes.PercentBase; | |||||
import org.apache.fop.datatypes.PercentBaseContext; | |||||
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; | |||||
/** | |||||
* Implements the rgb-named-color() function. | |||||
* @since XSL-FO 2.0 | |||||
*/ | |||||
class NamedColorFunction extends FunctionBase { | |||||
/** | |||||
* rgb-named-color() takes a 5 arguments. | |||||
* {@inheritDoc} | |||||
*/ | |||||
public int nbArgs() { | |||||
return 5; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public PercentBase getPercentBase() { | |||||
return new NamedPercentBase(); | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public Property eval(Property[] args, | |||||
PropertyInfo pInfo) throws PropertyException { | |||||
// Map color profile NCNAME to src from declarations/color-profile element | |||||
String colorProfileName = args[3].getString(); | |||||
String colorName = args[4].getString(); | |||||
Declarations decls = pInfo.getFO().getRoot().getDeclarations(); | |||||
ColorProfile cp = null; | |||||
if (decls != null) { | |||||
cp = decls.getColorProfile(colorProfileName); | |||||
} | |||||
if (cp == null) { | |||||
PropertyException pe = new PropertyException("The " + colorProfileName | |||||
+ " color profile was not declared"); | |||||
pe.setPropertyInfo(pInfo); | |||||
throw pe; | |||||
} | |||||
String src = (cp != null ? 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("sRGB color values out of range. " | |||||
+ "Arguments to rgb-named-color() must be [0..255] or [0%..100%]"); | |||||
} | |||||
// rgb-named-color is replaced with fop-rgb-named-color which has an extra 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-named-color("); | |||||
sb.append(red / 255f); | |||||
sb.append(',').append(green / 255f); | |||||
sb.append(',').append(blue / 255f); | |||||
sb.append(',').append(colorProfileName); | |||||
sb.append(',').append(src); | |||||
sb.append(", '").append(colorName).append('\''); | |||||
sb.append(")"); | |||||
return ColorProperty.getInstance(pInfo.getUserAgent(), sb.toString()); | |||||
} | |||||
private static final class NamedPercentBase implements PercentBase { | |||||
/** {@inheritDoc} */ | |||||
public int getBaseLength(PercentBaseContext context) throws PropertyException { | |||||
return 0; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public double getBaseValue() { | |||||
return 255f; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public int getDimension() { | |||||
return 0; | |||||
} | |||||
} | |||||
} |
FUNCTION_TABLE.put("label-end", new LabelEndFunction()); | FUNCTION_TABLE.put("label-end", new LabelEndFunction()); | ||||
FUNCTION_TABLE.put("body-start", new BodyStartFunction()); | FUNCTION_TABLE.put("body-start", new BodyStartFunction()); | ||||
FUNCTION_TABLE.put("rgb-icc", new ICCColorFunction()); | FUNCTION_TABLE.put("rgb-icc", new ICCColorFunction()); | ||||
FUNCTION_TABLE.put("rgb-named-color", new NamedColorFunction()); //since XSL-FO 2.0 | |||||
FUNCTION_TABLE.put("cie-lab-color", new CIELabColorFunction()); //since XSL-FO 2.0 | |||||
FUNCTION_TABLE.put("cmyk", new CMYKcolorFunction()); //non-standard!!! | FUNCTION_TABLE.put("cmyk", new CMYKcolorFunction()); //non-standard!!! | ||||
/** | /** |
void next() throws PropertyException { | void next() throws PropertyException { | ||||
currentTokenValue = null; | currentTokenValue = null; | ||||
currentTokenStartIndex = exprIndex; | currentTokenStartIndex = exprIndex; | ||||
boolean currentMaybeOperator = recognizeOperator; | |||||
boolean bSawDecimal; | boolean bSawDecimal; | ||||
recognizeOperator = true; | recognizeOperator = true; | ||||
while ( true ) { | while ( true ) { | ||||
private void nextColor() throws PropertyException { | private void nextColor() throws PropertyException { | ||||
if (exprIndex < exprLength | |||||
&& isHexDigit(expr.charAt(exprIndex))) { | |||||
if (exprIndex < exprLength) { | |||||
++exprIndex; | ++exprIndex; | ||||
scanHexDigits(); | scanHexDigits(); | ||||
int len = exprIndex - currentTokenStartIndex - 1; | int len = exprIndex - currentTokenStartIndex - 1; | ||||
if (len % 3 == 0) { | if (len % 3 == 0) { | ||||
currentToken = TOK_COLORSPEC; | currentToken = TOK_COLORSPEC; | ||||
} else { | } else { | ||||
//Actually not a color at all, but an NCNAME starting with "#" | |||||
scanRestOfName(); | scanRestOfName(); | ||||
currentToken = TOK_NCNAME; | currentToken = TOK_NCNAME; | ||||
} | } |
* @throws PropertyException | * @throws PropertyException | ||||
* for invalid or inconsistent FO input | * for invalid or inconsistent FO input | ||||
*/ | */ | ||||
@Override | |||||
public Property convertProperty(Property p, | public Property convertProperty(Property p, | ||||
PropertyList propertyList, FObj fo) | PropertyList propertyList, FObj fo) | ||||
throws PropertyException { | throws PropertyException { | ||||
* @param foUserAgent FOP user agent | * @param foUserAgent FOP user agent | ||||
* @return float the AWT color represented by this ColorType instance | * @return float the AWT color represented by this ColorType instance | ||||
*/ | */ | ||||
@Override | |||||
public Color getColor(FOUserAgent foUserAgent) { | public Color getColor(FOUserAgent foUserAgent) { | ||||
return color; | return color; | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public String toString() { | public String toString() { | ||||
return ColorUtil.colorToString(color); | return ColorUtil.colorToString(color); | ||||
} | } | ||||
/** | /** | ||||
* @return this.colorType cast as an Object | * @return this.colorType cast as an Object | ||||
*/ | */ | ||||
@Override | |||||
public Object getObject() { | public Object getObject() { | ||||
return this; | return this; | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public boolean equals(Object o) { | public boolean equals(Object o) { | ||||
if (this == o) { | if (this == o) { | ||||
return true; | return true; | ||||
} | } | ||||
if (o instanceof ColorProperty) { | if (o instanceof ColorProperty) { | ||||
return ((ColorProperty) o).color.equals(this.color); | |||||
return org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor( | |||||
((ColorProperty) o).color, this.color); | |||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public int hashCode() { | public int hashCode() { | ||||
return this.color.hashCode(); | return this.color.hashCode(); | ||||
} | } |
/* | |||||
* 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.pdf; | |||||
/** | |||||
* This class represents a "CIE L*a*b*" color space. It is expected that the components have | |||||
* the following ranges: L* [0..100], a* and b* [-127..127] | |||||
*/ | |||||
public class PDFCIELabColorSpace extends PDFArray implements PDFColorSpace { | |||||
/** | |||||
* Creates a new "CIE L*a*b*" color space. Valid value ranges for the white and black point | |||||
* are [0..1] as per the PDF spec. | |||||
* @param whitePoint the white point | |||||
* @param blackPoint the optional black point (may be null) | |||||
*/ | |||||
public PDFCIELabColorSpace(float[] whitePoint, float[] blackPoint) { | |||||
super(); | |||||
add(new PDFName("Lab")); | |||||
PDFDictionary dict = new PDFDictionary(); | |||||
dict.put("WhitePoint", toPDFArray("White point", whitePoint)); | |||||
if (whitePoint[1] != 1f) { | |||||
throw new IllegalArgumentException("The white point's Y coordinate must be 1.0"); | |||||
} | |||||
if (blackPoint != null) { | |||||
dict.put("BlackPoint", toPDFArray("Black point", blackPoint)); | |||||
} | |||||
dict.put("Range", new PDFArray(dict, new int[] {-128, 128, -128, 128})); | |||||
add(dict); | |||||
} | |||||
private PDFArray toPDFArray(String name, float[] whitePoint) { | |||||
PDFArray wp = new PDFArray(); | |||||
if (whitePoint == null || whitePoint.length != 3) { | |||||
throw new IllegalArgumentException(name + " must be given an have 3 components"); | |||||
} | |||||
for (int i = 0; i < 3; i++) { | |||||
wp.add(whitePoint[i]); | |||||
} | |||||
return wp; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public String getName() { | |||||
return "CS" + this.getObjectNumber(); | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public int getNumComponents() { | |||||
return 3; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public boolean isCMYKColorSpace() { | |||||
return false; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public boolean isDeviceColorSpace() { | |||||
return false; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public boolean isGrayColorSpace() { | |||||
return false; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public boolean isRGBColorSpace() { | |||||
return false; | |||||
} | |||||
} |
import java.awt.Color; | import java.awt.Color; | ||||
import java.awt.color.ColorSpace; | import java.awt.color.ColorSpace; | ||||
import java.awt.color.ICC_ColorSpace; | |||||
import java.io.IOException; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import org.apache.xmlgraphics.java2d.color.DeviceCMYKColorSpace; | import org.apache.xmlgraphics.java2d.color.DeviceCMYKColorSpace; | ||||
import org.apache.fop.util.ColorExt; | |||||
/** | /** | ||||
* PDF Color object. | |||||
* This is used to output color to a PDF content stream. | |||||
* PDF Color object. It is currently only used to hold the transparent color of a masked bitmap | |||||
* image. And in this context, only RGB and Gray values are used. | |||||
* <p> | |||||
* Use of this class is discouraged. {@link PDFColorHandler} is now used for in-content color | |||||
* selection. For masked bitmaps, it may be wiser to switch to {@link Color} in the long run. | |||||
*/ | */ | ||||
public class PDFColor extends PDFPathPaint { | public class PDFColor extends PDFPathPaint { | ||||
// could be 3.0 as well. | // could be 3.0 as well. | ||||
private double yellow = -1.0; | private double yellow = -1.0; | ||||
private double black = -1.0; | private double black = -1.0; | ||||
// TODO - It would probably be better to reorganize PDFPathPaint/PDFColor/PDFColorSpace | |||||
// 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; | |||||
/** | /** | ||||
* Create a PDF color with double values ranging from 0 to 1 | |||||
* Create a PDF color with double values ranging from 0 to 1. | |||||
* | * | ||||
* @param theRed the red double value | * @param theRed the red double value | ||||
* @param theGreen the green double value | * @param theGreen the green double value | ||||
this.blue = theBlue; | this.blue = theBlue; | ||||
} | } | ||||
/** | |||||
* Create PDFColor for the given document and based on the java.awt.Color object | |||||
* | |||||
* In case the java.awt.Color is an instance of the ColorExt class a PDFICCStream is added to | |||||
* the PDFDocument that is being created | |||||
* | |||||
* @param pdfDoc PDFDocument that is being created | |||||
* @param col Color object from which to create this PDFColor | |||||
*/ | |||||
public PDFColor(PDFDocument pdfDoc, Color col) { | |||||
this(col); | |||||
// TODO - 1) There is a potential conflict when FOP and Batik elements use the same color | |||||
// profile name for different profiles. | |||||
// 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(); | |||||
ColorSpace ceCs = colorExt.getOrigColorSpace(); | |||||
try { | |||||
pdfIccStream.setColorSpace(((ICC_ColorSpace)ceCs).getProfile(), null); | |||||
pdfIccStream.setData( | |||||
((ICC_ColorSpace)colorExt.getColorSpace()).getProfile().getData()); | |||||
} catch (IOException ioe) { | |||||
log.error("Failed to set profile data for " + colorExt.getIccProfileName()); | |||||
} | |||||
pdfDoc.registerObject(pdfIccStream); | |||||
pdfDoc.getFactory().makeICCBasedColorSpace( | |||||
null, colorExt.getIccProfileName(), pdfIccStream); | |||||
if (log.isInfoEnabled()) { | |||||
log.info("Adding PDFICCStream " + colorExt.getIccProfileName() | |||||
+ " for " + colorExt.getIccProfileSrc()); | |||||
} | |||||
} | |||||
} | |||||
/** | /** | ||||
* Create a PDF color from a java.awt.Color object. | * Create a PDF color from a java.awt.Color object. | ||||
* | * | ||||
* Different Color objects are handled differently. Cases recognized are. | * Different Color objects are handled differently. Cases recognized are. | ||||
* | * | ||||
* 1. CMYK color | * 1. CMYK color | ||||
* 2. ColorExt color | |||||
* 3. 'Normal' java.awt.Color (RGB case assumed) | |||||
* 3. 'Normal' java.awt.Color (RGB case assumed or implicit conversion to sRGB) | |||||
* | * | ||||
* @param col the java.awt.Color object for which to create a PDFColor object | * @param col the java.awt.Color object for which to create a PDFColor object | ||||
*/ | */ | ||||
public PDFColor(java.awt.Color col) { | public PDFColor(java.awt.Color col) { | ||||
ColorSpace cs = col.getColorSpace(); | ColorSpace cs = col.getColorSpace(); | ||||
ColorExt ce = null; | |||||
if (col instanceof ColorExt) { | |||||
ce = (ColorExt)col; | |||||
cs = ce.getOrigColorSpace(); | |||||
} | |||||
if (cs != null && cs instanceof DeviceCMYKColorSpace) { | if (cs != null && cs instanceof DeviceCMYKColorSpace) { | ||||
// CMYK case | // CMYK case | ||||
this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_CMYK); | this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_CMYK); | ||||
float[] cmyk = (ce == null | |||||
? col.getColorComponents(null) | |||||
: ce.getOriginalColorComponents()); | |||||
float[] cmyk = col.getColorComponents(null); | |||||
this.cyan = cmyk[0]; | this.cyan = cmyk[0]; | ||||
this.magenta = cmyk[1]; | this.magenta = cmyk[1]; | ||||
this.yellow = cmyk[2]; | this.yellow = cmyk[2]; | ||||
this.black = cmyk[3]; | this.black = cmyk[3]; | ||||
} else if (ce != null) { | |||||
// ColorExt (ICC) case | |||||
this.colorExt = ce; | |||||
float[] rgb = col.getRGBColorComponents(null); | |||||
this.red = rgb[0]; | |||||
this.green = rgb[1]; | |||||
this.blue = rgb[2]; | |||||
// TODO - See earlier todo | |||||
this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); | |||||
} else { | } else { | ||||
// Default (RGB) Color | |||||
// Default (RGB) Color (ICC Colors are converted to sRGB, too) | |||||
this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); | this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); | ||||
float[] comps = new float[3]; | float[] comps = new float[3]; | ||||
comps = col.getColorComponents(comps); | comps = col.getColorComponents(comps); | ||||
public PDFColor(int theRed, int theGreen, int theBlue) { | public PDFColor(int theRed, int theGreen, int theBlue) { | ||||
this(((double)theRed) / 255d, ((double)theGreen) / 255d, | this(((double)theRed) / 255d, ((double)theGreen) / 255d, | ||||
((double)theBlue) / 255d); | ((double)theBlue) / 255d); | ||||
} | } | ||||
/** | /** | ||||
*/ | */ | ||||
public PDFColor(double theCyan, double theMagenta, double theYellow, | public PDFColor(double theCyan, double theMagenta, double theYellow, | ||||
double theBlack) { | double theBlack) { | ||||
// super(theNumber);//? | |||||
this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_CMYK); | this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_CMYK); | ||||
this.cyan = theCyan; | this.cyan = theCyan; | ||||
public String getColorSpaceOut(boolean fillNotStroke) { | public String getColorSpaceOut(boolean fillNotStroke) { | ||||
StringBuffer p = new StringBuffer(""); | StringBuffer p = new StringBuffer(""); | ||||
if (this.colorExt != null) { | |||||
if (fillNotStroke) { | |||||
p.append("/" + this.colorExt.getIccProfileName() + " cs "); | |||||
} else { | |||||
p.append("/" + this.colorExt.getIccProfileName() + " CS "); | |||||
} | |||||
float[] colorArgs; | |||||
colorArgs = this.colorExt.getOriginalColorComponents(); | |||||
if (colorArgs == null) { | |||||
colorArgs = this.colorExt.getColorComponents(null); | |||||
} | |||||
for (int ix = 0; ix < colorArgs.length; ix++) { | |||||
p.append(colorArgs[ix] + " "); | |||||
} | |||||
if (fillNotStroke) { | |||||
p.append("sc\n"); | |||||
} else { | |||||
p.append("SC\n"); | |||||
} | |||||
} else if (this.colorSpace.getColorSpace() | |||||
if (this.colorSpace.getColorSpace() | |||||
== PDFDeviceColorSpace.DEVICE_RGB) { // colorspace is RGB | == PDFDeviceColorSpace.DEVICE_RGB) { // colorspace is RGB | ||||
// according to pdfspec 12.1 p.399 | // according to pdfspec 12.1 p.399 | ||||
// if the colors are the same then just use the g or G operator | // if the colors are the same then just use the g or G operator |
/* | |||||
* 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.pdf; | |||||
import java.awt.Color; | |||||
import java.awt.color.ColorSpace; | |||||
import java.awt.color.ICC_ColorSpace; | |||||
import java.awt.color.ICC_Profile; | |||||
import java.text.DecimalFormat; | |||||
import java.util.Map; | |||||
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.ColorUtil; | |||||
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; | |||||
import org.apache.xmlgraphics.java2d.color.DeviceCMYKColorSpace; | |||||
import org.apache.xmlgraphics.java2d.color.NamedColorSpace; | |||||
import org.apache.xmlgraphics.java2d.color.profile.ColorProfileUtil; | |||||
import org.apache.fop.util.DecimalFormatCache; | |||||
/** | |||||
* This class handles the registration of color spaces and the generation of PDF code to select | |||||
* the right colors given a {@link Color} instance. | |||||
*/ | |||||
public class PDFColorHandler { | |||||
private Log log = LogFactory.getLog(PDFColorHandler.class); | |||||
private PDFResources resources; | |||||
private Map<String, PDFCIELabColorSpace> cieLabColorSpaces; | |||||
public PDFColorHandler(PDFResources resources) { | |||||
this.resources = resources; | |||||
} | |||||
private PDFDocument getDocument() { | |||||
return this.resources.getDocumentSafely(); | |||||
} | |||||
/** | |||||
* Generates code to select the given color and handles the registration of color spaces in | |||||
* PDF where necessary. | |||||
* @param codeBuffer the target buffer to receive the color selection code | |||||
* @param color the color | |||||
* @param fill true for fill color, false for stroke color | |||||
*/ | |||||
public void establishColor(StringBuffer codeBuffer, Color color, boolean fill) { | |||||
if (color instanceof ColorWithAlternatives) { | |||||
ColorWithAlternatives colExt = (ColorWithAlternatives)color; | |||||
//Alternate colors have priority | |||||
Color[] alt = colExt.getAlternativeColors(); | |||||
for (int i = 0, c = alt.length; i < c; i++) { | |||||
Color col = alt[i]; | |||||
boolean established = establishColorFromColor(codeBuffer, col, fill); | |||||
if (established) { | |||||
return; | |||||
} | |||||
} | |||||
if (log.isDebugEnabled() && alt.length > 0) { | |||||
log.debug("None of the alternative colors are supported. Using fallback: " | |||||
+ color); | |||||
} | |||||
} | |||||
//Fallback | |||||
boolean established = establishColorFromColor(codeBuffer, color, fill); | |||||
if (!established) { | |||||
establishDeviceRGB(codeBuffer, color, fill); | |||||
} | |||||
} | |||||
private boolean establishColorFromColor(StringBuffer codeBuffer, Color color, boolean fill) { | |||||
ColorSpace cs = color.getColorSpace(); | |||||
if (cs instanceof DeviceCMYKColorSpace) { | |||||
establishDeviceCMYK(codeBuffer, color, fill); | |||||
return true; | |||||
} else if (!cs.isCS_sRGB()) { | |||||
if (cs instanceof ICC_ColorSpace) { | |||||
PDFICCBasedColorSpace pdfcs = getICCBasedColorSpace((ICC_ColorSpace)cs); | |||||
establishColor(codeBuffer, pdfcs, color, fill); | |||||
return true; | |||||
} else if (cs instanceof NamedColorSpace) { | |||||
PDFSeparationColorSpace sepcs = getSeparationColorSpace((NamedColorSpace)cs); | |||||
establishColor(codeBuffer, sepcs, color, fill); | |||||
return true; | |||||
} else if (cs instanceof CIELabColorSpace) { | |||||
CIELabColorSpace labcs = (CIELabColorSpace)cs; | |||||
PDFCIELabColorSpace pdflab = getCIELabColorSpace(labcs); | |||||
selectColorSpace(codeBuffer, pdflab, fill); | |||||
float[] comps = color.getColorComponents(null); | |||||
float[] nativeComps = labcs.toNativeComponents(comps); | |||||
writeColor(codeBuffer, nativeComps, labcs.getNumComponents(), (fill ? "sc" : "SC")); | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
private PDFICCBasedColorSpace getICCBasedColorSpace(ICC_ColorSpace cs) { | |||||
ICC_Profile profile = cs.getProfile(); | |||||
String desc = ColorProfileUtil.getICCProfileDescription(profile); | |||||
if (log.isDebugEnabled()) { | |||||
log.trace("ICC profile encountered: " + desc); | |||||
} | |||||
PDFICCBasedColorSpace pdfcs = this.resources.getICCColorSpaceByProfileName(desc); | |||||
if (pdfcs == null) { | |||||
//color space is not in the PDF, yet | |||||
PDFFactory factory = getDocument().getFactory(); | |||||
PDFICCStream pdfICCStream = factory.makePDFICCStream(); | |||||
PDFDeviceColorSpace altSpace = PDFDeviceColorSpace.toPDFColorSpace(cs); | |||||
pdfICCStream.setColorSpace(profile, altSpace); | |||||
pdfcs = factory.makeICCBasedColorSpace(null, desc, pdfICCStream); | |||||
} | |||||
return pdfcs; | |||||
} | |||||
private PDFSeparationColorSpace getSeparationColorSpace(NamedColorSpace cs) { | |||||
PDFName colorName = new PDFName(cs.getColorName()); | |||||
PDFSeparationColorSpace sepcs = (PDFSeparationColorSpace)this.resources.getColorSpace( | |||||
colorName); | |||||
if (sepcs == null) { | |||||
//color space is not in the PDF, yet | |||||
PDFFactory factory = getDocument().getFactory(); | |||||
sepcs = factory.makeSeparationColorSpace(null, cs); | |||||
} | |||||
return sepcs; | |||||
} | |||||
private PDFCIELabColorSpace getCIELabColorSpace(CIELabColorSpace labCS) { | |||||
if (this.cieLabColorSpaces == null) { | |||||
this.cieLabColorSpaces = new java.util.HashMap<String, PDFCIELabColorSpace>(); | |||||
} | |||||
float[] wp = labCS.getWhitePoint(); | |||||
StringBuilder sb = new StringBuilder(); | |||||
for (int i = 0; i < 3; i++) { | |||||
if (i > 0) { | |||||
sb.append(','); | |||||
} | |||||
sb.append(wp[i]); | |||||
} | |||||
String key = sb.toString(); | |||||
PDFCIELabColorSpace cielab = this.cieLabColorSpaces.get(key); | |||||
if (cielab == null) { | |||||
//color space is not in the PDF, yet | |||||
float[] wp1 = new float[] {wp[0] / 100f, wp[1] / 100f, wp[2] / 100f}; | |||||
cielab = new PDFCIELabColorSpace(wp1, null); | |||||
getDocument().registerObject(cielab); | |||||
this.resources.addColorSpace(cielab); | |||||
this.cieLabColorSpaces.put(key, cielab); | |||||
} | |||||
return cielab; | |||||
} | |||||
private void establishColor(StringBuffer codeBuffer, | |||||
PDFColorSpace pdfcs, Color color, boolean fill) { | |||||
selectColorSpace(codeBuffer, pdfcs, fill); | |||||
writeColor(codeBuffer, color, pdfcs.getNumComponents(), (fill ? "sc" : "SC")); | |||||
} | |||||
private void selectColorSpace(StringBuffer codeBuffer, PDFColorSpace pdfcs, boolean fill) { | |||||
codeBuffer.append(new PDFName(pdfcs.getName())); | |||||
if (fill) { | |||||
codeBuffer.append(" cs "); | |||||
} else { | |||||
codeBuffer.append(" CS "); | |||||
} | |||||
} | |||||
private void establishDeviceRGB(StringBuffer codeBuffer, Color color, boolean fill) { | |||||
float[] comps; | |||||
if (color.getColorSpace().isCS_sRGB()) { | |||||
comps = color.getColorComponents(null); | |||||
} else { | |||||
if (log.isDebugEnabled()) { | |||||
log.debug("Converting color to sRGB as a fallback: " + color); | |||||
} | |||||
ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); | |||||
comps = color.getColorComponents(sRGB, null); | |||||
} | |||||
if (ColorUtil.isGray(color)) { | |||||
comps = new float[] {comps[0]}; //assuming that all components are the same | |||||
writeColor(codeBuffer, comps, 1, (fill ? "g" : "G")); | |||||
} else { | |||||
writeColor(codeBuffer, comps, 3, (fill ? "rg" : "RG")); | |||||
} | |||||
} | |||||
private void establishDeviceCMYK(StringBuffer codeBuffer, Color color, boolean fill) { | |||||
writeColor(codeBuffer, color, 4, (fill ? "k" : "K")); | |||||
} | |||||
private void writeColor(StringBuffer codeBuffer, Color color, int componentCount, | |||||
String command) { | |||||
float[] comps = color.getColorComponents(null); | |||||
writeColor(codeBuffer, comps, componentCount, command); | |||||
} | |||||
private void writeColor(StringBuffer codeBuffer, float[] comps, int componentCount, | |||||
String command) { | |||||
if (comps.length != componentCount) { | |||||
throw new IllegalStateException("Color with unexpected component count encountered"); | |||||
} | |||||
DecimalFormat df = DecimalFormatCache.getDecimalFormat(4); | |||||
for (int i = 0, c = comps.length; i < c; i++) { | |||||
codeBuffer.append(df.format(comps[i])).append(" "); | |||||
} | |||||
codeBuffer.append(command).append("\n"); | |||||
} | |||||
} |
package org.apache.fop.pdf; | package org.apache.fop.pdf; | ||||
import java.awt.color.ColorSpace; | |||||
/** | /** | ||||
* Represents a device-specific color space. Used for mapping DeviceRGB, DeviceCMYK and DeviceGray. | * Represents a device-specific color space. Used for mapping DeviceRGB, DeviceCMYK and DeviceGray. | ||||
*/ | */ | ||||
return getColorSpace() == DEVICE_GRAY; | return getColorSpace() == DEVICE_GRAY; | ||||
} | } | ||||
/** | |||||
* Returns a suitable {@link PDFDeviceColorSpace} object given a {@link ColorSpace} object. | |||||
* @param cs ColorSpace instance | |||||
* @return a PDF-based color space | |||||
*/ | |||||
public static PDFDeviceColorSpace toPDFColorSpace(ColorSpace cs) { | |||||
if (cs == null) { | |||||
return null; | |||||
} | |||||
PDFDeviceColorSpace pdfCS = new PDFDeviceColorSpace(0); | |||||
switch (cs.getType()) { | |||||
case ColorSpace.TYPE_CMYK: | |||||
pdfCS.setColorSpace(PDFDeviceColorSpace.DEVICE_CMYK); | |||||
break; | |||||
case ColorSpace.TYPE_GRAY: | |||||
pdfCS.setColorSpace(PDFDeviceColorSpace.DEVICE_GRAY); | |||||
break; | |||||
default: | |||||
pdfCS.setColorSpace(PDFDeviceColorSpace.DEVICE_RGB); | |||||
} | |||||
return pdfCS; | |||||
} | |||||
} | } |
*/ | */ | ||||
public class PDFDocument { | public class PDFDocument { | ||||
private static final Integer LOCATION_PLACEHOLDER = new Integer(0); | |||||
private static final Long LOCATION_PLACEHOLDER = new Long(0); | |||||
/** Integer constant to represent PDF 1.3 */ | /** Integer constant to represent PDF 1.3 */ | ||||
public static final int PDF_VERSION_1_3 = 3; | public static final int PDF_VERSION_1_3 = 3; | ||||
private Log log = LogFactory.getLog("org.apache.fop.pdf"); | private Log log = LogFactory.getLog("org.apache.fop.pdf"); | ||||
/** the current character position */ | /** the current character position */ | ||||
private int position = 0; | |||||
private long position = 0; | |||||
/** character position of xref table */ | /** character position of xref table */ | ||||
private int xref; | |||||
private long xref; | |||||
/** the character position of each object */ | /** the character position of each object */ | ||||
private List location = new ArrayList(); | |||||
private List<Long> location = new ArrayList<Long>(); | |||||
/** List of objects to write in the trailer */ | /** List of objects to write in the trailer */ | ||||
private List trailerObjects = new ArrayList(); | private List trailerObjects = new ArrayList(); | ||||
* @return the image or PDFXObject for the key if found | * @return the image or PDFXObject for the key if found | ||||
* @deprecated Use getXObject instead (so forms are treated in the same way) | * @deprecated Use getXObject instead (so forms are treated in the same way) | ||||
*/ | */ | ||||
@Deprecated | |||||
public PDFImageXObject getImage(String key) { | public PDFImageXObject getImage(String key) { | ||||
return (PDFImageXObject)this.xObjectsMap.get(key); | return (PDFImageXObject)this.xObjectsMap.get(key); | ||||
} | } | ||||
* @param objidx the object's index | * @param objidx the object's index | ||||
* @param position the position | * @param position the position | ||||
*/ | */ | ||||
private void setLocation(int objidx, int position) { | |||||
private void setLocation(int objidx, long position) { | |||||
while (this.location.size() <= objidx) { | while (this.location.size() <= objidx) { | ||||
this.location.add(LOCATION_PLACEHOLDER); | this.location.add(LOCATION_PLACEHOLDER); | ||||
} | } | ||||
this.location.set(objidx, new Integer(position)); | |||||
this.location.set(objidx, position); | |||||
} | } | ||||
/** | /** | ||||
for (int count = 0; count < this.location.size(); count++) { | for (int count = 0; count < this.location.size(); count++) { | ||||
final String padding = "0000000000"; | final String padding = "0000000000"; | ||||
s = this.location.get(count).toString(); | s = this.location.get(count).toString(); | ||||
if (s.length() > 10) { | |||||
throw new IOException("PDF file too large. PDF cannot grow beyond approx. 9.3GB."); | |||||
} | |||||
/* contruct xref entry for object */ | /* contruct xref entry for object */ | ||||
loc = padding.substring(s.length()) + s; | loc = padding.substring(s.length()) + s; |
package org.apache.fop.pdf; | package org.apache.fop.pdf; | ||||
// Java | // Java | ||||
import java.awt.Color; | |||||
import java.awt.geom.Point2D; | import java.awt.geom.Point2D; | ||||
import java.awt.geom.Rectangle2D; | import java.awt.geom.Rectangle2D; | ||||
import java.io.FileNotFoundException; | import java.io.FileNotFoundException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.net.MalformedURLException; | import java.net.MalformedURLException; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Arrays; | |||||
import java.util.BitSet; | import java.util.BitSet; | ||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.List; | import java.util.List; | ||||
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||||
import org.apache.xmlgraphics.java2d.color.NamedColorSpace; | |||||
import org.apache.xmlgraphics.xmp.Metadata; | import org.apache.xmlgraphics.xmp.Metadata; | ||||
import org.apache.fop.fonts.CIDFont; | import org.apache.fop.fonts.CIDFont; | ||||
for (currentPosition = 0; currentPosition < lastPosition; | for (currentPosition = 0; currentPosition < lastPosition; | ||||
currentPosition++) { // for every consecutive color pair | currentPosition++) { // for every consecutive color pair | ||||
PDFColor currentColor = (PDFColor)theColors.get(currentPosition); | |||||
PDFColor nextColor = (PDFColor)theColors.get(currentPosition | |||||
+ 1); | |||||
// colorspace must be consistant | |||||
if (getDocument().getColorSpace() != currentColor.getColorSpace()) { | |||||
currentColor.setColorSpace( | |||||
getDocument().getColorSpace()); | |||||
Color currentColor = (Color)theColors.get(currentPosition); | |||||
Color nextColor = (Color)theColors.get(currentPosition + 1); | |||||
// colorspace must be consistent, so we simply convert to sRGB where necessary | |||||
if (!currentColor.getColorSpace().isCS_sRGB()) { | |||||
//Convert to sRGB | |||||
currentColor = ColorUtil.toSRGBColor(currentColor); | |||||
theColors.set(currentPosition, currentColor); | |||||
} | } | ||||
if (getDocument().getColorSpace() | |||||
!= nextColor.getColorSpace()) { | |||||
nextColor.setColorSpace( | |||||
getDocument().getColorSpace()); | |||||
if (!nextColor.getColorSpace().isCS_sRGB()) { | |||||
//Convert to sRGB | |||||
nextColor = ColorUtil.toSRGBColor(nextColor); | |||||
theColors.set(currentPosition + 1, nextColor); | |||||
} | } | ||||
theCzero = currentColor.getVector(); | |||||
theCone = nextColor.getVector(); | |||||
theCzero = toColorVector(currentColor); | |||||
theCone = toColorVector(nextColor); | |||||
myfunc = makeFunction(2, null, null, theCzero, theCone, | myfunc = makeFunction(2, null, null, theCzero, theCone, | ||||
interpolation); | interpolation); | ||||
return (myPattern); | return (myPattern); | ||||
} | } | ||||
private List toColorVector(Color nextColor) { | |||||
List vector = new java.util.ArrayList(); | |||||
float[] comps = nextColor.getColorComponents(null); | |||||
for (int i = 0, c = comps.length; i < c; i++) { | |||||
vector.add(new Double(comps[i])); | |||||
} | |||||
return vector; | |||||
} | |||||
/* ============= named destinations and the name dictionary ============ */ | /* ============= named destinations and the name dictionary ============ */ | ||||
/** | /** | ||||
return cs; | return cs; | ||||
} | } | ||||
/** | |||||
* Create a new Separation color space. | |||||
* @param res the resource context (may be null) | |||||
* @param ncs the named color space to map to a separation color space | |||||
* @return the newly created Separation color space | |||||
*/ | |||||
public PDFSeparationColorSpace makeSeparationColorSpace(PDFResourceContext res, | |||||
NamedColorSpace ncs) { | |||||
String colorName = ncs.getColorName(); | |||||
final Double zero = new Double(0d); | |||||
final Double one = new Double(1d); | |||||
List theDomain = Arrays.asList(new Double[] {zero, one}); | |||||
List theRange = Arrays.asList(new Double[] {zero, one, zero, one, zero, one}); | |||||
List theCZero = Arrays.asList(new Double[] {one, one, one}); | |||||
List theCOne = new ArrayList(); | |||||
float[] comps = ncs.getRGBColor().getColorComponents(null); | |||||
for (int i = 0, c = comps.length; i < c; i++) { | |||||
theCOne.add(new Double(comps[i])); | |||||
} | |||||
PDFFunction tintFunction = makeFunction(2, theDomain, theRange, | |||||
theCZero, theCOne, 1.0d); | |||||
PDFSeparationColorSpace cs = new PDFSeparationColorSpace(colorName, tintFunction); | |||||
getDocument().registerObject(cs); | |||||
if (res != null) { | |||||
res.getPDFResources().addColorSpace(cs); | |||||
} else { | |||||
getDocument().getResources().addColorSpace(cs); | |||||
} | |||||
return cs; | |||||
} | |||||
/** | /** | ||||
* Make an Array object (ex. Widths array for a font). | * Make an Array object (ex. Widths array for a font). | ||||
* | * |
return this.name; | return this.name; | ||||
} | } | ||||
/** | |||||
* Returns the name without the leading slash. | |||||
* @return the name without the leading slash | |||||
*/ | |||||
public String getName() { | |||||
return this.name.substring(1); | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public boolean equals(Object obj) { | |||||
if (!(obj instanceof PDFName)) { | |||||
return false; | |||||
} | |||||
PDFName other = (PDFName)obj; | |||||
return this.name.equals(other.name); | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public int hashCode() { | |||||
return name.hashCode(); | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
protected int output(OutputStream stream) throws IOException { | protected int output(OutputStream stream) throws IOException { | ||||
CountingOutputStream cout = new CountingOutputStream(stream); | CountingOutputStream cout = new CountingOutputStream(stream); |
package org.apache.fop.pdf; | package org.apache.fop.pdf; | ||||
import java.awt.Color; | |||||
import java.awt.Paint; | import java.awt.Paint; | ||||
import java.awt.Shape; | import java.awt.Shape; | ||||
import java.awt.geom.Area; | import java.awt.geom.Area; | ||||
import java.awt.geom.GeneralPath; | import java.awt.geom.GeneralPath; | ||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||||
import org.apache.fop.util.AbstractPaintingState; | import org.apache.fop.util.AbstractPaintingState; | ||||
/** | /** | ||||
*/ | */ | ||||
public boolean setPaint(Paint p) { | public boolean setPaint(Paint p) { | ||||
PDFData data = getPDFData(); | PDFData data = getPDFData(); | ||||
Paint paint = data.paint; | |||||
if (paint == null) { | |||||
Paint currentPaint = data.paint; | |||||
if (currentPaint == null) { | |||||
if (p != null) { | if (p != null) { | ||||
data.paint = p; | data.paint = p; | ||||
return true; | return true; | ||||
} | } | ||||
} else if (!paint.equals(p)) { | |||||
} else if (p instanceof Color && currentPaint instanceof Color) { | |||||
if (!ColorUtil.isSameColor((Color)p, (Color)currentPaint)) { | |||||
data.paint = p; | |||||
return true; | |||||
} | |||||
} else if (!currentPaint.equals(p)) { | |||||
data.paint = p; | data.paint = p; | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
protected AbstractData instantiateData() { | protected AbstractData instantiateData() { | ||||
return new PDFData(); | return new PDFData(); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
protected AbstractPaintingState instantiate() { | protected AbstractPaintingState instantiate() { | ||||
return new PDFPaintingState(); | return new PDFPaintingState(); | ||||
} | } | ||||
* This call should be used when the q operator is used | * This call should be used when the q operator is used | ||||
* so that the state is known when popped. | * so that the state is known when popped. | ||||
*/ | */ | ||||
@Override | |||||
public void save() { | public void save() { | ||||
AbstractData data = getData(); | AbstractData data = getData(); | ||||
AbstractData copy = (AbstractData)data.clone(); | AbstractData copy = (AbstractData)data.clone(); | ||||
private float characterSpacing = 0f; | private float characterSpacing = 0f; | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public Object clone() { | public Object clone() { | ||||
PDFData obj = (PDFData)super.clone(); | PDFData obj = (PDFData)super.clone(); | ||||
obj.paint = this.paint; | obj.paint = this.paint; | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public String toString() { | public String toString() { | ||||
return super.toString() | return super.toString() | ||||
+ ", paint=" + paint | + ", paint=" + paint | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
protected AbstractData instantiate() { | protected AbstractData instantiate() { | ||||
return new PDFData(); | return new PDFData(); | ||||
} | } |
package org.apache.fop.pdf; | package org.apache.fop.pdf; | ||||
import java.io.IOException; | |||||
import java.io.OutputStream; | |||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.HashSet; | import java.util.HashSet; | ||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import org.apache.fop.fonts.base14.ZapfDingbats; | import org.apache.fop.fonts.base14.ZapfDingbats; | ||||
/** | /** | ||||
* class representing a /Resources object. | |||||
* Class representing a /Resources object. | |||||
* | * | ||||
* /Resources object contain a list of references to the fonts for the | * /Resources object contain a list of references to the fonts for the | ||||
* document | * document | ||||
*/ | */ | ||||
public class PDFResources extends PDFObject { | |||||
public class PDFResources extends PDFDictionary { | |||||
/** | /** | ||||
* /Font objects keyed by their internal name | * /Font objects keyed by their internal name | ||||
* Add a ColorSpace dictionary to the resources. | * Add a ColorSpace dictionary to the resources. | ||||
* @param colorSpace the color space | * @param colorSpace the color space | ||||
*/ | */ | ||||
public void addColorSpace(PDFICCBasedColorSpace colorSpace) { | |||||
this.colorSpaces.put(colorSpace.getName(), colorSpace); | |||||
String desc = ColorProfileUtil.getICCProfileDescription( | |||||
colorSpace.getICCStream().getICCProfile()); | |||||
this.iccColorSpaces.put(desc, colorSpace); | |||||
public void addColorSpace(PDFColorSpace colorSpace) { | |||||
this.colorSpaces.put(new PDFName(colorSpace.getName()), colorSpace); | |||||
if (colorSpace instanceof PDFICCBasedColorSpace) { | |||||
PDFICCBasedColorSpace icc = (PDFICCBasedColorSpace)colorSpace; | |||||
String desc = ColorProfileUtil.getICCProfileDescription( | |||||
icc.getICCStream().getICCProfile()); | |||||
this.iccColorSpaces.put(desc, colorSpace); | |||||
} | |||||
} | } | ||||
/** | /** | ||||
* @param name the name of the color space | * @param name the name of the color space | ||||
* @return the requested color space or null if it wasn't found | * @return the requested color space or null if it wasn't found | ||||
*/ | */ | ||||
public PDFICCBasedColorSpace getColorSpace(String name) { | |||||
PDFICCBasedColorSpace cs = (PDFICCBasedColorSpace)this.colorSpaces.get(name); | |||||
public PDFColorSpace getColorSpace(PDFName name) { | |||||
PDFColorSpace cs = (PDFColorSpace)this.colorSpaces.get(name); | |||||
return cs; | return cs; | ||||
} | } | ||||
/** | |||||
* represent the object in PDF | |||||
* This adds the references to all the objects in the current | |||||
* resource context. | |||||
* | |||||
* @return the PDF | |||||
* {@inheritDoc} | |||||
*/ | |||||
@Override | |||||
public String toPDFString() { | |||||
StringBuffer p = new StringBuffer(128); | |||||
p.append(getObjectID() + "<<\n"); | |||||
if (!this.fonts.isEmpty()) { | |||||
p.append("/Font <<\n"); | |||||
/** {@inheritDoc} */ | |||||
protected int output(OutputStream stream) throws IOException { | |||||
populateDictionary(); | |||||
return super.output(stream); | |||||
} | |||||
private void populateDictionary() { | |||||
if (!this.fonts.isEmpty()) { | |||||
PDFDictionary dict = new PDFDictionary(this); | |||||
/* construct PDF dictionary of font object references */ | /* construct PDF dictionary of font object references */ | ||||
Iterator fontIterator = this.fonts.keySet().iterator(); | Iterator fontIterator = this.fonts.keySet().iterator(); | ||||
while (fontIterator.hasNext()) { | while (fontIterator.hasNext()) { | ||||
String fontName = (String)fontIterator.next(); | String fontName = (String)fontIterator.next(); | ||||
p.append(" /" + fontName + " " | |||||
+ ((PDFFont)this.fonts.get(fontName)).referencePDF() | |||||
+ "\n"); | |||||
dict.put(fontName, (PDFFont)this.fonts.get(fontName)); | |||||
} | } | ||||
p.append(">>\n"); | |||||
put("Font", dict); | |||||
} | } | ||||
PDFShading currentShading = null; | |||||
if (!this.shadings.isEmpty()) { | if (!this.shadings.isEmpty()) { | ||||
p.append("/Shading <<\n"); | |||||
PDFDictionary dict = new PDFDictionary(this); | |||||
for (Iterator iter = shadings.iterator(); iter.hasNext();) { | for (Iterator iter = shadings.iterator(); iter.hasNext();) { | ||||
currentShading = (PDFShading)iter.next(); | |||||
p.append(" /" + currentShading.getName() + " " | |||||
+ currentShading.referencePDF() + " "); // \n ?????? | |||||
PDFShading currentShading = (PDFShading)iter.next(); | |||||
dict.put(currentShading.getName(), currentShading); | |||||
} | } | ||||
p.append(">>\n"); | |||||
put("Shading", dict); | |||||
} | } | ||||
// "free" the memory. Sorta. | |||||
currentShading = null; | |||||
PDFPattern currentPattern = null; | |||||
if (!this.patterns.isEmpty()) { | if (!this.patterns.isEmpty()) { | ||||
p.append("/Pattern <<\n"); | |||||
PDFDictionary dict = new PDFDictionary(this); | |||||
for (Iterator iter = patterns.iterator(); iter.hasNext();) { | for (Iterator iter = patterns.iterator(); iter.hasNext();) { | ||||
currentPattern = (PDFPattern)iter.next(); | |||||
p.append(" /" + currentPattern.getName() + " " | |||||
+ currentPattern.referencePDF() + " "); | |||||
PDFPattern currentPattern = (PDFPattern)iter.next(); | |||||
dict.put(currentPattern.getName(), currentPattern); | |||||
} | } | ||||
p.append(">>\n"); | |||||
put("Pattern", dict); | |||||
} | } | ||||
// "free" the memory. Sorta. | |||||
currentPattern = null; | |||||
p.append("/ProcSet [ /PDF /ImageB /ImageC /Text ]\n"); | |||||
PDFArray procset = new PDFArray(this); | |||||
procset.add(new PDFName("PDF")); | |||||
procset.add(new PDFName("ImageB")); | |||||
procset.add(new PDFName("ImageC")); | |||||
procset.add(new PDFName("Text")); | |||||
put("ProcSet", procset); | |||||
if (this.xObjects != null && !this.xObjects.isEmpty()) { | if (this.xObjects != null && !this.xObjects.isEmpty()) { | ||||
p = p.append("/XObject <<\n"); | |||||
PDFDictionary dict = new PDFDictionary(this); | |||||
for (Iterator iter = xObjects.iterator(); iter.hasNext();) { | for (Iterator iter = xObjects.iterator(); iter.hasNext();) { | ||||
PDFXObject xobj = (PDFXObject)iter.next(); | PDFXObject xobj = (PDFXObject)iter.next(); | ||||
p = p.append(" " + xobj.getName() + " " | |||||
+ xobj.referencePDF() | |||||
+ "\n"); | |||||
dict.put(xobj.getName().toString(), xobj); | |||||
} | } | ||||
p = p.append(">>\n"); | |||||
put("XObject", dict); | |||||
} | } | ||||
if (!this.gstates.isEmpty()) { | if (!this.gstates.isEmpty()) { | ||||
p = p.append("/ExtGState <<\n"); | |||||
PDFDictionary dict = new PDFDictionary(this); | |||||
for (Iterator iter = gstates.iterator(); iter.hasNext();) { | for (Iterator iter = gstates.iterator(); iter.hasNext();) { | ||||
PDFGState gs = (PDFGState)iter.next(); | PDFGState gs = (PDFGState)iter.next(); | ||||
p = p.append(" /" + gs.getName() + " " | |||||
+ gs.referencePDF() | |||||
+ "\n"); | |||||
dict.put(gs.getName(), gs); | |||||
} | } | ||||
p = p.append(">>\n"); | |||||
put("ExtGState", dict); | |||||
} | } | ||||
if (!this.colorSpaces.isEmpty()) { | if (!this.colorSpaces.isEmpty()) { | ||||
p = p.append("/ColorSpace <<\n"); | |||||
PDFDictionary dict = new PDFDictionary(this); | |||||
for (Iterator iter = colorSpaces.values().iterator(); iter.hasNext();) { | for (Iterator iter = colorSpaces.values().iterator(); iter.hasNext();) { | ||||
PDFICCBasedColorSpace colorSpace = (PDFICCBasedColorSpace)iter.next(); | |||||
p = p.append(" /" + colorSpace.getName() + " " | |||||
+ colorSpace.referencePDF() | |||||
+ "\n"); | |||||
PDFColorSpace colorSpace = (PDFColorSpace)iter.next(); | |||||
dict.put(colorSpace.getName(), colorSpace); | |||||
} | } | ||||
p = p.append(">>\n"); | |||||
put("ColorSpace", dict); | |||||
} | } | ||||
p = p.append(">>\nendobj\n"); | |||||
return p.toString(); | |||||
} | } | ||||
} | } |
/* | |||||
* 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.pdf; | |||||
/** | |||||
* This class represents a "Separation" color space. It is used in FOP to map named colors. | |||||
*/ | |||||
public class PDFSeparationColorSpace extends PDFArray implements PDFColorSpace { | |||||
/** | |||||
* Creates a new "Separation" color space. | |||||
* @param colorName the name of the colorant | |||||
* @param tintFunction the tint function used as fallback | |||||
*/ | |||||
public PDFSeparationColorSpace(String colorName, PDFFunction tintFunction) { | |||||
super(); | |||||
add(new PDFName("Separation")); | |||||
add(new PDFName(colorName)); | |||||
add(new PDFName("DeviceRGB")); | |||||
add(new PDFReference(tintFunction)); | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public String getName() { | |||||
//return "CS" + this.getObjectNumber(); | |||||
return getColorName().toString(); | |||||
} | |||||
/** | |||||
* Returns the name of the colorant. | |||||
* @return the name of the colorant | |||||
*/ | |||||
public PDFName getColorName() { | |||||
return (PDFName)get(1); | |||||
} | |||||
/** | |||||
* Returns a reference to the tint function that is used as a fallback if the colorant is | |||||
* not available. | |||||
* @return a reference to the tint function | |||||
*/ | |||||
public PDFReference getTintFunction() { | |||||
return (PDFReference)get(2); | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public int getNumComponents() { | |||||
return 1; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public boolean isCMYKColorSpace() { | |||||
return false; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public boolean isDeviceColorSpace() { | |||||
return false; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public boolean isGrayColorSpace() { | |||||
return false; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public boolean isRGBColorSpace() { | |||||
return false; | |||||
} | |||||
} |
import org.w3c.dom.Document; | import org.w3c.dom.Document; | ||||
import org.w3c.dom.Node; | import org.w3c.dom.Node; | ||||
import org.w3c.dom.NodeList; | import org.w3c.dom.NodeList; | ||||
import org.xml.sax.SAXException; | import org.xml.sax.SAXException; | ||||
import org.xml.sax.helpers.AttributesImpl; | import org.xml.sax.helpers.AttributesImpl; | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
protected String getMainNamespace() { | protected String getMainNamespace() { | ||||
return NAMESPACE; | return NAMESPACE; | ||||
} | } | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public IFDocumentNavigationHandler getDocumentNavigationHandler() { | public IFDocumentNavigationHandler getDocumentNavigationHandler() { | ||||
return this; | return this; | ||||
} | } | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void startDocument() throws IFException { | public void startDocument() throws IFException { | ||||
super.startDocument(); | super.startDocument(); | ||||
try { | try { | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void startDocumentHeader() throws IFException { | public void startDocumentHeader() throws IFException { | ||||
try { | try { | ||||
handler.startElement(EL_HEADER); | handler.startElement(EL_HEADER); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void endDocumentHeader() throws IFException { | public void endDocumentHeader() throws IFException { | ||||
try { | try { | ||||
handler.endElement(EL_HEADER); | handler.endElement(EL_HEADER); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void startDocumentTrailer() throws IFException { | public void startDocumentTrailer() throws IFException { | ||||
try { | try { | ||||
handler.startElement(EL_TRAILER); | handler.startElement(EL_TRAILER); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void endDocumentTrailer() throws IFException { | public void endDocumentTrailer() throws IFException { | ||||
try { | try { | ||||
handler.endElement(EL_TRAILER); | handler.endElement(EL_TRAILER); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void startPageHeader() throws IFException { | public void startPageHeader() throws IFException { | ||||
try { | try { | ||||
handler.startElement(EL_PAGE_HEADER); | handler.startElement(EL_PAGE_HEADER); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void endPageHeader() throws IFException { | public void endPageHeader() throws IFException { | ||||
try { | try { | ||||
handler.endElement(EL_PAGE_HEADER); | handler.endElement(EL_PAGE_HEADER); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void startPageTrailer() throws IFException { | public void startPageTrailer() throws IFException { | ||||
try { | try { | ||||
handler.startElement(EL_PAGE_TRAILER); | handler.startElement(EL_PAGE_TRAILER); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void endPageTrailer() throws IFException { | public void endPageTrailer() throws IFException { | ||||
try { | try { | ||||
commitNavigation(); | commitNavigation(); | ||||
} | } | ||||
} | } | ||||
if (color != null) { | if (color != null) { | ||||
changed = !color.equals(state.getTextColor()); | |||||
changed = !org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor( | |||||
color, state.getTextColor()); | |||||
if (changed) { | if (changed) { | ||||
state.setTextColor(color); | state.setTextColor(color); | ||||
addAttribute(atts, "color", toString(color)); | addAttribute(atts, "color", toString(color)); |
import java.awt.Color; | import java.awt.Color; | ||||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||||
/** a state class for intermediate format data */ | /** a state class for intermediate format data */ | ||||
public final class IFState { | public final class IFState { | ||||
* @param color the new text color | * @param color the new text color | ||||
*/ | */ | ||||
public void setTextColor(Color color) { | public void setTextColor(Color color) { | ||||
if (!color.equals(this.textColor)) { | |||||
if (!ColorUtil.isSameColor(color, this.textColor)) { | |||||
this.fontChanged = true; | this.fontChanged = true; | ||||
} | } | ||||
this.textColor = color; | this.textColor = color; |
import java.awt.geom.Area; | import java.awt.geom.Area; | ||||
import java.awt.geom.GeneralPath; | import java.awt.geom.GeneralPath; | ||||
import org.apache.xmlgraphics.java2d.color.ColorUtil; | |||||
import org.apache.fop.fo.Constants; | import org.apache.fop.fo.Constants; | ||||
import org.apache.fop.fonts.FontInfo; | import org.apache.fop.fonts.FontInfo; | ||||
* @return true if the background color has changed | * @return true if the background color has changed | ||||
*/ | */ | ||||
public boolean updateColor(Color col) { | public boolean updateColor(Color col) { | ||||
if (!col.equals(getGraph().getColor())) { | |||||
if (!ColorUtil.isSameColor(col, getGraph().getColor())) { | |||||
getGraph().setColor(col); | getGraph().setColor(col); | ||||
return true; | return true; | ||||
} else { | } else { | ||||
* @return true if the new paint changes the current paint | * @return true if the new paint changes the current paint | ||||
*/ | */ | ||||
public boolean updatePaint(Paint p) { | public boolean updatePaint(Paint p) { | ||||
if (getGraph().getPaint() == null) { | |||||
Paint currentPaint = getGraph().getPaint(); | |||||
if (currentPaint == null) { | |||||
if (p != null) { | if (p != null) { | ||||
getGraph().setPaint(p); | getGraph().setPaint(p); | ||||
return true; | return true; | ||||
} | } | ||||
} else if (!p.equals(getGraph().getPaint())) { | |||||
} else if (p instanceof Color && currentPaint instanceof Color) { | |||||
if (!ColorUtil.isSameColor((Color)p, (Color)currentPaint)) { | |||||
getGraph().setPaint(p); | |||||
return true; | |||||
} | |||||
} else if (!p.equals(currentPaint)) { | |||||
getGraph().setPaint(p); | getGraph().setPaint(p); | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public String toString() { | public String toString() { | ||||
String s = "Java2DGraphicsState " + currentGraphics.toString() | String s = "Java2DGraphicsState " + currentGraphics.toString() | ||||
+ ", Stroke (width: " + currentStrokeWidth + " style: " | + ", Stroke (width: " + currentStrokeWidth + " style: " |
import org.apache.fop.pdf.PDFICCBasedColorSpace; | import org.apache.fop.pdf.PDFICCBasedColorSpace; | ||||
import org.apache.fop.pdf.PDFICCStream; | import org.apache.fop.pdf.PDFICCStream; | ||||
import org.apache.fop.pdf.PDFImage; | import org.apache.fop.pdf.PDFImage; | ||||
import org.apache.fop.pdf.PDFName; | |||||
import org.apache.fop.pdf.PDFReference; | import org.apache.fop.pdf.PDFReference; | ||||
/** | /** | ||||
} else { | } else { | ||||
if (cs == null && desc.startsWith("sRGB")) { | if (cs == null && desc.startsWith("sRGB")) { | ||||
//It's the default sRGB profile which we mapped to DefaultRGB in PDFRenderer | //It's the default sRGB profile which we mapped to DefaultRGB in PDFRenderer | ||||
cs = doc.getResources().getColorSpace("DefaultRGB"); | |||||
cs = (PDFICCBasedColorSpace)doc.getResources().getColorSpace( | |||||
new PDFName("DefaultRGB")); | |||||
} | } | ||||
if (cs == null) { | if (cs == null) { | ||||
// sRGB hasn't been set up for the PDF document | // sRGB hasn't been set up for the PDF document |
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import org.apache.fop.pdf.PDFColor; | |||||
import org.apache.fop.pdf.PDFColorHandler; | |||||
import org.apache.fop.pdf.PDFDocument; | import org.apache.fop.pdf.PDFDocument; | ||||
import org.apache.fop.pdf.PDFFilterList; | import org.apache.fop.pdf.PDFFilterList; | ||||
import org.apache.fop.pdf.PDFNumber; | import org.apache.fop.pdf.PDFNumber; | ||||
/** the current stream to add PDF commands to */ | /** the current stream to add PDF commands to */ | ||||
private PDFStream currentStream; | private PDFStream currentStream; | ||||
private PDFColorHandler colorHandler; | |||||
/** drawing state */ | /** drawing state */ | ||||
protected PDFPaintingState currentState = null; | protected PDFPaintingState currentState = null; | ||||
/** Text generation utility holding the current font status */ | /** Text generation utility holding the current font status */ | ||||
}; | }; | ||||
this.currentState = new PDFPaintingState(); | this.currentState = new PDFPaintingState(); | ||||
this.colorHandler = new PDFColorHandler(document.getResources()); | |||||
} | } | ||||
/** | /** | ||||
*/ | */ | ||||
public void setColor(Color col, boolean fill, PDFStream stream) { | public void setColor(Color col, boolean fill, PDFStream stream) { | ||||
assert stream != null; | assert stream != null; | ||||
PDFColor color = new PDFColor(this.document, col); | |||||
stream.add(color.getColorSpaceOut(fill)); | |||||
StringBuffer sb = new StringBuffer(); | |||||
setColor(col, fill, sb); | |||||
stream.add(sb.toString()); | |||||
} | } | ||||
/** | /** | ||||
*/ | */ | ||||
protected void setColor(Color col, boolean fill, StringBuffer pdf) { | protected void setColor(Color col, boolean fill, StringBuffer pdf) { | ||||
if (pdf != null) { | if (pdf != null) { | ||||
PDFColor color = new PDFColor(this.document, col); | |||||
pdf.append(color.getColorSpaceOut(fill)); | |||||
colorHandler.establishColor(pdf, col, fill); | |||||
} else { | } else { | ||||
setColor(col, fill, this.currentStream); | setColor(col, fill, this.currentStream); | ||||
} | } |
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
public void setUserAgent(FOUserAgent agent) { | public void setUserAgent(FOUserAgent agent) { | ||||
super.setUserAgent(agent); | super.setUserAgent(agent); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void setupFontInfo(FontInfo inFontInfo) throws FOPException { | public void setupFontInfo(FontInfo inFontInfo) throws FOPException { | ||||
if (mimic != null) { | if (mimic != null) { | ||||
mimic.setupFontInfo(inFontInfo); | mimic.setupFontInfo(inFontInfo); | ||||
//TODO Remove the following line (makes changes in the test checks necessary) | //TODO Remove the following line (makes changes in the test checks necessary) | ||||
addAttribute(name, bkg.toString()); | addAttribute(name, bkg.toString()); | ||||
if (bkg.getColor() != null) { | if (bkg.getColor() != null) { | ||||
addAttribute("bkg-color", bkg.getColor().toString()); | |||||
addAttribute("bkg-color", ColorUtil.colorToString(bkg.getColor())); | |||||
} | } | ||||
if (bkg.getURL() != null) { | if (bkg.getURL() != null) { | ||||
addAttribute("bkg-img", bkg.getURL()); | addAttribute("bkg-img", bkg.getURL()); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void processOffDocumentItem(OffDocumentItem oDI) { | public void processOffDocumentItem(OffDocumentItem oDI) { | ||||
if (oDI instanceof BookmarkData) { | if (oDI instanceof BookmarkData) { | ||||
renderBookmarkTree((BookmarkData) oDI); | renderBookmarkTree((BookmarkData) oDI); | ||||
* Renders a BookmarkTree object | * Renders a BookmarkTree object | ||||
* @param bookmarkRoot the BookmarkData object representing the top of the tree | * @param bookmarkRoot the BookmarkData object representing the top of the tree | ||||
*/ | */ | ||||
@Override | |||||
protected void renderBookmarkTree(BookmarkData bookmarkRoot) { | protected void renderBookmarkTree(BookmarkData bookmarkRoot) { | ||||
if (bookmarkRoot.getWhenToProcess() == OffDocumentItem.END_OF_DOC) { | if (bookmarkRoot.getWhenToProcess() == OffDocumentItem.END_OF_DOC) { | ||||
endPageSequence(); | endPageSequence(); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void startRenderer(OutputStream outputStream) | public void startRenderer(OutputStream outputStream) | ||||
throws IOException { | throws IOException { | ||||
log.debug("Rendering areas to Area Tree XML"); | log.debug("Rendering areas to Area Tree XML"); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void stopRenderer() throws IOException { | public void stopRenderer() throws IOException { | ||||
endPageSequence(); | endPageSequence(); | ||||
endElement("areaTree"); | endElement("areaTree"); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void renderPage(PageViewport page) throws IOException, FOPException { | public void renderPage(PageViewport page) throws IOException, FOPException { | ||||
atts.clear(); | atts.clear(); | ||||
addAttribute("bounds", page.getViewArea()); | addAttribute("bounds", page.getViewArea()); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
protected void handleExtensionAttachments(List attachments) { | protected void handleExtensionAttachments(List attachments) { | ||||
if (attachments != null && attachments.size() > 0) { | if (attachments != null && attachments.size() > 0) { | ||||
startElement("extension-attachments"); | startElement("extension-attachments"); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void startPageSequence(PageSequence pageSequence) { | public void startPageSequence(PageSequence pageSequence) { | ||||
handleDocumentExtensionAttachments(); | handleDocumentExtensionAttachments(); | ||||
endPageSequence(); // move this before handleDocumentExtensionAttachments() ? | endPageSequence(); // move this before handleDocumentExtensionAttachments() ? | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderRegionViewport(RegionViewport port) { | protected void renderRegionViewport(RegionViewport port) { | ||||
if (port != null) { | if (port != null) { | ||||
atts.clear(); | atts.clear(); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
protected void startVParea(CTM ctm, Rectangle2D clippingRect) { | protected void startVParea(CTM ctm, Rectangle2D clippingRect) { | ||||
//only necessary for graphical output | //only necessary for graphical output | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
protected void endVParea() { | protected void endVParea() { | ||||
//only necessary for graphical output | //only necessary for graphical output | ||||
} | } | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
* org.apache.fop.area.inline.InlineArea) | * org.apache.fop.area.inline.InlineArea) | ||||
*/ | */ | ||||
@Override | |||||
protected void renderInlineAreaBackAndBorders(InlineArea area) { | protected void renderInlineAreaBackAndBorders(InlineArea area) { | ||||
//only necessary for graphical output | //only necessary for graphical output | ||||
} | } | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderBeforeFloat(BeforeFloat bf) { | protected void renderBeforeFloat(BeforeFloat bf) { | ||||
startElement("beforeFloat"); | startElement("beforeFloat"); | ||||
super.renderBeforeFloat(bf); | super.renderBeforeFloat(bf); | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderFootnote(Footnote footnote) { | protected void renderFootnote(Footnote footnote) { | ||||
atts.clear(); | atts.clear(); | ||||
addAttribute("top-offset", footnote.getTop()); | addAttribute("top-offset", footnote.getTop()); | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderMainReference(MainReference mr) { | protected void renderMainReference(MainReference mr) { | ||||
atts.clear(); | atts.clear(); | ||||
addAreaAttributes(mr); | addAreaAttributes(mr); | ||||
addTraitAttributes(span); | addTraitAttributes(span); | ||||
startElement("span", atts); | startElement("span", atts); | ||||
for (int c = 0; c < span.getColumnCount(); c++) { | for (int c = 0; c < span.getColumnCount(); c++) { | ||||
NormalFlow flow = (NormalFlow) span.getNormalFlow(c); | |||||
NormalFlow flow = span.getNormalFlow(c); | |||||
renderFlow(flow); | renderFlow(flow); | ||||
} | } | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderFlow(NormalFlow flow) { | protected void renderFlow(NormalFlow flow) { | ||||
// the normal flow reference area contains stacked blocks | // the normal flow reference area contains stacked blocks | ||||
atts.clear(); | atts.clear(); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
protected void renderReferenceArea(Block block) { | protected void renderReferenceArea(Block block) { | ||||
handleBlockTraits(block); | handleBlockTraits(block); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
protected void renderBlock(Block block) { | protected void renderBlock(Block block) { | ||||
atts.clear(); | atts.clear(); | ||||
addAreaAttributes(block); | addAreaAttributes(block); | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderLineArea(LineArea line) { | protected void renderLineArea(LineArea line) { | ||||
atts.clear(); | atts.clear(); | ||||
addAreaAttributes(line); | addAreaAttributes(line); | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderInlineArea(InlineArea inlineArea) { | protected void renderInlineArea(InlineArea inlineArea) { | ||||
atts.clear(); | atts.clear(); | ||||
if (inlineArea.getClass() == InlineArea.class) { | if (inlineArea.getClass() == InlineArea.class) { | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderViewport(Viewport viewport) { | protected void renderViewport(Viewport viewport) { | ||||
atts.clear(); | atts.clear(); | ||||
addAreaAttributes(viewport); | addAreaAttributes(viewport); | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
public void renderImage(Image image, Rectangle2D pos) { | public void renderImage(Image image, Rectangle2D pos) { | ||||
atts.clear(); | atts.clear(); | ||||
addAreaAttributes(image); | addAreaAttributes(image); | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
public void renderContainer(Container cont) { | public void renderContainer(Container cont) { | ||||
startElement("container"); | startElement("container"); | ||||
super.renderContainer(cont); | super.renderContainer(cont); | ||||
* @param pos the position of the foreign object | * @param pos the position of the foreign object | ||||
* @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D) | * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D) | ||||
*/ | */ | ||||
@Override | |||||
public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { | public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { | ||||
atts.clear(); | atts.clear(); | ||||
addAreaAttributes(fo); | addAreaAttributes(fo); | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderInlineSpace(Space space) { | protected void renderInlineSpace(Space space) { | ||||
atts.clear(); | atts.clear(); | ||||
addAreaAttributes(space); | addAreaAttributes(space); | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderText(TextArea text) { | protected void renderText(TextArea text) { | ||||
atts.clear(); | atts.clear(); | ||||
if (text.getTextWordSpaceAdjust() != 0) { | if (text.getTextWordSpaceAdjust() != 0) { | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderWord(WordArea word) { | protected void renderWord(WordArea word) { | ||||
atts.clear(); | atts.clear(); | ||||
addAttribute("offset", word.getOffset()); | addAttribute("offset", word.getOffset()); | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderSpace(SpaceArea space) { | protected void renderSpace(SpaceArea space) { | ||||
atts.clear(); | atts.clear(); | ||||
addAttribute("offset", space.getOffset()); | addAttribute("offset", space.getOffset()); | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderInlineParent(InlineParent ip) { | protected void renderInlineParent(InlineParent ip) { | ||||
atts.clear(); | atts.clear(); | ||||
addAreaAttributes(ip); | addAreaAttributes(ip); | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderInlineBlockParent(InlineBlockParent ibp) { | protected void renderInlineBlockParent(InlineBlockParent ibp) { | ||||
atts.clear(); | atts.clear(); | ||||
addAreaAttributes(ibp); | addAreaAttributes(ibp); | ||||
/** | /** | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
@Override | |||||
protected void renderLeader(Leader area) { | protected void renderLeader(Leader area) { | ||||
atts.clear(); | atts.clear(); | ||||
addAreaAttributes(area); | addAreaAttributes(area); |
import org.apache.batik.bridge.DocumentLoader; | import org.apache.batik.bridge.DocumentLoader; | ||||
import org.apache.batik.bridge.SVGTextElementBridge; | import org.apache.batik.bridge.SVGTextElementBridge; | ||||
import org.apache.batik.bridge.UserAgent; | import org.apache.batik.bridge.UserAgent; | ||||
import org.apache.batik.dom.svg.SVGOMDocument; | |||||
import org.apache.batik.gvt.TextPainter; | import org.apache.batik.gvt.TextPainter; | ||||
import org.apache.xmlgraphics.image.loader.ImageManager; | import org.apache.xmlgraphics.image.loader.ImageManager; | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public void registerSVGBridges() { | public void registerSVGBridges() { | ||||
super.registerSVGBridges(); | super.registerSVGBridges(); | ||||
putBridge(new PDFImageElementBridge()); | putBridge(new PDFImageElementBridge()); | ||||
} | } | ||||
// Make sure any 'sub bridge contexts' also have our bridges. | |||||
//TODO There's no matching method in the super-class here | |||||
/** @return the new bridge context */ | |||||
/** {@inheritDoc} */ | |||||
@Override | |||||
public BridgeContext createBridgeContext() { | public BridgeContext createBridgeContext() { | ||||
//Retained for pre-Batik-1.7 compatibility | |||||
return createBridgeContext(null); | |||||
} | |||||
/** {@inheritDoc} */ | |||||
@Override | |||||
public BridgeContext createBridgeContext(SVGOMDocument doc) { | |||||
// Make sure any 'sub bridge contexts' also have our bridges. | |||||
return new PDFBridgeContext(getUserAgent(), getDocumentLoader(), | return new PDFBridgeContext(getUserAgent(), getDocumentLoader(), | ||||
fontInfo, | fontInfo, | ||||
getImageManager(), | getImageManager(), |
import org.apache.fop.fonts.FontInfo; | import org.apache.fop.fonts.FontInfo; | ||||
import org.apache.fop.fonts.FontSetup; | import org.apache.fop.fonts.FontSetup; | ||||
import org.apache.fop.pdf.PDFAnnotList; | import org.apache.fop.pdf.PDFAnnotList; | ||||
import org.apache.fop.pdf.PDFColor; | |||||
import org.apache.fop.pdf.PDFColorHandler; | |||||
import org.apache.fop.pdf.PDFDocument; | import org.apache.fop.pdf.PDFDocument; | ||||
import org.apache.fop.pdf.PDFFilterList; | import org.apache.fop.pdf.PDFFilterList; | ||||
import org.apache.fop.pdf.PDFNumber; | import org.apache.fop.pdf.PDFNumber; | ||||
this.pdfDoc = new PDFDocument("Apache FOP Version " + Version.getVersion() | this.pdfDoc = new PDFDocument("Apache FOP Version " + Version.getVersion() | ||||
+ ": PDFDocumentGraphics2D"); | + ": PDFDocumentGraphics2D"); | ||||
this.pdfContext = new PDFContext(); | this.pdfContext = new PDFContext(); | ||||
this.colorHandler = new PDFColorHandler(this.pdfDoc.getResources()); | |||||
} | } | ||||
/** | /** | ||||
* @param col the background colour to fill | * @param col the background colour to fill | ||||
*/ | */ | ||||
public void setBackgroundColor(Color col) { | public void setBackgroundColor(Color col) { | ||||
Color c = col; | |||||
PDFColor currentColour = new PDFColor(c.getRed(), c.getGreen(), c.getBlue()); | |||||
currentStream.write("q\n"); | |||||
currentStream.write(currentColour.getColorSpaceOut(true)); | |||||
StringBuffer sb = new StringBuffer(); | |||||
sb.append("q\n"); | |||||
this.colorHandler.establishColor(sb, col, true); | |||||
currentStream.write("0 0 " + width + " " + height + " re\n"); | |||||
sb.append("0 0 ").append(width).append(" ").append(height).append(" re\n"); | |||||
currentStream.write("f\n"); | |||||
currentStream.write("Q\n"); | |||||
sb.append("f\n"); | |||||
sb.append("Q\n"); | |||||
currentStream.write(sb.toString()); | |||||
} | } | ||||
/** | /** |
import org.apache.fop.pdf.BitmapImage; | import org.apache.fop.pdf.BitmapImage; | ||||
import org.apache.fop.pdf.PDFAnnotList; | import org.apache.fop.pdf.PDFAnnotList; | ||||
import org.apache.fop.pdf.PDFColor; | import org.apache.fop.pdf.PDFColor; | ||||
import org.apache.fop.pdf.PDFColorHandler; | |||||
import org.apache.fop.pdf.PDFConformanceException; | import org.apache.fop.pdf.PDFConformanceException; | ||||
import org.apache.fop.pdf.PDFDeviceColorSpace; | import org.apache.fop.pdf.PDFDeviceColorSpace; | ||||
import org.apache.fop.pdf.PDFDocument; | import org.apache.fop.pdf.PDFDocument; | ||||
import org.apache.fop.render.pdf.ImageRawCCITTFaxAdapter; | import org.apache.fop.render.pdf.ImageRawCCITTFaxAdapter; | ||||
import org.apache.fop.render.pdf.ImageRawJPEGAdapter; | import org.apache.fop.render.pdf.ImageRawJPEGAdapter; | ||||
import org.apache.fop.render.pdf.ImageRenderedAdapter; | import org.apache.fop.render.pdf.ImageRenderedAdapter; | ||||
import org.apache.fop.util.ColorExt; | |||||
/** | /** | ||||
* PDF Graphics 2D. | * PDF Graphics 2D. | ||||
*/ | */ | ||||
protected PDFPaintingState paintingState; | protected PDFPaintingState paintingState; | ||||
/** the PDF color handler */ | |||||
protected PDFColorHandler colorHandler; | |||||
/** | /** | ||||
* The PDF graphics state level that this svg is being drawn into. | * The PDF graphics state level that this svg is being drawn into. | ||||
*/ | */ | ||||
PDFResourceContext page, String pref, String font, float size) { | PDFResourceContext page, String pref, String font, float size) { | ||||
this(textAsShapes); | this(textAsShapes); | ||||
pdfDoc = doc; | pdfDoc = doc; | ||||
this.colorHandler = new PDFColorHandler(doc.getResources()); | |||||
resourceContext = page; | resourceContext = page; | ||||
currentFontName = font; | currentFontName = font; | ||||
currentFontSize = size; | currentFontSize = size; | ||||
public PDFGraphics2D(PDFGraphics2D g) { | public PDFGraphics2D(PDFGraphics2D g) { | ||||
super(g); | super(g); | ||||
this.pdfDoc = g.pdfDoc; | this.pdfDoc = g.pdfDoc; | ||||
this.colorHandler = g.colorHandler; | |||||
this.resourceContext = g.resourceContext; | this.resourceContext = g.resourceContext; | ||||
this.currentFontName = g.currentFontName; | this.currentFontName = g.currentFontName; | ||||
this.currentFontSize = g.currentFontSize; | this.currentFontSize = g.currentFontSize; | ||||
protected void applyColor(Color col, boolean fill) { | protected void applyColor(Color col, boolean fill) { | ||||
preparePainting(); | preparePainting(); | ||||
Color c = col; | |||||
if (col instanceof ColorExt) { | |||||
PDFColor currentColour = new PDFColor(this.pdfDoc, col); | |||||
currentStream.write(currentColour.getColorSpaceOut(fill)); | |||||
} else if (c.getColorSpace().getType() | |||||
== ColorSpace.TYPE_RGB) { | |||||
PDFColor currentColour = new PDFColor(c.getRed(), c.getGreen(), | |||||
c.getBlue()); | |||||
currentStream.write(currentColour.getColorSpaceOut(fill)); | |||||
} else if (c.getColorSpace().getType() | |||||
== ColorSpace.TYPE_CMYK) { | |||||
if (pdfDoc.getProfile().getPDFAMode().isPDFA1LevelB()) { | |||||
//See PDF/A-1, ISO 19005:1:2005(E), 6.2.3.3 | |||||
//FOP is currently restricted to DeviceRGB if PDF/A-1 is active. | |||||
throw new PDFConformanceException( | |||||
"PDF/A-1 does not allow mixing DeviceRGB and DeviceCMYK."); | |||||
} | |||||
PDFColor currentColour = new PDFColor(c); | |||||
currentStream.write(currentColour.getColorSpaceOut(fill)); | |||||
} else if (c.getColorSpace().getType() | |||||
== ColorSpace.TYPE_2CLR) { | |||||
// used for black/magenta | |||||
float[] cComps = c.getColorComponents(new float[1]); | |||||
double[] blackMagenta = new double[1]; | |||||
for (int i = 0; i < 1; i++) { | |||||
blackMagenta[i] = cComps[i]; | |||||
} | |||||
//PDFColor currentColour = new PDFColor(blackMagenta[0], blackMagenta[1]); | |||||
//currentStream.write(currentColour.getColorSpaceOut(fill)); | |||||
} else { | |||||
throw new UnsupportedOperationException( | |||||
"Color Space not supported by PDFGraphics2D: " + c.getColorSpace()); | |||||
//TODO Handle this in PDFColorHandler by automatically converting the color. | |||||
//This won't work properly anyway after the redesign of ColorExt | |||||
if (col.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { | |||||
if (pdfDoc.getProfile().getPDFAMode().isPDFA1LevelB()) { | |||||
//See PDF/A-1, ISO 19005:1:2005(E), 6.2.3.3 | |||||
//FOP is currently restricted to DeviceRGB if PDF/A-1 is active. | |||||
throw new PDFConformanceException( | |||||
"PDF/A-1 does not allow mixing DeviceRGB and DeviceCMYK."); | |||||
} | |||||
} | } | ||||
StringBuffer sb = new StringBuffer(); | |||||
colorHandler.establishColor(sb, col, fill); | |||||
currentStream.write(sb.toString()); | |||||
} | } | ||||
/** | /** | ||||
return false; // PDF can't do alpha | return false; // PDF can't do alpha | ||||
} | } | ||||
PDFColor color1 = new PDFColor(c1.getRed(), c1.getGreen(), | |||||
c1.getBlue()); | |||||
someColors.add(color1); | |||||
//PDFColor color1 = new PDFColor(c1.getRed(), c1.getGreen(), | |||||
// c1.getBlue()); | |||||
someColors.add(c1); | |||||
if (count > 0 && count < cols.length - 1) { | if (count > 0 && count < cols.length - 1) { | ||||
theBounds.add(new Double(fractions[count])); | theBounds.add(new Double(fractions[count])); | ||||
} | } | ||||
} | } | ||||
//Gradients are currently restricted to sRGB | |||||
PDFDeviceColorSpace aColorSpace; | PDFDeviceColorSpace aColorSpace; | ||||
aColorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); | aColorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); | ||||
PDFPattern myPat = pdfDoc.getFactory().makeGradient( | PDFPattern myPat = pdfDoc.getFactory().makeGradient( | ||||
return false; // PDF can't do alpha | return false; // PDF can't do alpha | ||||
} | } | ||||
someColors.add(new PDFColor(cc.getRed(), cc.getGreen(), | |||||
cc.getBlue())); | |||||
someColors.add(cc); | |||||
} | } | ||||
float[] fractions = rgp.getFractions(); | float[] fractions = rgp.getFractions(); |
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public int hashCode() { | public int hashCode() { | ||||
return toString().hashCode(); | return toString().hashCode(); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public boolean equals(Object obj) { | public boolean equals(Object obj) { | ||||
if (obj == null) { | if (obj == null) { | ||||
return false; | return false; | ||||
if (obj instanceof BorderProps) { | if (obj instanceof BorderProps) { | ||||
BorderProps other = (BorderProps)obj; | BorderProps other = (BorderProps)obj; | ||||
return (style == other.style) | return (style == other.style) | ||||
&& color.equals(other.color) | |||||
&& org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor( | |||||
color, other.color) | |||||
&& width == other.width | && width == other.width | ||||
&& mode == other.mode; | && mode == other.mode; | ||||
} | } | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public String toString() { | public String toString() { | ||||
StringBuffer sbuf = new StringBuffer(); | StringBuffer sbuf = new StringBuffer(); | ||||
sbuf.append('('); | sbuf.append('('); |
* @return true if the color has changed | * @return true if the color has changed | ||||
*/ | */ | ||||
public boolean setColor(Color col) { | public boolean setColor(Color col) { | ||||
if (!col.equals(getData().color)) { | |||||
Color other = getData().color; | |||||
if (!org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor(col, other)) { | |||||
getData().color = col; | getData().color = col; | ||||
return true; | return true; | ||||
} | } | ||||
* @return true if the color has changed | * @return true if the color has changed | ||||
*/ | */ | ||||
public boolean setBackColor(Color col) { | public boolean setBackColor(Color col) { | ||||
if (!col.equals(getData().backColor)) { | |||||
Color other = getData().backColor; | |||||
if (!org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor(col, other)) { | |||||
getData().backColor = col; | getData().backColor = col; | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public Object clone() { | public Object clone() { | ||||
AbstractPaintingState state = instantiate(); | AbstractPaintingState state = instantiate(); | ||||
state.stateStack = new StateStack(this.stateStack); | state.stateStack = new StateStack(this.stateStack); | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public String toString() { | public String toString() { | ||||
return ", stateStack=" + stateStack | return ", stateStack=" + stateStack | ||||
+ ", currentData=" + data; | + ", currentData=" + data; | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public Object clone() { | public Object clone() { | ||||
AbstractData data = instantiate(); | AbstractData data = instantiate(); | ||||
data.color = this.color; | data.color = this.color; | ||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | |||||
public String toString() { | public String toString() { | ||||
return "color=" + color | return "color=" + color | ||||
+ ", backColor=" + backColor | + ", backColor=" + backColor |
<<<<<<< .working | |||||
/* | /* | ||||
* Licensed to the Apache Software Foundation (ASF) under one or more | * Licensed to the Apache Software Foundation (ASF) under one or more | ||||
* contributor license agreements. See the NOTICE file distributed with | * contributor license agreements. See the NOTICE file distributed with | ||||
} | } | ||||
} | } | ||||
======= | |||||
/* | |||||
* 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 java.util.Arrays; | |||||
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; | |||||
/** | |||||
* Color helper class. | |||||
* <p> | |||||
* This class extends java.awt.Color class keeping track of the original color | |||||
* property values specified by the fo user in a rgb-icc call. | |||||
* @deprecated Replaced by {@link ColorWithAlternatives} | |||||
*/ | |||||
@Deprecated | |||||
public final class ColorExt extends Color { | |||||
// | |||||
private static final long serialVersionUID = 1L; | |||||
// Values of fop-rgb-icc arguments | |||||
private float rgbReplacementRed; | |||||
private float rgbReplacementGreen; | |||||
private float rgbReplacementBlue; | |||||
private String iccProfileName; | |||||
private String iccProfileSrc; | |||||
private ColorSpace colorSpace; | |||||
private float[] colorValues; | |||||
/* | |||||
* Helper for createFromFoRgbIcc | |||||
*/ | |||||
private ColorExt(ColorSpace colorSpace, float[] colorValues, float opacity) { | |||||
super(colorSpace, colorValues, opacity); | |||||
} | |||||
/* | |||||
* Helper for createFromSvgIccColor | |||||
*/ | |||||
private ColorExt(float red, float green, float blue, float opacity) { | |||||
super(red, green, blue, opacity); | |||||
} | |||||
/** | |||||
* Create ColorExt object backup up FO's rgb-icc color function | |||||
* | |||||
* @param redReplacement | |||||
* Red part of RGB replacement color that will be used when ICC | |||||
* profile can not be loaded | |||||
* @param greenReplacement | |||||
* Green part of RGB replacement color that will be used when ICC | |||||
* profile can not be loaded | |||||
* @param blueReplacement | |||||
* Blue part of RGB replacement color that will be used when ICC | |||||
* profile can not be loaded | |||||
* @param profileName | |||||
* Name of ICC profile | |||||
* @param profileSrc | |||||
* Source of ICC profile | |||||
* @param colorSpace | |||||
* ICC ColorSpace for the ICC profile | |||||
* @param iccValues | |||||
* color values | |||||
* @return the requested color object | |||||
*/ | |||||
public static ColorExt createFromFoRgbIcc(float redReplacement, | |||||
float greenReplacement, float blueReplacement, String profileName, | |||||
String profileSrc, ColorSpace colorSpace, float[] iccValues) { | |||||
ColorExt ce = new ColorExt(colorSpace, iccValues, 1.0f); | |||||
ce.rgbReplacementRed = redReplacement; | |||||
ce.rgbReplacementGreen = greenReplacement; | |||||
ce.rgbReplacementBlue = blueReplacement; | |||||
ce.iccProfileName = profileName; | |||||
ce.iccProfileSrc = profileSrc; | |||||
ce.colorSpace = colorSpace; | |||||
ce.colorValues = iccValues; | |||||
return ce; | |||||
} | |||||
/** | |||||
* Create ColorExt object backing up SVG's icc-color function. | |||||
* | |||||
* @param red | |||||
* Red value resulting from the conversion from the user provided | |||||
* (icc) color values to the batik (rgb) color space | |||||
* @param green | |||||
* Green value resulting from the conversion from the user | |||||
* provided (icc) color values to the batik (rgb) color space | |||||
* @param blue | |||||
* Blue value resulting from the conversion from the user | |||||
* provided (icc) color values to the batik (rgb) color space | |||||
* @param opacity | |||||
* Opacity | |||||
* @param profileName | |||||
* ICC profile name | |||||
* @param profileHref | |||||
* the URI to the color profile | |||||
* @param profileCS | |||||
* ICC ColorSpace profile | |||||
* @param colorValues | |||||
* ICC color values | |||||
* @return the requested color object | |||||
*/ | |||||
public static ColorExt createFromSvgIccColor( // CSOK: ParameterNumber | |||||
float red, float green, | |||||
float blue, float opacity, String profileName, String profileHref, | |||||
ColorSpace profileCS, float[] colorValues) { | |||||
//TODO this method is not referenced by FOP, can it be deleted? | |||||
ColorExt ce = new ColorExt(red, green, blue, opacity); | |||||
ce.rgbReplacementRed = -1; | |||||
ce.rgbReplacementGreen = -1; | |||||
ce.rgbReplacementBlue = -1; | |||||
ce.iccProfileName = profileName; | |||||
ce.iccProfileSrc = profileHref; | |||||
ce.colorSpace = profileCS; | |||||
ce.colorValues = colorValues; | |||||
return ce; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
@Override | |||||
public int hashCode() { | |||||
//implementation from the superclass should be good enough for our purposes | |||||
return super.hashCode(); | |||||
} | |||||
/** {@inheritDoc} */ | |||||
@Override | |||||
public boolean equals(Object obj) { | |||||
if (this == obj) { | |||||
return true; | |||||
} | |||||
if (!super.equals(obj)) { | |||||
return false; | |||||
} | |||||
if (getClass() != obj.getClass()) { | |||||
return false; | |||||
} | |||||
ColorExt other = (ColorExt)obj; | |||||
//TODO maybe use super.getColorComponents() instead | |||||
if (!Arrays.equals(colorValues, other.colorValues)) { | |||||
return false; | |||||
} | |||||
if (iccProfileName == null) { | |||||
if (other.iccProfileName != null) { | |||||
return false; | |||||
} | |||||
} else if (!iccProfileName.equals(other.iccProfileName)) { | |||||
return false; | |||||
} | |||||
if (iccProfileSrc == null) { | |||||
if (other.iccProfileSrc != null) { | |||||
return false; | |||||
} | |||||
} else if (!iccProfileSrc.equals(other.iccProfileSrc)) { | |||||
return false; | |||||
} | |||||
if (Float.floatToIntBits(rgbReplacementBlue) | |||||
!= Float.floatToIntBits(other.rgbReplacementBlue)) { | |||||
return false; | |||||
} | |||||
if (Float.floatToIntBits(rgbReplacementGreen) | |||||
!= Float.floatToIntBits(other.rgbReplacementGreen)) { | |||||
return false; | |||||
} | |||||
if (Float.floatToIntBits(rgbReplacementRed) | |||||
!= Float.floatToIntBits(other.rgbReplacementRed)) { | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* Get ICC profile name | |||||
* | |||||
* @return ICC profile name | |||||
*/ | |||||
public String getIccProfileName() { | |||||
return this.iccProfileName; | |||||
} | |||||
/** | |||||
* Get ICC profile source | |||||
* | |||||
* @return ICC profile source | |||||
*/ | |||||
public String getIccProfileSrc() { | |||||
return this.iccProfileSrc; | |||||
} | |||||
/** | |||||
* @return the original ColorSpace | |||||
*/ | |||||
public ColorSpace getOrigColorSpace() { | |||||
//TODO this method is probably unnecessary due to super.cs and getColorSpace() | |||||
return this.colorSpace; | |||||
} | |||||
/** | |||||
* Returns the original color values. | |||||
* @return the original color values | |||||
*/ | |||||
public float[] getOriginalColorComponents() { | |||||
//TODO this method is probably unnecessary due to super.fvalue and getColorComponents() | |||||
float[] copy = new float[this.colorValues.length]; | |||||
System.arraycopy(this.colorValues, 0, copy, 0, copy.length); | |||||
return copy; | |||||
} | |||||
/** | |||||
* Create string representation of fop-rgb-icc function call to map this | |||||
* ColorExt settings | |||||
* @return the string representing the internal fop-rgb-icc() function call | |||||
*/ | |||||
public String toFunctionCall() { | |||||
StringBuffer sb = new StringBuffer(40); | |||||
sb.append("fop-rgb-icc("); | |||||
sb.append(this.rgbReplacementRed + ","); | |||||
sb.append(this.rgbReplacementGreen + ","); | |||||
sb.append(this.rgbReplacementBlue + ","); | |||||
sb.append(this.iccProfileName + ","); | |||||
if (this.iccProfileSrc != null) { | |||||
sb.append("\"" + this.iccProfileSrc + "\""); | |||||
} | |||||
float[] colorComponents = this.getColorComponents(null); | |||||
for (int ix = 0; ix < colorComponents.length; ix++) { | |||||
sb.append(","); | |||||
sb.append(colorComponents[ix]); | |||||
} | |||||
sb.append(")"); | |||||
return sb.toString(); | |||||
} | |||||
} | |||||
>>>>>>> .merge-right.r1069429 |
package org.apache.fop.util; | package org.apache.fop.util; | ||||
import java.awt.color.ColorSpace; | import java.awt.color.ColorSpace; | ||||
import java.awt.color.ICC_ColorSpace; | |||||
import java.awt.color.ICC_Profile; | import java.awt.color.ICC_Profile; | ||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.Map; | import java.util.Map; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.xmlgraphics.java2d.color.profile.ColorProfileUtil; | import org.apache.xmlgraphics.java2d.color.profile.ColorProfileUtil; | ||||
import org.apache.xmlgraphics.java2d.color.ICCColorSpaceWithIntent; | |||||
import org.apache.xmlgraphics.java2d.color.RenderingIntent; | |||||
/** | /** | ||||
* Map with cached ICC based ColorSpace objects. | * Map with cached ICC based ColorSpace objects. | ||||
*/ | */ | ||||
* The FOP URI resolver is used to try and locate the ICC file. | * The FOP URI resolver is used to try and locate the ICC file. | ||||
* If that fails null is returned. | * If that fails null is returned. | ||||
* | * | ||||
* @param profileName the profile name | |||||
* @param base a base URI to resolve relative URIs | * @param base a base URI to resolve relative URIs | ||||
* @param iccProfileSrc ICC Profile source to return a ColorSpace for | * @param iccProfileSrc ICC Profile source to return a ColorSpace for | ||||
* @param renderingIntent overriding rendering intent | |||||
* @return ICC ColorSpace object or null if ColorSpace could not be created | * @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, | |||||
RenderingIntent renderingIntent) { | |||||
String key = profileName + ":" + base + iccProfileSrc; | |||||
ColorSpace colorSpace = null; | ColorSpace colorSpace = null; | ||||
if (!colorSpaceMap.containsKey(base + iccProfileSrc)) { | |||||
if (!colorSpaceMap.containsKey(key)) { | |||||
try { | try { | ||||
ICC_Profile iccProfile = null; | ICC_Profile iccProfile = null; | ||||
// First attempt to use the FOP URI resolver to locate the ICC | // First attempt to use the FOP URI resolver to locate the ICC | ||||
// iccProfile = ICC_Profile.getInstance(iccProfileSrc); | // iccProfile = ICC_Profile.getInstance(iccProfileSrc); | ||||
} | } | ||||
if (iccProfile != null) { | if (iccProfile != null) { | ||||
colorSpace = new ICC_ColorSpace(iccProfile); | |||||
colorSpace = new ICCColorSpaceWithIntent(iccProfile, renderingIntent, | |||||
profileName, iccProfileSrc); | |||||
} | } | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
// Ignore exception - will be logged a bit further down | // Ignore exception - will be logged a bit further down | ||||
if (colorSpace != null) { | if (colorSpace != null) { | ||||
// Put in cache (not when VM resolved it as we can't control | // Put in cache (not when VM resolved it as we can't control | ||||
colorSpaceMap.put(base + iccProfileSrc, colorSpace); | |||||
colorSpaceMap.put(key, colorSpace); | |||||
} else { | } else { | ||||
// TODO To avoid an excessive amount of warnings perhaps | // TODO To avoid an excessive amount of warnings perhaps | ||||
// register a null ColorMap in the colorSpaceMap | // register a null ColorMap in the colorSpaceMap | ||||
log.warn("Color profile '" + iccProfileSrc + "' not found."); | log.warn("Color profile '" + iccProfileSrc + "' not found."); | ||||
} | } | ||||
} else { | } else { | ||||
colorSpace = colorSpaceMap.get(base + iccProfileSrc); | |||||
colorSpace = colorSpaceMap.get(key); | |||||
} | } | ||||
return colorSpace; | return colorSpace; | ||||
} | } |
/* | |||||
* 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; | |||||
} | |||||
} |
documents. Example: the fix of marks layering will be such a case when it's done. | documents. Example: the fix of marks layering will be such a case when it's done. | ||||
--> | --> | ||||
<release version="FOP Trunk" date="TBD"> | <release version="FOP Trunk" date="TBD"> | ||||
<action context="Renderers" dev="JM" type="add"> | |||||
Added support for CIE Lab colors (from XSL-FO 2.0 WD). | |||||
</action> | |||||
<action context="Renderers" dev="JM" type="add" fixes-bug="49403" due-to="Patrick Jaromin"> | |||||
Initial work on spot colors (aka named colors) for PDF output. | |||||
</action> | |||||
<action context="Renderers" dev="JM" type="fix" fixes-bug="50705" due-to="Mehdi Houshmand"> | <action context="Renderers" dev="JM" type="fix" fixes-bug="50705" due-to="Mehdi Houshmand"> | ||||
Fix to preserve the order of AFP TLEs and NOPs as given in the XSL-FO document. | Fix to preserve the order of AFP TLEs and NOPs as given in the XSL-FO document. | ||||
</action> | </action> |
import junit.framework.TestCase; | import junit.framework.TestCase; | ||||
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.DeviceCMYKColorSpace; | ||||
import org.apache.fop.fo.Constants; | import org.apache.fop.fo.Constants; | ||||
import org.apache.fop.util.ColorExt; | |||||
import org.apache.fop.util.ColorUtil; | import org.apache.fop.util.ColorUtil; | ||||
/** | /** | ||||
assertEquals(b1, b2); | assertEquals(b1, b2); | ||||
float[] cmyk = new float[] {1.0f, 1.0f, 0.5f, 1.0f}; | float[] cmyk = new float[] {1.0f, 1.0f, 0.5f, 1.0f}; | ||||
DeviceCMYKColorSpace cmykCs = ColorSpaces.getDeviceCMYKColorSpace(); | |||||
float[] rgb = cmykCs.toRGB(cmyk); | |||||
col = ColorExt.createFromFoRgbIcc(rgb[0], rgb[1], rgb[2], | |||||
"#CMYK", null, cmykCs, cmyk); | |||||
col = DeviceCMYKColorSpace.createCMYKColor(cmyk); | |||||
//Convert to sRGB with CMYK alternative as constructed by the cmyk() function | |||||
float[] rgb = col.getRGBColorComponents(null); | |||||
col = new ColorWithAlternatives(rgb[0], rgb[1], rgb[2], new Color[] {col}); | |||||
b1 = new BorderProps(Constants.EN_INSET, 9999, | b1 = new BorderProps(Constants.EN_INSET, 9999, | ||||
col, BorderProps.SEPARATE); | col, BorderProps.SEPARATE); | ||||
ser = b1.toString(); | ser = b1.toString(); |
import java.awt.Color; | import java.awt.Color; | ||||
import java.awt.color.ColorSpace; | import java.awt.color.ColorSpace; | ||||
import java.net.URI; | |||||
import junit.framework.TestCase; | import junit.framework.TestCase; | ||||
import org.apache.xmlgraphics.java2d.color.ColorSpaces; | import org.apache.xmlgraphics.java2d.color.ColorSpaces; | ||||
import org.apache.xmlgraphics.java2d.color.ColorWithAlternatives; | |||||
import org.apache.xmlgraphics.java2d.color.NamedColorSpace; | |||||
import org.apache.xmlgraphics.java2d.color.RenderingIntent; | |||||
import org.apache.fop.apps.FOUserAgent; | import org.apache.fop.apps.FOUserAgent; | ||||
import org.apache.fop.apps.FopFactory; | import org.apache.fop.apps.FopFactory; | ||||
assertEquals(col1, col2); | 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)"); | 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)"); | col2 = ColorUtil.parseColorString(null, "cmyk(0.0,0.0,0.0,0.5)"); | ||||
assertEquals(col1, col2); | 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)"); | 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)); | |||||
assertTrue(col1.equals(col2)); | |||||
assertFalse(org.apache.xmlgraphics.java2d.color.ColorUtil.isSameColor(col1, col2)); | |||||
} | } | ||||
/** | /** | ||||
*/ | */ | ||||
public void testRGBICC() throws Exception { | public void testRGBICC() throws Exception { | ||||
FopFactory fopFactory = FopFactory.newInstance(); | FopFactory fopFactory = FopFactory.newInstance(); | ||||
ColorSpace cs = fopFactory.getColorSpace(null, | |||||
"src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm"); | |||||
assertNotNull(cs); | |||||
URI sRGBLoc = new URI( | |||||
"file:src/java/org/apache/fop/pdf/sRGB%20Color%20Space%20Profile.icm"); | |||||
ColorSpace cs = fopFactory.getColorSpaceCache().get( | |||||
"sRGBAlt", null, sRGBLoc.toASCIIString(), RenderingIntent.AUTO); | |||||
assertNotNull("Color profile not found", cs); | |||||
FOUserAgent ua = fopFactory.newFOUserAgent(); | FOUserAgent ua = fopFactory.newFOUserAgent(); | ||||
ColorExt colActual; | |||||
ColorWithFallback colActual; | |||||
//fop-rgb-icc() is used instead of rgb-icc() inside FOP! | //fop-rgb-icc() is used instead of rgb-icc() inside FOP! | ||||
String colSpec = "fop-rgb-icc(1.0,0.0,0.0,sRGBAlt," | 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 | |||||
+ "\"" + sRGBLoc.toASCIIString() + "\",1.0,0.0,0.0)"; | |||||
colActual = (ColorWithFallback)ColorUtil.parseColorString(ua, colSpec); | |||||
assertEquals(cs, colActual.getColorSpace()); | |||||
assertEquals(255, colActual.getRed(), 2f); //Java 5: 253, Java 6: 255 | |||||
assertEquals(0, colActual.getGreen(), 25f); //Java 5: 25, Java 6: 0 | |||||
assertEquals(0, colActual.getBlue()); | |||||
//I don't understand the difference. Maybe Java's sRGB and HP's sRGB are somehow not | //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 | //equivalent. This is only going to be a problem if anyone actually makes use of the | ||||
//RGB fallback in any renderer. | //RGB fallback in any renderer. | ||||
//TODO Anyone know what's going on here? | //TODO Anyone know what's going on here? | ||||
assertEquals(0, colActual.getBlue()); | |||||
assertEquals(cs, colActual.getColorSpace()); | |||||
float[] comps = colActual.getColorComponents(null); | float[] comps = colActual.getColorComponents(null); | ||||
assertEquals(3, comps.length); | assertEquals(3, comps.length); | ||||
assertEquals(1f, comps[0], 0); | assertEquals(1f, comps[0], 0); | ||||
assertEquals(0f, comps[1], 0); | assertEquals(0f, comps[1], 0); | ||||
assertEquals(0f, comps[2], 0); | assertEquals(0f, comps[2], 0); | ||||
assertEquals(0, colActual.getAlternativeColors().length); | |||||
Color fallback = colActual.getFallbackColor(); | |||||
assertTrue(fallback.getColorSpace().isCS_sRGB()); | |||||
assertEquals(255, fallback.getRed()); | |||||
assertEquals(0, fallback.getGreen()); | |||||
assertEquals(0, fallback.getBlue()); | |||||
assertEquals(colSpec, ColorUtil.colorToString(colActual)); | assertEquals(colSpec, ColorUtil.colorToString(colActual)); | ||||
* @throws Exception if an error occurs | * @throws Exception if an error occurs | ||||
*/ | */ | ||||
public void testCMYK() throws Exception { | public void testCMYK() throws Exception { | ||||
ColorExt colActual; | |||||
ColorWithAlternatives colActual; | |||||
String colSpec; | String colSpec; | ||||
colSpec = "cmyk(0.0, 0.0, 1.0, 0.0)"; | 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.getRed()); | ||||
assertEquals(255, colActual.getGreen()); | assertEquals(255, colActual.getGreen()); | ||||
assertEquals(0, colActual.getBlue()); | assertEquals(0, colActual.getBlue()); | ||||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), colActual.getColorSpace()); | |||||
float[] comps = colActual.getColorComponents(null); | |||||
Color alt = colActual.getAlternativeColors()[0]; | |||||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace()); | |||||
float[] comps = alt.getColorComponents(null); | |||||
assertEquals(4, comps.length); | assertEquals(4, comps.length); | ||||
assertEquals(0f, comps[0], 0); | assertEquals(0f, comps[0], 0); | ||||
assertEquals(0f, comps[1], 0); | assertEquals(0f, comps[1], 0); | ||||
ColorUtil.colorToString(colActual)); | ColorUtil.colorToString(colActual)); | ||||
colSpec = "cmyk(0.0274, 0.2196, 0.3216, 0.0)"; | 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(ColorSpaces.getDeviceCMYKColorSpace(), colActual.getColorSpace()); | |||||
comps = colActual.getColorComponents(null); | |||||
colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec); | |||||
assertEquals(248, colActual.getRed(), 1); | |||||
assertEquals(199, colActual.getGreen(), 1); | |||||
assertEquals(172, colActual.getBlue(), 1); | |||||
alt = colActual.getAlternativeColors()[0]; | |||||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace()); | |||||
comps = alt.getColorComponents(null); | |||||
assertEquals(0.0274f, comps[0], 0.001); | assertEquals(0.0274f, comps[0], 0.001); | ||||
assertEquals(0.2196f, comps[1], 0.001); | assertEquals(0.2196f, comps[1], 0.001); | ||||
assertEquals(0.3216f, comps[2], 0.001); | assertEquals(0.3216f, comps[2], 0.001); | ||||
ColorUtil.colorToString(colActual)); | ColorUtil.colorToString(colActual)); | ||||
colSpec = "fop-rgb-icc(1.0,1.0,0.0,#CMYK,,0.0,0.0,1.0,0.0)"; | 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.getRed()); | ||||
assertEquals(255, colActual.getGreen()); | assertEquals(255, colActual.getGreen()); | ||||
assertEquals(0, colActual.getBlue()); | assertEquals(0, colActual.getBlue()); | ||||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), colActual.getColorSpace()); | |||||
comps = colActual.getColorComponents(null); | |||||
alt = colActual.getAlternativeColors()[0]; | |||||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace()); | |||||
comps = alt.getColorComponents(null); | |||||
assertEquals(4, comps.length); | assertEquals(4, comps.length); | ||||
assertEquals(0f, comps[0], 0); | assertEquals(0f, comps[0], 0); | ||||
assertEquals(0f, comps[1], 0); | assertEquals(0f, comps[1], 0); | ||||
ColorUtil.colorToString(colActual)); | ColorUtil.colorToString(colActual)); | ||||
colSpec = "fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.0,0.0,0.0,0.5)"; | 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); | |||||
assertEquals(127, colActual.getRed()); | |||||
assertEquals(127, colActual.getGreen()); | |||||
assertEquals(127, colActual.getBlue()); | |||||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), colActual.getColorSpace()); | |||||
comps = colActual.getColorComponents(null); | |||||
colActual = (ColorWithAlternatives)ColorUtil.parseColorString(null, colSpec); | |||||
assertEquals(127, colActual.getRed(), 1); | |||||
assertEquals(127, colActual.getGreen(), 1); | |||||
assertEquals(127, colActual.getBlue(), 1); | |||||
alt = colActual.getAlternativeColors()[0]; | |||||
assertEquals(ColorSpaces.getDeviceCMYKColorSpace(), alt.getColorSpace()); | |||||
comps = alt.getColorComponents(null); | |||||
assertEquals(4, comps.length); | assertEquals(4, comps.length); | ||||
assertEquals(0f, comps[0], 0); | assertEquals(0f, comps[0], 0); | ||||
assertEquals(0f, comps[1], 0); | assertEquals(0f, comps[1], 0); | ||||
assertEquals(0.5f, comps[3], 0); | assertEquals(0.5f, comps[3], 0); | ||||
assertEquals("fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.0,0.0,0.0,0.5)", | assertEquals("fop-rgb-icc(0.5,0.5,0.5,#CMYK,,0.0,0.0,0.0,0.5)", | ||||
ColorUtil.colorToString(colActual)); | ColorUtil.colorToString(colActual)); | ||||
//Verify that the cmyk() and fop-rgb-icc(#CMYK) functions have the same results | |||||
ColorWithAlternatives colCMYK = (ColorWithAlternatives)ColorUtil.parseColorString( | |||||
null, "cmyk(0,0,0,0.5)"); | |||||
assertEquals(colCMYK.getAlternativeColors()[0], colActual.getAlternativeColors()[0]); | |||||
//The following doesn't work: | |||||
//assertEquals(colCMYK, colActual); | |||||
//java.awt.Color does not consistenly calculate the int RGB values: | |||||
//Color(ColorSpace cspace, float components[], float alpha): 0.5 --> 127 | |||||
//Color(float r, float g, float b): 0.5 --> 128 | |||||
if (!colCMYK.equals(colActual)) { | |||||
System.out.println("Info: java.awt.Color does not consistently calculate" | |||||
+ " int RGB values from float RGB values."); | |||||
} | |||||
} | |||||
/** | |||||
* Tests color for the #Separation pseudo-colorspace. | |||||
* @throws Exception if an error occurs | |||||
*/ | |||||
public void testSeparationColor() throws Exception { | |||||
ColorWithFallback colActual; | |||||
String colSpec; | |||||
colSpec = "fop-rgb-icc(1.0,0.8,0.0,#Separation,,Postgelb)"; | |||||
colActual = (ColorWithFallback)ColorUtil.parseColorString(null, colSpec); | |||||
assertEquals(255, colActual.getRed(), 5); | |||||
assertEquals(204, colActual.getGreen(), 3); | |||||
assertEquals(0, colActual.getBlue(), 12); | |||||
//sRGB results differ between JDKs | |||||
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)colActual.getColorSpace(); | |||||
assertEquals("Postgelb", ncs.getColorName()); | |||||
float[] comps = colActual.getColorComponents(null); | |||||
assertEquals(1, comps.length); | |||||
assertEquals(1f, comps[0], 0); | |||||
assertEquals(colSpec, ColorUtil.colorToString(colActual)); | |||||
} | } | ||||
/** | |||||
* Tests the fop-rgb-named-color() function. | |||||
* @throws Exception if an error occurs | |||||
*/ | |||||
public void testNamedColorProfile() throws Exception { | |||||
FopFactory fopFactory = FopFactory.newInstance(); | |||||
URI ncpLoc = new URI("file:test/resources/color/ncp-example.icc"); | |||||
ColorSpace cs = fopFactory.getColorSpaceCache().get( | |||||
"NCP", null, ncpLoc.toASCIIString(), RenderingIntent.AUTO); | |||||
assertNotNull("Color profile not found", cs); | |||||
FOUserAgent ua = fopFactory.newFOUserAgent(); | |||||
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 = (ColorWithFallback)ColorUtil.parseColorString(ua, colSpec); | |||||
assertEquals(255, colActual.getRed(), 2); | |||||
assertEquals(193, colActual.getGreen(), 2); | |||||
assertEquals(0, colActual.getBlue()); | |||||
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); | |||||
assertTrue(colActual.getColorSpace() instanceof NamedColorSpace); | |||||
NamedColorSpace ncs; | |||||
ncs = (NamedColorSpace)colActual.getColorSpace(); | |||||
assertEquals("Postgelb", ncs.getColorName()); | |||||
comps = colActual.getColorComponents(null); | |||||
assertEquals(1, comps.length); | |||||
assertEquals(1f, comps[0], 0); | |||||
assertEquals(colSpec, ColorUtil.colorToString(colActual)); | |||||
} | |||||
} | } |