Browse Source

Re-integrate/merge Temp_Color branch into Trunk.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1069439 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_1rc1old
Jeremias Maerki 13 years ago
parent
commit
3df0d00cdc
38 changed files with 2145 additions and 623 deletions
  1. 67
    23
      src/java/org/apache/fop/afp/goca/GraphicsSetProcessColor.java
  2. 8
    1
      src/java/org/apache/fop/afp/modca/GraphicsObject.java
  3. 33
    1
      src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java
  4. 18
    18
      src/java/org/apache/fop/apps/FopFactory.java
  5. 94
    0
      src/java/org/apache/fop/fo/expr/CIELabColorFunction.java
  6. 112
    0
      src/java/org/apache/fop/fo/expr/NamedColorFunction.java
  7. 2
    0
      src/java/org/apache/fop/fo/expr/PropertyParser.java
  8. 2
    3
      src/java/org/apache/fop/fo/expr/PropertyTokenizer.java
  9. 8
    1
      src/java/org/apache/fop/fo/properties/ColorProperty.java
  10. 91
    0
      src/java/org/apache/fop/pdf/PDFCIELabColorSpace.java
  11. 10
    93
      src/java/org/apache/fop/pdf/PDFColor.java
  12. 231
    0
      src/java/org/apache/fop/pdf/PDFColorHandler.java
  13. 26
    0
      src/java/org/apache/fop/pdf/PDFDeviceColorSpace.java
  14. 10
    6
      src/java/org/apache/fop/pdf/PDFDocument.java
  15. 59
    14
      src/java/org/apache/fop/pdf/PDFFactory.java
  16. 23
    0
      src/java/org/apache/fop/pdf/PDFName.java
  17. 17
    3
      src/java/org/apache/fop/pdf/PDFPaintingState.java
  18. 48
    69
      src/java/org/apache/fop/pdf/PDFResources.java
  19. 88
    0
      src/java/org/apache/fop/pdf/PDFSeparationColorSpace.java
  20. 14
    1
      src/java/org/apache/fop/render/intermediate/IFSerializer.java
  21. 3
    1
      src/java/org/apache/fop/render/intermediate/IFState.java
  22. 12
    3
      src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java
  23. 3
    1
      src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java
  24. 8
    5
      src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
  25. 34
    2
      src/java/org/apache/fop/render/xml/XMLRenderer.java
  26. 12
    3
      src/java/org/apache/fop/svg/PDFBridgeContext.java
  27. 9
    8
      src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java
  28. 24
    38
      src/java/org/apache/fop/svg/PDFGraphics2D.java
  29. 5
    1
      src/java/org/apache/fop/traits/BorderProps.java
  30. 8
    2
      src/java/org/apache/fop/util/AbstractPaintingState.java
  31. 259
    0
      src/java/org/apache/fop/util/ColorExt.java
  32. 13
    6
      src/java/org/apache/fop/util/ColorSpaceCache.java
  33. 557
    283
      src/java/org/apache/fop/util/ColorUtil.java
  34. 85
    0
      src/java/org/apache/fop/util/ColorWithFallback.java
  35. 6
    0
      status.xml
  36. 5
    6
      test/java/org/apache/fop/traits/BorderPropsTestCase.java
  37. 141
    31
      test/java/org/apache/fop/util/ColorUtilTestCase.java
  38. BIN
      test/resources/color/ncp-example.icc

+ 67
- 23
src/java/org/apache/fop/afp/goca/GraphicsSetProcessColor.java View File



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 + ")";
} }

+ 8
- 1
src/java/org/apache/fop/afp/modca/GraphicsObject.java View File

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);

+ 33
- 1
src/java/org/apache/fop/afp/ptoca/PtocaBuilder.java View File



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

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



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;
} }


} }

+ 94
- 0
src/java/org/apache/fop/fo/expr/CIELabColorFunction.java View File

/*
* 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;
}

}

}

+ 112
- 0
src/java/org/apache/fop/fo/expr/NamedColorFunction.java View File

/*
* 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;
}
}
}

+ 2
- 0
src/java/org/apache/fop/fo/expr/PropertyParser.java View File

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!!!


/** /**

+ 2
- 3
src/java/org/apache/fop/fo/expr/PropertyTokenizer.java View File

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;
} }

+ 8
- 1
src/java/org/apache/fop/fo/properties/ColorProperty.java View File

* @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();
} }

+ 91
- 0
src/java/org/apache/fop/pdf/PDFCIELabColorSpace.java View File

/*
* 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;
}

}

+ 10
- 93
src/java/org/apache/fop/pdf/PDFColor.java View File



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

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

/*
* 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");
}

}

+ 26
- 0
src/java/org/apache/fop/pdf/PDFDeviceColorSpace.java View File



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;
}

} }

+ 10
- 6
src/java/org/apache/fop/pdf/PDFDocument.java View File

*/ */
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;

+ 59
- 14
src/java/org/apache/fop/pdf/PDFFactory.java View File

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).
* *

+ 23
- 0
src/java/org/apache/fop/pdf/PDFName.java View File

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);

+ 17
- 3
src/java/org/apache/fop/pdf/PDFPaintingState.java View File



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();
} }

+ 48
- 69
src/java/org/apache/fop/pdf/PDFResources.java View File



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();
} }


} }

+ 88
- 0
src/java/org/apache/fop/pdf/PDFSeparationColorSpace.java View File

/*
* 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;
}

}

+ 14
- 1
src/java/org/apache/fop/render/intermediate/IFSerializer.java View File

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));

+ 3
- 1
src/java/org/apache/fop/render/intermediate/IFState.java View File



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;

+ 12
- 3
src/java/org/apache/fop/render/java2d/Java2DGraphicsState.java View File

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: "

+ 3
- 1
src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java View File

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

+ 8
- 5
src/java/org/apache/fop/render/pdf/PDFContentGenerator.java View File

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);
} }

+ 34
- 2
src/java/org/apache/fop/render/xml/XMLRenderer.java View File

/** /**
* {@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);

+ 12
- 3
src/java/org/apache/fop/svg/PDFBridgeContext.java View File

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(),

+ 9
- 8
src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java View File

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());
} }


/** /**

+ 24
- 38
src/java/org/apache/fop/svg/PDFGraphics2D.java View File

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();

+ 5
- 1
src/java/org/apache/fop/traits/BorderProps.java View File

} }


/** {@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('(');

+ 8
- 2
src/java/org/apache/fop/util/AbstractPaintingState.java View File

* @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

+ 259
- 0
src/java/org/apache/fop/util/ColorExt.java View File

<<<<<<< .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

+ 13
- 6
src/java/org/apache/fop/util/ColorSpaceCache.java View File

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;
} }

+ 557
- 283
src/java/org/apache/fop/util/ColorUtil.java
File diff suppressed because it is too large
View File


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

/*
* 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;
}

}

+ 6
- 0
status.xml View File

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>

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



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();

+ 141
- 31
test/java/org/apache/fop/util/ColorUtilTestCase.java View File



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));
}
} }

BIN
test/resources/color/ncp-example.icc View File


Loading…
Cancel
Save