diff options
author | Vincent Hennebert <vhennebert@apache.org> | 2014-07-18 19:48:02 +0000 |
---|---|---|
committer | Vincent Hennebert <vhennebert@apache.org> | 2014-07-18 19:48:02 +0000 |
commit | cdf8be3d3a3f4fde67723863d368b1096c305de9 (patch) | |
tree | 1e761f8593c6e5aad411be786ad5f83b1a454c68 /src/java/org/apache | |
parent | d8823a706376a572303ab86004c7370b12ef7d85 (diff) | |
parent | 27b9b2ecbfca055a3aad1eddeefd2c7f4aa62ad7 (diff) | |
download | xmlgraphics-fop-cdf8be3d3a3f4fde67723863d368b1096c305de9.tar.gz xmlgraphics-fop-cdf8be3d3a3f4fde67723863d368b1096c305de9.zip |
Merged branch FOP-2393_gradient-rendering back into trunk
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1611783 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache')
23 files changed, 1105 insertions, 3420 deletions
diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java index b1e23f35f..cad0a405d 100644 --- a/src/java/org/apache/fop/pdf/PDFFactory.java +++ b/src/java/org/apache/fop/pdf/PDFFactory.java @@ -20,14 +20,12 @@ package org.apache.fop.pdf; // Java -import java.awt.Color; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.text.DecimalFormat; -import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Iterator; @@ -41,7 +39,6 @@ import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.logging.Log; 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; @@ -244,188 +241,35 @@ public class PDFFactory { /* ========================= functions ================================= */ /** - * Make a Type 0 sampled function - * - * @param theDomain List objects of Double objects. - * This is the domain of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theRange List objects of Double objects. - * This is the Range of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theSize A List object of Integer objects. - * This is the number of samples in each input dimension. - * I can't imagine there being more or less than two input dimensions, - * so maybe this should be an array of length 2. - * - * See page 265 of the PDF 1.3 Spec. - * @param theBitsPerSample An int specifying the number of bits user - * to represent each sample value. - * Limited to 1,2,4,8,12,16,24 or 32. - * See page 265 of the 1.3 PDF Spec. - * @param theOrder The order of interpolation between samples. - * Default is 1 (one). Limited - * to 1 (one) or 3, which means linear or cubic-spline interpolation. - * - * This attribute is optional. - * - * See page 265 in the PDF 1.3 spec. - * @param theEncode List objects of Double objects. - * This is the linear mapping of input values intop the domain - * of the function's sample table. Default is hard to represent in - * ascii, but basically [0 (Size0 1) 0 (Size1 1)...]. - * This attribute is optional. - * - * See page 265 in the PDF 1.3 spec. - * @param theDecode List objects of Double objects. - * This is a linear mapping of sample values into the range. - * The default is just the range. - * - * This attribute is optional. - * Read about it on page 265 of the PDF 1.3 spec. - * @param theFunctionDataStream The sample values that specify - * the function are provided in a stream. - * - * This is optional, but is almost always used. - * - * Page 265 of the PDF 1.3 spec has more. - * @param theFilter This is a vector of String objects which - * are the various filters that have are to be - * applied to the stream to make sense of it. - * Order matters, so watch out. - * - * This is not documented in the Function section of the PDF 1.3 spec, - * it was deduced from samples that this is sometimes used, even if we may never - * use it in FOP. It is added for completeness sake. - * @param theFunctionType This is the type of function (0,2,3, or 4). - * It should be 0 as this is the constructor for sampled functions. - * @return the PDF function that was created - */ - public PDFFunction makeFunction(int theFunctionType, List theDomain, - List theRange, List theSize, - int theBitsPerSample, int theOrder, - List theEncode, List theDecode, - StringBuffer theFunctionDataStream, - List theFilter) { - // Type 0 function - PDFFunction function = new PDFFunction(theFunctionType, theDomain, - theRange, theSize, - theBitsPerSample, theOrder, - theEncode, theDecode, - theFunctionDataStream, - theFilter); - - function = registerFunction(function); - return (function); - } - - /** * make a type Exponential interpolation function * (for shading usually) - * - * @param theDomain List objects of Double objects. + * @param domain List objects of Double objects. * This is the domain of the function. * See page 264 of the PDF 1.3 Spec. - * @param theRange List of Doubles that is the Range of the function. + * @param range List of Doubles that is the Range of the function. * See page 264 of the PDF 1.3 Spec. - * @param theCZero This is a vector of Double objects which defines the function result + * @param cZero This is a vector of Double objects which defines the function result * when x=0. * * This attribute is optional. * It's described on page 268 of the PDF 1.3 spec. - * @param theCOne This is a vector of Double objects which defines the function result + * @param cOne This is a vector of Double objects which defines the function result * when x=1. * * This attribute is optional. * It's described on page 268 of the PDF 1.3 spec. - * @param theInterpolationExponentN This is the inerpolation exponent. + * @param interpolationExponentN This is the inerpolation exponent. * * This attribute is required. * PDF Spec page 268 - * @param theFunctionType The type of the function, which should be 2. - * @return the PDF function that was created - */ - public PDFFunction makeFunction(int theFunctionType, List theDomain, - List theRange, List theCZero, - List theCOne, - double theInterpolationExponentN) { // type 2 - PDFFunction function = new PDFFunction(theFunctionType, theDomain, - theRange, theCZero, theCOne, - theInterpolationExponentN); - function = registerFunction(function); - return (function); - } - - /** - * Make a Type 3 Stitching function * - * @param theDomain List objects of Double objects. - * This is the domain of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theRange List objects of Double objects. - * This is the Range of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theFunctions An List of the PDFFunction objects - * that the stitching function stitches. - * - * This attributed is required. - * It is described on page 269 of the PDF spec. - * @param theBounds This is a vector of Doubles representing - * the numbers that, in conjunction with Domain - * define the intervals to which each function from - * the 'functions' object applies. It must be in - * order of increasing magnitude, and each must be - * within Domain. - * - * It basically sets how much of the gradient each function handles. - * - * This attributed is required. - * It's described on page 269 of the PDF 1.3 spec. - * @param theEncode List objects of Double objects. - * This is the linear mapping of input values intop the domain - * of the function's sample table. Default is hard to represent in - * ascii, but basically [0 (Size0 1) 0 (Size1 1)...]. - * This attribute is required. - * - * See page 270 in the PDF 1.3 spec. - * @param theFunctionType This is the function type. It should be 3, - * for a stitching function. * @return the PDF function that was created */ - public PDFFunction makeFunction(int theFunctionType, List theDomain, - List theRange, List theFunctions, - List theBounds, - List theEncode) { - // Type 3 - - PDFFunction function = new PDFFunction(theFunctionType, theDomain, - theRange, theFunctions, - theBounds, theEncode); - + public PDFFunction makeFunction(List domain, List range, float[] cZero, float[] cOne, + double interpolationExponentN) { + PDFFunction function = new PDFFunction(domain, range, cZero, cOne, interpolationExponentN); function = registerFunction(function); - return (function); - } - - /** - * make a postscript calculator function - * - * @param theNumber the PDF object number - * @param theFunctionType the type of function to make - * @param theDomain the domain values - * @param theRange the range values of the function - * @param theFunctionDataStream a string containing the pdf drawing - * @return the PDF function that was created - */ - public PDFFunction makeFunction(int theNumber, int theFunctionType, - List theDomain, List theRange, - StringBuffer theFunctionDataStream) { - // Type 4 - PDFFunction function = new PDFFunction(theFunctionType, theDomain, - theRange, - theFunctionDataStream); - - function = registerFunction(function); - return (function); - + return function; } /** @@ -445,175 +289,6 @@ public class PDFFactory { /* ========================= shadings ================================== */ /** - * make a function based shading object - * - * @param res the PDF resource context to add the shading, may be null - * @param theShadingType The type of shading object, which should be 1 for function - * based shading. - * @param theColorSpace The colorspace is 'DeviceRGB' or something similar. - * @param theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox List of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Whether or not to anti-alias. - * @param theDomain Optional vector of Doubles specifying the domain. - * @param theMatrix List of Doubles specifying the matrix. - * If it's a pattern, then the matrix maps it to pattern space. - * If it's a shading, then it maps it to current user space. - * It's optional, the default is the identity matrix - * @param theFunction The PDF Function that maps an (x,y) location to a color - * @return the PDF shading that was created - */ - public PDFShading makeShading(PDFResourceContext res, int theShadingType, - PDFDeviceColorSpace theColorSpace, - List theBackground, List theBBox, - boolean theAntiAlias, List theDomain, - List theMatrix, - PDFFunction theFunction) { - // make Shading of Type 1 - PDFShading shading = new PDFShading(theShadingType, - theColorSpace, theBackground, - theBBox, theAntiAlias, theDomain, - theMatrix, theFunction); - - shading = registerShading(res, shading); - return (shading); - } - - /** - * Make an axial or radial shading object. - * - * @param res the PDF resource context to add the shading, may be null - * @param theShadingType 2 or 3 for axial or radial shading - * @param theColorSpace "DeviceRGB" or similar. - * @param theBackground theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox List of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Default is false - * @param theCoords List of four (type 2) or 6 (type 3) Double - * @param theDomain List of Doubles specifying the domain - * @param theFunction the Stitching (PDFfunction type 3) function, - * even if it's stitching a single function - * @param theExtend List of Booleans of whether to extend the - * start and end colors past the start and end points - * The default is [false, false] - * @return the PDF shading that was created - */ - public PDFShading makeShading(PDFResourceContext res, int theShadingType, - PDFDeviceColorSpace theColorSpace, - List theBackground, List theBBox, - boolean theAntiAlias, List theCoords, - List theDomain, PDFFunction theFunction, - List theExtend) { - // make Shading of Type 2 or 3 - PDFShading shading = new PDFShading(theShadingType, - theColorSpace, theBackground, - theBBox, theAntiAlias, theCoords, - theDomain, theFunction, - theExtend); - - shading = registerShading(res, shading); - - return (shading); - } - - /** - * Make a free-form gouraud shaded triangle mesh, coons patch mesh, or tensor patch mesh - * shading object - * - * @param res the PDF resource context to add the shading, may be null - * @param theShadingType 4, 6, or 7 depending on whether it's - * Free-form gouraud-shaded triangle meshes, coons patch meshes, - * or tensor product patch meshes, respectively. - * @param theColorSpace "DeviceRGB" or similar. - * @param theBackground theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox List of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Default is false - * @param theBitsPerCoordinate 1,2,4,8,12,16,24 or 32. - * @param theBitsPerComponent 1,2,4,8,12, and 16 - * @param theBitsPerFlag 2,4,8. - * @param theDecode List of Doubles see PDF 1.3 spec pages 303 to 312. - * @param theFunction the PDFFunction - * @return the PDF shading that was created - */ - public PDFShading makeShading(PDFResourceContext res, int theShadingType, - PDFDeviceColorSpace theColorSpace, - List theBackground, List theBBox, - boolean theAntiAlias, - int theBitsPerCoordinate, - int theBitsPerComponent, - int theBitsPerFlag, List theDecode, - PDFFunction theFunction) { - // make Shading of type 4,6 or 7 - PDFShading shading = new PDFShading(theShadingType, - theColorSpace, theBackground, - theBBox, theAntiAlias, - theBitsPerCoordinate, - theBitsPerComponent, - theBitsPerFlag, theDecode, - theFunction); - - shading = registerShading(res, shading); - - return (shading); - } - - /** - * make a Lattice-Form Gouraud mesh shading object - * - * @param res the PDF resource context to add the shading, may be null - * @param theShadingType 5 for lattice-Form Gouraud shaded-triangle mesh - * without spaces. "Shading1" or "Sh1" are good examples. - * @param theColorSpace "DeviceRGB" or similar. - * @param theBackground theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox List of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Default is false - * @param theBitsPerCoordinate 1,2,4,8,12,16, 24, or 32 - * @param theBitsPerComponent 1,2,4,8,12,24,32 - * @param theDecode List of Doubles. See page 305 in PDF 1.3 spec. - * @param theVerticesPerRow number of vertices in each "row" of the lattice. - * @param theFunction The PDFFunction that's mapped on to this shape - * @return the PDF shading that was created - */ - public PDFShading makeShading(PDFResourceContext res, int theShadingType, - PDFDeviceColorSpace theColorSpace, - List theBackground, List theBBox, - boolean theAntiAlias, - int theBitsPerCoordinate, - int theBitsPerComponent, List theDecode, - int theVerticesPerRow, - PDFFunction theFunction) { - // make shading of Type 5 - PDFShading shading = new PDFShading(theShadingType, - theColorSpace, theBackground, - theBBox, theAntiAlias, - theBitsPerCoordinate, - theBitsPerComponent, theDecode, - theVerticesPerRow, theFunction); - - shading = registerShading(res, shading); - - return (shading); - } - - /** * Registers a shading object against the document * @param res The PDF resource context * @param shading The shading object to be registered @@ -697,148 +372,6 @@ public class PDFFactory { return pattern; } - /** - * Make a smooth shading pattern - * - * @param res the PDF resource context to add the shading, may be null - * @param thePatternType the type of the pattern, which is 2, smooth shading - * @param theShading the PDF Shading object that comprises this pattern - * @param theXUID optional:the extended unique Identifier if used. - * @param theExtGState optional: the extended graphics state, if used. - * @param theMatrix Optional:List of Doubles that specify the matrix. - * @return the PDF pattern that was created - */ - public PDFPattern makePattern(PDFResourceContext res, - int thePatternType, PDFShading theShading, - List theXUID, StringBuffer theExtGState, - List theMatrix) { - PDFPattern pattern = new PDFPattern(2, theShading, - theXUID, theExtGState, theMatrix); - - PDFPattern oldpatt = getDocument().findPattern(pattern); - if (oldpatt == null) { - getDocument().registerObject(pattern); - } else { - pattern = oldpatt; - } - - if (res != null) { - res.getPDFResources().addPattern(pattern); - } else { - getDocument().getResources().addPattern(pattern); - } - - return (pattern); - } - - /** - * Make a gradient - * - * @param res the PDF resource context to add the shading, may be null - * @param radial if true a radial gradient will be created - * @param theColorspace the colorspace of the gradient - * @param theColors the list of colors for the gradient - * @param theBounds the list of bounds associated with the colors - * @param theCoords the coordinates for the gradient - * @param theMatrix the coordinate-transformation matrix - * @return the PDF pattern that was created - */ - public PDFPattern makeGradient(PDFResourceContext res, boolean radial, - PDFDeviceColorSpace theColorspace, - List theColors, List theBounds, - List theCoords, List theMatrix) { - PDFShading myShad; - PDFFunction myfunky; - PDFFunction myfunc; - List theCzero; - List theCone; - PDFPattern myPattern; - //PDFColorSpace theColorSpace; - double interpolation = 1.000; - List theFunctions = new ArrayList(); - - int currentPosition; - int lastPosition = theColors.size() - 1; - - - // if 5 elements, the penultimate element is 3. - // do not go beyond that, because you always need - // to have a next color when creating the function. - - for (currentPosition = 0; currentPosition < lastPosition; - currentPosition++) { // for every consecutive color pair - 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 (!nextColor.getColorSpace().isCS_sRGB()) { - //Convert to sRGB - nextColor = ColorUtil.toSRGBColor(nextColor); - theColors.set(currentPosition + 1, nextColor); - } - - theCzero = toColorVector(currentColor); - theCone = toColorVector(nextColor); - - myfunc = makeFunction(2, null, null, theCzero, theCone, - interpolation); - - theFunctions.add(myfunc); - - } // end of for every consecutive color pair - - myfunky = makeFunction(3, null, null, theFunctions, theBounds, - null); - - if (radial) { - if (theCoords.size() == 6) { - myShad = makeShading(res, 3, getDocument().getPDFColorSpace(), - null, null, - false, theCoords, null, myfunky, - null); - } else { // if the center x, center y, and radius specifiy - // the gradient, then assume the same center x, center y, - // and radius of zero for the other necessary component - List newCoords = new ArrayList(); - newCoords.add(theCoords.get(0)); - newCoords.add(theCoords.get(1)); - newCoords.add(theCoords.get(2)); - newCoords.add(theCoords.get(0)); - newCoords.add(theCoords.get(1)); - newCoords.add(new Double(0.0)); - - myShad = makeShading(res, 3, getDocument().getPDFColorSpace(), - null, null, - false, newCoords, null, myfunky, - null); - - } - } else { - myShad = makeShading(res, 2, getDocument().getPDFColorSpace(), - null, null, - false, theCoords, null, myfunky, - null); - - } - - myPattern = makePattern(res, 2, myShad, null, null, theMatrix); - - 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 ============ */ @@ -1866,16 +1399,11 @@ public class PDFFactory { 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); + List domain = Arrays.asList(new Double[] {zero, one}); + List range = Arrays.asList(new Double[] {zero, one, zero, one, zero, one}); + float[] cZero = new float[] {1f, 1f, 1f}; + float[] cOne = ncs.getRGBColor().getColorComponents(null); + PDFFunction tintFunction = makeFunction(domain, range, cZero, cOne, 1.0d); PDFSeparationColorSpace cs = new PDFSeparationColorSpace(colorName, tintFunction); getDocument().registerObject(cs); if (res != null) { diff --git a/src/java/org/apache/fop/pdf/PDFFunction.java b/src/java/org/apache/fop/pdf/PDFFunction.java index 09cbd9708..3ce581d7f 100644 --- a/src/java/org/apache/fop/pdf/PDFFunction.java +++ b/src/java/org/apache/fop/pdf/PDFFunction.java @@ -19,12 +19,15 @@ package org.apache.fop.pdf; -// Java... +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; -import org.apache.fop.render.shading.Function; -import org.apache.fop.render.shading.FunctionDelegate; -import org.apache.fop.render.shading.FunctionPattern; +import org.apache.fop.render.gradient.Function; +import org.apache.fop.render.gradient.Function.SubFunctionRenderer; +import org.apache.fop.render.gradient.GradientMaker; +import org.apache.fop.render.gradient.GradientMaker.DoubleFormatter; /** * class representing a PDF Function. @@ -37,75 +40,11 @@ import org.apache.fop.render.shading.FunctionPattern; * * All PDF Functions have a FunctionType (0,2,3, or 4), a Domain, and a Range. */ -public class PDFFunction extends PDFObject implements Function { +public class PDFFunction extends PDFObject { - private FunctionDelegate delegate; + private final Function function; - /** - * create an complete Function object of Type 0, A Sampled function. - * - * Use null for an optional object parameter if you choose not to use it. - * For optional int parameters, pass the default. - * - * @param theDomain List objects of Double objects. - * This is the domain of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theRange List objects of Double objects. - * This is the Range of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theSize A List object of Integer objects. - * This is the number of samples in each input dimension. - * I can't imagine there being more or less than two input dimensions, - * so maybe this should be an array of length 2. - * - * See page 265 of the PDF 1.3 Spec. - * @param theBitsPerSample An int specifying the number of bits - used to represent each sample value. - * Limited to 1,2,4,8,12,16,24 or 32. - * See page 265 of the 1.3 PDF Spec. - * @param theOrder The order of interpolation between samples. Default is 1 (one). Limited - * to 1 (one) or 3, which means linear or cubic-spline interpolation. - * - * This attribute is optional. - * - * See page 265 in the PDF 1.3 spec. - * @param theEncode List objects of Double objects. - * This is the linear mapping of input values intop the domain - * of the function's sample table. Default is hard to represent in - * ascii, but basically [0 (Size0 1) 0 (Size1 1)...]. - * This attribute is optional. - * - * See page 265 in the PDF 1.3 spec. - * @param theDecode List objects of Double objects. - * This is a linear mapping of sample values into the range. - * The default is just the range. - * - * This attribute is optional. - * Read about it on page 265 of the PDF 1.3 spec. - * @param theFunctionDataStream The sample values that specify - * the function are provided in a stream. - * - * This is optional, but is almost always used. - * - * Page 265 of the PDF 1.3 spec has more. - * @param theFilter This is a vector of String objects which are the various filters that - * have are to be applied to the stream to make sense of it. Order matters, - * so watch out. - * - * This is not documented in the Function section of the PDF 1.3 spec, - * it was deduced from samples that this is sometimes used, even if we may never - * use it in FOP. It is added for completeness sake. - * @param theFunctionType This is the type of function (0,2,3, or 4). - * It should be 0 as this is the constructor for sampled functions. - */ - public PDFFunction(int theFunctionType, List<Double> theDomain, - List<Double> theRange, List<Double> theSize, int theBitsPerSample, - int theOrder, List<Double> theEncode, List<Double> theDecode, - StringBuffer theFunctionDataStream, List<String> theFilter) { - delegate = new FunctionDelegate(this, theFunctionType, theDomain, theRange, - theSize, theBitsPerSample, theOrder, theEncode, theDecode, - theFunctionDataStream, theFilter); - } + private final List<PDFFunction> pdfFunctions; /** * create an complete Function object of Type 2, an Exponential Interpolation function. @@ -113,104 +52,44 @@ public class PDFFunction extends PDFObject implements Function { * Use null for an optional object parameter if you choose not to use it. * For optional int parameters, pass the default. * - * @param theDomain List objects of Double objects. + * @param domain List objects of Double objects. * This is the domain of the function. * See page 264 of the PDF 1.3 Spec. - * @param theRange List of Doubles that is the Range of the function. + * @param range List of Doubles that is the Range of the function. * See page 264 of the PDF 1.3 Spec. - * @param theCZero This is a vector of Double objects which defines the function result + * @param cZero This is a vector of Double objects which defines the function result * when x=0. * * This attribute is optional. * It's described on page 268 of the PDF 1.3 spec. - * @param theCOne This is a vector of Double objects which defines the function result + * @param cOne This is a vector of Double objects which defines the function result * when x=1. * * This attribute is optional. * It's described on page 268 of the PDF 1.3 spec. - * @param theInterpolationExponentN This is the inerpolation exponent. + * @param interpolationExponentN This is the inerpolation exponent. * * This attribute is required. * PDF Spec page 268 - * @param theFunctionType The type of the function, which should be 2. */ - public PDFFunction(int theFunctionType, List<Double> theDomain, - List<Double> theRange, List<Double> theCZero, List<Double> theCOne, - double theInterpolationExponentN) { - delegate = new FunctionDelegate(this, theFunctionType, theDomain, theRange, - theCZero, theCOne, theInterpolationExponentN); + public PDFFunction(List<Double> domain, List<Double> range, float[] cZero, float[] cOne, + double interpolationExponentN) { + this(new Function(domain, range, cZero, cOne, interpolationExponentN)); } - /** - * create an complete Function object of Type 3, a Stitching function. - * - * Use null for an optional object parameter if you choose not to use it. - * For optional int parameters, pass the default. - * - * @param theDomain List objects of Double objects. - * This is the domain of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theRange List objects of Double objects. - * This is the Range of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theFunctions A List of the PDFFunction objects that the stitching function stitches. - * - * This attributed is required. - * It is described on page 269 of the PDF spec. - * @param theBounds This is a vector of Doubles representing the numbers that, - * in conjunction with Domain define the intervals to which each function from - * the 'functions' object applies. It must be in order of increasing magnitude, - * and each must be within Domain. - * - * It basically sets how much of the gradient each function handles. - * - * This attributed is required. - * It's described on page 269 of the PDF 1.3 spec. - * @param theEncode List objects of Double objects. - * This is the linear mapping of input values intop the domain - * of the function's sample table. Default is hard to represent in - * ascii, but basically [0 (Size0 1) 0 (Size1 1)...]. - * This attribute is required. - * - * See page 270 in the PDF 1.3 spec. - * @param theFunctionType This is the function type. It should be 3, - * for a stitching function. - */ - public PDFFunction(int theFunctionType, List<Double> theDomain, - List<Double> theRange, List<Function> theFunctions, - List<Double> theBounds, List<Double> theEncode) { - delegate = new FunctionDelegate(this, theFunctionType, theDomain, theRange, - theFunctions, theBounds, theEncode); + @SuppressWarnings("unchecked") + public PDFFunction(Function function) { + this(function, Collections.EMPTY_LIST); + } + public PDFFunction(Function function, List<PDFFunction> pdfFunctions) { + this.function = function; + this.pdfFunctions = pdfFunctions; } - /** - * create an complete Function object of Type 4, a postscript calculator function. - * - * Use null for an optional object parameter if you choose not to use it. - * For optional int parameters, pass the default. - * - * @param theDomain List object of Double objects. - * This is the domain of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theRange List object of Double objects. - * This is the Range of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theFunctionDataStream This is a stream of arithmetic, - * boolean, and stack operators and boolean constants. - * I end up enclosing it in the '{' and '}' braces for you, so don't do it - * yourself. - * - * This attribute is required. - * It's described on page 269 of the PDF 1.3 spec. - * @param theFunctionType The type of function which should be 4, as this is - * a Postscript calculator function - */ - public PDFFunction(int theFunctionType, List<Double> theDomain, - List<Double> theRange, StringBuffer theFunctionDataStream) { - delegate = new FunctionDelegate(this, theFunctionType, theDomain, theRange, - theFunctionDataStream); + public Function getFunction() { + return function; } /** @@ -230,8 +109,25 @@ public class PDFFunction extends PDFObject implements Function { public byte[] toByteString() { - FunctionPattern pattern = new FunctionPattern(this); - return encode(pattern.toWriteableString()); + List<String> functionsStrings = new ArrayList<String>(function.getFunctions().size()); + for (PDFFunction f : pdfFunctions) { + functionsStrings.add(f.referencePDF()); + } + SubFunctionRenderer subFunctionRenderer = new SubFunctionRenderer() { + + public void outputFunction(StringBuilder out, int functionIndex) { + out.append(pdfFunctions.get(functionIndex).referencePDF()); + } + }; + StringBuilder out = new StringBuilder(); + GradientMaker.DoubleFormatter doubleFormatter = new DoubleFormatter() { + + public String formatDouble(double d) { + return PDFNumber.doubleOut(d); + } + }; + function.output(out, doubleFormatter, subFunctionRenderer); + return encode(out.toString()); } /** {@inheritDoc} */ @@ -245,91 +141,51 @@ public class PDFFunction extends PDFObject implements Function { if (!(obj instanceof PDFFunction)) { return false; } - PDFFunction func = (PDFFunction)obj; - if (delegate.getFunctionType() != func.getFunctionType()) { + Function func = ((PDFFunction) obj).function; + if (function.getFunctionType() != func.getFunctionType()) { return false; } - if (delegate.getBitsPerSample() != func.getBitsPerSample()) { + if (function.getBitsPerSample() != func.getBitsPerSample()) { return false; } - if (delegate.getOrder() != func.getOrder()) { + if (function.getOrder() != func.getOrder()) { return false; } - if (delegate.getInterpolationExponentN() != func.getInterpolationExponentN()) { + if (function.getInterpolationExponentN() != func.getInterpolationExponentN()) { return false; } - if (delegate.getDomain() != null) { - if (!delegate.getDomain().equals(func.getDomain())) { + if (function.getDomain() != null) { + if (!function.getDomain().equals(func.getDomain())) { return false; } } else if (func.getDomain() != null) { return false; } - if (delegate.getRange() != null) { - if (!delegate.getRange().equals(func.getRange())) { + if (function.getRange() != null) { + if (!function.getRange().equals(func.getRange())) { return false; } } else if (func.getRange() != null) { return false; } - if (delegate.getSize() != null) { - if (!delegate.getSize().equals(func.getSize())) { - return false; - } - } else if (func.getSize() != null) { - return false; - } - if (delegate.getEncode() != null) { - if (!delegate.getEncode().equals(func.getEncode())) { + if (function.getEncode() != null) { + if (!function.getEncode().equals(func.getEncode())) { return false; } } else if (func.getEncode() != null) { return false; } - if (delegate.getDecode() != null) { - if (!delegate.getDecode().equals(func.getDecode())) { - return false; - } - } else if (func.getDecode() != null) { - return false; - } - if (delegate.getDataStream() != null) { - if (!delegate.getDataStream().equals(func.getDataStream())) { - return false; - } - } else if (func.getDataStream() != null) { - return false; - } - if (delegate.getFilter() != null) { - if (!delegate.getFilter().equals(func.getFilter())) { - return false; - } - } else if (func.getFilter() != null) { - return false; - } - if (delegate.getCZero() != null) { - if (!delegate.getCZero().equals(func.getCZero())) { - return false; - } - } else if (func.getCZero() != null) { + if (!Arrays.equals(function.getCZero(), func.getCZero())) { return false; } - if (delegate.getCOne() != null) { - if (!delegate.getCOne().equals(func.getCOne())) { - return false; - } - } else if (func.getCOne() != null) { + if (!Arrays.equals(function.getCOne(), func.getCOne())) { return false; } - if (delegate.getFunctions() != null) { - if (!delegate.getFunctions().equals(func.getFunctions())) { - return false; - } - } else if (func.getFunctions() != null) { + if (!pdfFunctions.equals(((PDFFunction) obj).pdfFunctions)) { return false; } - if (delegate.getBounds() != null) { - if (!delegate.getBounds().equals(func.getBounds())) { + if (function.getBounds() != null) { + if (!function.getBounds().equals(func.getBounds())) { return false; } } else if (func.getBounds() != null) { @@ -338,63 +194,4 @@ public class PDFFunction extends PDFObject implements Function { return true; } - public int getFunctionType() { - return delegate.getFunctionType(); - } - - public List<Double> getBounds() { - return delegate.getBounds(); - } - - public List<Double> getDomain() { - return delegate.getDomain(); - } - - public List<Double> getSize() { - return delegate.getSize(); - } - - public List<String> getFilter() { - return delegate.getFilter(); - } - - public List<Double> getEncode() { - return delegate.getEncode(); - } - - public List<Function> getFunctions() { - return delegate.getFunctions(); - } - - public int getBitsPerSample() { - return delegate.getBitsPerSample(); - } - - public double getInterpolationExponentN() { - return delegate.getInterpolationExponentN(); - } - - public int getOrder() { - return delegate.getOrder(); - } - - public List<Double> getRange() { - return delegate.getRange(); - } - - public List<Double> getDecode() { - return delegate.getDecode(); - } - - public StringBuffer getDataStream() { - return delegate.getDataStream(); - } - - public List<Double> getCZero() { - return delegate.getCZero(); - } - - public List<Double> getCOne() { - return delegate.getCOne(); - } } diff --git a/src/java/org/apache/fop/pdf/PDFPattern.java b/src/java/org/apache/fop/pdf/PDFPattern.java index 9871d15dc..7acffa0c9 100644 --- a/src/java/org/apache/fop/pdf/PDFPattern.java +++ b/src/java/org/apache/fop/pdf/PDFPattern.java @@ -23,9 +23,6 @@ import java.io.IOException; import java.io.OutputStream; import java.util.List; -import org.apache.fop.render.shading.Pattern; -import org.apache.fop.render.shading.Shading; - /** * class representing a PDF Function. * @@ -36,7 +33,7 @@ import org.apache.fop.render.shading.Shading; * * All PDF Functions have a FunctionType (0,2,3, or 4), a Domain, and a Range. */ -public class PDFPattern extends PDFPathPaint implements Pattern { +public class PDFPattern extends PDFPathPaint { /** * The resources associated with this pattern @@ -144,19 +141,18 @@ public class PDFPattern extends PDFPathPaint implements Pattern { * Create a type 2 pattern (smooth shading) * * @param thePatternType the type of the pattern, which is 2, smooth shading - * @param theShading the PDF Shading object that comprises this pattern + * @param shading the Shading object that comprises this pattern * @param theXUID optional:the extended unique Identifier if used. * @param theExtGState optional: the extended graphics state, if used. * @param theMatrix Optional:List of Doubles that specify the matrix. */ - public PDFPattern(int thePatternType, Shading theShading, + public PDFPattern(int thePatternType, PDFShading shading, List theXUID, StringBuffer theExtGState, List theMatrix) { super(); this.patternType = 2; // thePatternType; - assert theShading instanceof PDFShading; - this.shading = (PDFShading)theShading; + this.shading = shading; this.xUID = theXUID; // this isn't really implemented, so it should always be null. // I just don't want to have to add a new parameter once it is implemented. diff --git a/src/java/org/apache/fop/pdf/PDFShading.java b/src/java/org/apache/fop/pdf/PDFShading.java index eaef78fdd..c4ba5b089 100644 --- a/src/java/org/apache/fop/pdf/PDFShading.java +++ b/src/java/org/apache/fop/pdf/PDFShading.java @@ -19,12 +19,12 @@ package org.apache.fop.pdf; -// Java... import java.util.List; -import org.apache.fop.render.shading.Function; -import org.apache.fop.render.shading.Shading; -import org.apache.fop.render.shading.ShadingPattern; +import org.apache.fop.render.gradient.GradientMaker; +import org.apache.fop.render.gradient.GradientMaker.DoubleFormatter; +import org.apache.fop.render.gradient.Shading; + /** * class representing a PDF Smooth Shading object. @@ -36,7 +36,7 @@ import org.apache.fop.render.shading.ShadingPattern; * * All PDF Functions have a shadingType (0,2,3, or 4), a Domain, and a Range. */ -public class PDFShading extends PDFObject implements Shading { +public class PDFShading extends PDFObject { // Guts common to all function types /** @@ -44,266 +44,23 @@ public class PDFShading extends PDFObject implements Shading { */ protected String shadingName; - /** - * Required: The Type of shading (1,2,3,4,5,6,7) - */ - protected int shadingType = 3; // Default - - /** - * A ColorSpace representing the colorspace. "DeviceRGB" is an example. - */ - protected PDFDeviceColorSpace colorSpace; - - /** - * The background color. Since shading is opaque, - * this is very rarely used. - */ - protected List background; - - /** - * Optional: A List specifying the clipping rectangle - */ - protected List bBox; - - /** - * Optional: A flag whether or not to filter the shading function - * to prevent aliasing artifacts. Default is false. - */ - protected boolean antiAlias; - - /** - * Optional for Type 1: Array of four numbers, xmin, xmax, ymin, ymax. - * Default is [0 1 0 1] - * Optional for Type 2: An array of two numbers between which the blend - * varies between start and end points. Default is 0, 1. - * Optional for Type 3: An array of two numbers between which the blend - * varies between start and end points. Default is 0, 1. - */ - protected List domain; - - /** - * Optional for Type 1: A transformation matrix - */ - protected List matrix; - - /** - * Required for Type 1, 2, and 3: - * The object of the color mapping function (usually type 2 or 3). - * Optional for Type 4,5,6, and 7: When it's nearly the same thing. - */ - protected PDFFunction function; + private final Shading shading; - /** - * Required for Type 2: An Array of four numbers specifying - * the starting and ending coordinate pairs - * Required for Type 3: An Array of six numbers [x0,y0,r0,x1,y1,r1] - * specifying the centers and radii of - * the starting and ending circles. - */ - protected List coords; - - /** - * Required for Type 2+3: An Array of two boolean values specifying - * whether to extend the start and end colors past the start - * and end points, respectively. - * Default is false, false. - */ - protected List extend; - - /** - * Required for Type 4,5,6, and 7: Specifies the number of bits used - * to represent each vertex coordinate. - * Allowed to be 1,2,4,8,12,16,24, or 32. - */ - protected int bitsPerCoordinate; - - /** - * Required for Type 4,5,6, and 7: Specifies the number of bits used - * to represent the edge flag for each vertex. - * Allowed to be 2,4,or 8, while the Edge flag itself is allowed to - * be 0,1 or 2. - */ - protected int bitsPerFlag; - - /** - * Required for Type 4,5,6, and 7: Array of Doubles which specifies - * how to decode coordinate and color component values. - * Each type has a differing number of decode array members, so check - * the spec. - * Page 303 in PDF Spec 1.3 - */ - protected List decode; - - /** - * Required for Type 4,5,6, and 7: Specifies the number of bits used - * to represent each color coordinate. - * Allowed to be 1,2,4,8,12, or 16 - */ - protected int bitsPerComponent; - - /** - * Required for Type 5:The number of vertices in each "row" of - * the lattice; it must be greater than or equal to 2. - */ - protected int verticesPerRow; - - /** - * Constructor for type function based shading - * - * @param theShadingType The type of shading object, which should be 1 for function - * based shading. - * @param theColorSpace The colorspace is 'DeviceRGB' or something similar. - * @param theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox List of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Whether or not to anti-alias. - * @param theDomain Optional vector of Doubles specifying the domain. - * @param theMatrix List of Doubles specifying the matrix. - * If it's a pattern, then the matrix maps it to pattern space. - * If it's a shading, then it maps it to current user space. - * It's optional, the default is the identity matrix - * @param theFunction The PDF Function that maps an (x,y) location to a color - */ - public PDFShading(int theShadingType, PDFDeviceColorSpace theColorSpace, - List theBackground, List theBBox, - boolean theAntiAlias, List theDomain, - List theMatrix, PDFFunction theFunction) { - super(); - this.shadingType = theShadingType; // 1 - this.colorSpace = theColorSpace; - this.background = theBackground; - this.bBox = theBBox; - this.antiAlias = theAntiAlias; - - this.domain = theDomain; - this.matrix = theMatrix; - this.function = theFunction; - - } + private final PDFFunction pdfFunction; /** * Constructor for Type 2 and 3 * - * @param theShadingType 2 or 3 for axial or radial shading - * @param theColorSpace "DeviceRGB" or similar. - * @param theBackground theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox List of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Default is false - * @param theCoords List of four (type 2) or 6 (type 3) Double - * @param theDomain List of Doubles specifying the domain - * @param theFunction the Stitching (PDFfunction type 3) function, + * @param shadingType 2 or 3 for axial or radial shading + * @param colorSpace "DeviceRGB" or similar. + * @param coords List of four (type 2) or 6 (type 3) Double + * @param pdfFunction the Stitching (PDFfunction type 3) function, * even if it's stitching a single function - * @param theExtend List of Booleans of whether to extend the start - * and end colors past the start and end points - * The default is [false, false] */ - public PDFShading(int theShadingType, PDFDeviceColorSpace theColorSpace, - List theBackground, List theBBox, - boolean theAntiAlias, List theCoords, - List theDomain, Function theFunction, - List theExtend) { - super(); - this.shadingType = theShadingType; // 2 or 3 - this.colorSpace = theColorSpace; - this.background = theBackground; - this.bBox = theBBox; - this.antiAlias = theAntiAlias; - - this.coords = theCoords; - this.domain = theDomain; - assert theFunction instanceof PDFFunction; - this.function = (PDFFunction)theFunction; - this.extend = theExtend; - - } - - /** - * Constructor for Type 4,6, or 7 - * - * @param theShadingType 4, 6, or 7 depending on whether it's - * Free-form gouraud-shaded triangle meshes, coons patch meshes, - * or tensor product patch meshes, respectively. - * @param theColorSpace "DeviceRGB" or similar. - * @param theBackground theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox List of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Default is false - * @param theBitsPerCoordinate 1,2,4,8,12,16,24 or 32. - * @param theBitsPerComponent 1,2,4,8,12, and 16 - * @param theBitsPerFlag 2,4,8. - * @param theDecode List of Doubles see PDF 1.3 spec pages 303 to 312. - * @param theFunction the PDFFunction - */ - public PDFShading(int theShadingType, PDFDeviceColorSpace theColorSpace, - List theBackground, List theBBox, - boolean theAntiAlias, int theBitsPerCoordinate, - int theBitsPerComponent, int theBitsPerFlag, - List theDecode, PDFFunction theFunction) { - super(); - - this.shadingType = theShadingType; // 4,6 or 7 - this.colorSpace = theColorSpace; - this.background = theBackground; - this.bBox = theBBox; - this.antiAlias = theAntiAlias; - - this.bitsPerCoordinate = theBitsPerCoordinate; - this.bitsPerComponent = theBitsPerComponent; - this.bitsPerFlag = theBitsPerFlag; - this.decode = theDecode; - this.function = theFunction; - } - - /** - * Constructor for type 5 - * - * @param theShadingType 5 for lattice-Form Gouraud shaded-triangle mesh - * @param theColorSpace "DeviceRGB" or similar. - * @param theBackground theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox List of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Default is false - * @param theBitsPerCoordinate 1,2,4,8,12,16, 24, or 32 - * @param theBitsPerComponent 1,2,4,8,12,24,32 - * @param theDecode List of Doubles. See page 305 in PDF 1.3 spec. - * @param theVerticesPerRow number of vertices in each "row" of the lattice. - * @param theFunction The PDFFunction that's mapped on to this shape - */ - public PDFShading(int theShadingType, PDFDeviceColorSpace theColorSpace, - List theBackground, List theBBox, - boolean theAntiAlias, int theBitsPerCoordinate, - int theBitsPerComponent, List theDecode, - int theVerticesPerRow, PDFFunction theFunction) { - super(); - this.shadingType = theShadingType; // 5 - this.colorSpace = theColorSpace; - this.background = theBackground; - this.bBox = theBBox; - this.antiAlias = theAntiAlias; - - this.bitsPerCoordinate = theBitsPerCoordinate; - this.bitsPerComponent = theBitsPerComponent; - this.decode = theDecode; - this.verticesPerRow = theVerticesPerRow; - this.function = theFunction; - + public PDFShading(int shadingType, PDFDeviceColorSpace colorSpace, + List coords, PDFFunction pdfFunction) { + shading = new Shading(shadingType, colorSpace, coords, pdfFunction.getFunction()); + this.pdfFunction = pdfFunction; } /** @@ -340,8 +97,21 @@ public class PDFShading extends PDFObject implements Shading { * @return the PDF string. */ public String toPDFString() { - ShadingPattern pattern = new ShadingPattern(this); - return pattern.toString(colorSpace, shadingType, background, bBox, antiAlias); + Shading.FunctionRenderer functionRenderer = new Shading.FunctionRenderer() { + + public void outputFunction(StringBuilder out) { + out.append(pdfFunction.referencePDF()); + } + }; + StringBuilder out = new StringBuilder(); + GradientMaker.DoubleFormatter doubleFormatter = new DoubleFormatter() { + + public String formatDouble(double d) { + return PDFNumber.doubleOut(d); + } + }; + shading.output(out, doubleFormatter, functionRenderer); + return out.toString(); } /** {@inheritDoc} */ @@ -355,257 +125,54 @@ public class PDFShading extends PDFObject implements Shading { if (!(obj instanceof PDFShading)) { return false; } - PDFShading shad = (PDFShading)obj; - if (shadingType != shad.shadingType) { - return false; - } - if (antiAlias != shad.antiAlias) { - return false; - } - if (bitsPerCoordinate != shad.bitsPerCoordinate) { + Shading other = ((PDFShading) obj).shading; + if (shading.getShadingType() != other.getShadingType()) { return false; } - if (bitsPerFlag != shad.bitsPerFlag) { + if (shading.isAntiAlias() != other.isAntiAlias()) { return false; } - if (bitsPerComponent != shad.bitsPerComponent) { + if (shading.getBitsPerCoordinate() != other.getBitsPerCoordinate()) { return false; } - if (verticesPerRow != shad.verticesPerRow) { + if (shading.getBitsPerFlag() != other.getBitsPerFlag()) { return false; } - if (colorSpace != null) { - if (!colorSpace.equals(shad.colorSpace)) { - return false; - } - } else if (shad.colorSpace != null) { - return false; - } - if (background != null) { - if (!background.equals(shad.background)) { - return false; - } - } else if (shad.background != null) { + if (shading.getBitsPerComponent() != other.getBitsPerComponent()) { return false; } - if (bBox != null) { - if (!bBox.equals(shad.bBox)) { - return false; - } - } else if (shad.bBox != null) { + if (shading.getVerticesPerRow() != other.getVerticesPerRow()) { return false; } - if (domain != null) { - if (!domain.equals(shad.domain)) { + if (shading.getColorSpace() != null) { + if (!shading.getColorSpace().equals(other.getColorSpace())) { return false; } - } else if (shad.domain != null) { + } else if (other.getColorSpace() != null) { return false; } - if (matrix != null) { - if (!matrix.equals(shad.matrix)) { + if (shading.getCoords() != null) { + if (!shading.getCoords().equals(other.getCoords())) { return false; } - } else if (shad.matrix != null) { + } else if (other.getCoords() != null) { return false; } - if (coords != null) { - if (!coords.equals(shad.coords)) { + if (shading.getExtend() != null) { + if (!shading.getExtend().equals(other.getExtend())) { return false; } - } else if (shad.coords != null) { + } else if (other.getExtend() != null) { return false; } - if (extend != null) { - if (!extend.equals(shad.extend)) { + if (shading.getFunction() != null) { + if (!shading.getFunction().equals(other.getFunction())) { return false; } - } else if (shad.extend != null) { - return false; - } - if (decode != null) { - if (!decode.equals(shad.decode)) { - return false; - } - } else if (shad.decode != null) { - return false; - } - if (function != null) { - if (!function.equals(shad.function)) { - return false; - } - } else if (shad.function != null) { + } else if (other.getFunction() != null) { return false; } return true; } - /** - * A method to write a type 1 shading object - * @param p The StringBuffer to write the shading object - * @return Returns the StringBuffer to which the shading object was written - */ - public StringBuffer handleShadingType1(StringBuffer p) { - if (this.domain != null) { - p.append("/Domain [ "); - for (int domainIndex = 0; domainIndex < domain.size(); domainIndex++) { - p.append(PDFNumber.doubleOut((Double)this.domain.get(domainIndex)) - + " "); - } - p.append("] \n"); - } else { - p.append("/Domain [ 0 1 ] \n"); - } - - if (this.matrix != null) { - p.append("/Matrix [ "); - for (int matrixIndex = 0; matrixIndex < matrix.size(); matrixIndex++) { - p.append(PDFNumber.doubleOut((Double)this.matrix.get(matrixIndex)) - + " "); - } - p.append("] \n"); - } - - if (this.function != null) { - p.append("/Function "); - p.append(this.function.referencePDF() + " \n"); - } - return p; - } - - /** - * A method to write a type 2 or 3 shading object - * @param p The StringBuffer to write the shading object - * @return Returns the StringBuffer to which the shading object was written - */ - public StringBuffer handleShadingType2or3(StringBuffer p) { - // 3 is radial shading (circular gradient) - if (this.coords != null) { - p.append("/Coords [ "); - for (int coordIndex = 0; coordIndex < coords.size(); coordIndex++) { - p.append(PDFNumber.doubleOut((Double)this.coords.get(coordIndex)) - + " "); - } - p.append("] \n"); - } - - // DOMAIN - if (this.domain != null) { - p.append("/Domain [ "); - for (int domainIndex = 0; domainIndex < domain.size(); domainIndex++) { - p.append(PDFNumber.doubleOut((Double)this.domain.get(domainIndex)) - + " "); - } - p.append("] \n"); - } else { - p.append("/Domain [ 0 1 ] \n"); - } - - if (this.extend != null) { - p.append("/Extend [ "); - for (int extendIndex = 0; extendIndex < extend.size(); extendIndex++) { - p.append((this.extend.get(extendIndex)) + " "); - } - - p.append("] \n"); - } else { - p.append("/Extend [ true true ] \n"); - } - - - if (this.function != null) { - p.append("/Function "); - p.append(this.function.referencePDF() + " \n"); - } - - return p; - } - - /** - * A method to write a type 4, 6 or 7 shading object - * @param p The StringBuffer to write the shading object - * @return Returns the StringBuffer to which the shading object was written - */ - public StringBuffer handleShadingType4or6or7(StringBuffer p) { - // 6:coons patch meshes - // 7://tensor product patch meshes (which no one ever uses) - if (this.bitsPerCoordinate > 0) { - p.append("/BitsPerCoordinate " + this.bitsPerCoordinate - + " \n"); - } else { - p.append("/BitsPerCoordinate 1 \n"); - } - - if (this.bitsPerComponent > 0) { - p.append("/BitsPerComponent " + this.bitsPerComponent - + " \n"); - } else { - p.append("/BitsPerComponent 1 \n"); - } - - if (this.bitsPerFlag > 0) { - p.append("/BitsPerFlag " + this.bitsPerFlag + " \n"); - } else { - p.append("/BitsPerFlag 2 \n"); - } - - if (this.decode != null) { - p.append("/Decode [ "); - for (int decodeIndex = 0; decodeIndex < decode.size(); decodeIndex++) { - p.append((this.decode.get(decodeIndex)) + " "); - } - - p.append("] \n"); - } - - if (this.function != null) { - p.append("/Function "); - p.append(this.function.referencePDF() + " \n"); - } - - return p; - } - - /** - * A method to write a type 5 shading object - * @param p The StringBuffer to write the shading object - * @return Returns the StringBuffer to which the shading object was written - */ - public StringBuffer handleShadingType5(StringBuffer p) { - if (this.bitsPerCoordinate > 0) { - p.append("/BitsPerCoordinate " + this.bitsPerCoordinate - + " \n"); - } else { - p.append("/BitsPerCoordinate 1 \n"); - } - - if (this.bitsPerComponent > 0) { - p.append("/BitsPerComponent " + this.bitsPerComponent - + " \n"); - } else { - p.append("/BitsPerComponent 1 \n"); - } - - if (this.decode != null) { - p.append("/Decode [ "); - for (int decodeIndex = 0; decodeIndex < decode.size(); decodeIndex++) { - p.append((this.decode.get(decodeIndex)) + " "); - } - - p.append("] \n"); - } - - if (this.function != null) { - p.append("/Function "); - p.append(this.function.referencePDF() + " \n"); - } - - if (this.verticesPerRow > 0) { - p.append("/VerticesPerRow " + this.verticesPerRow + " \n"); - } else { - p.append("/VerticesPerRow 2 \n"); - } - - return p; - } } diff --git a/src/java/org/apache/fop/render/gradient/Function.java b/src/java/org/apache/fop/render/gradient/Function.java new file mode 100644 index 000000000..5099fce96 --- /dev/null +++ b/src/java/org/apache/fop/render/gradient/Function.java @@ -0,0 +1,399 @@ +/* + * 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. + */ + +package org.apache.fop.render.gradient; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.apache.fop.render.gradient.GradientMaker.DoubleFormatter; + +public class Function { + + public interface SubFunctionRenderer { + + void outputFunction(StringBuilder out, int functionIndex); + } + + /** + * Required: The Type of function (0,2,3,4) default is 0. + */ + private int functionType; + + /** + * Required: 2 * m Array of Double numbers which are possible inputs to the function + */ + private List<Double> domain; + + /** + * Required: 2 * n Array of Double numbers which are possible outputs to the function + */ + private List<Double> range; + + /** + * Required for Type 0: Number of Bits used to represent each sample value. + * Limited to 1,2,4,8,12,16,24, or 32 + */ + private int bitsPerSample = 1; + + /** + * Optional for Type 0: order of interpolation between samples. + * Limited to linear (1) or cubic (3). Default is 1 + */ + private int order = 1; + + /** + * Optional for Type 0: A 2 * m array of Doubles which provides a + * linear mapping of input values to the domain. + * + * Required for Type 3: A 2 * k array of Doubles that, taken + * in pairs, map each subset of the domain defined by Domain + * and the Bounds array to the domain of the corresponding function. + * Should be two values per function, usually (0,1), + * as in [0 1 0 1] for 2 functions. + */ + private List<Double> encode; + + /* *************************TYPE 2************************** */ + + /** + * Required For Type 2: An Array of n Doubles defining + * the function result when x=0. Default is [0]. + */ + private float[] cZero; + + /** + * Required For Type 2: An Array of n Doubles defining + * the function result when x=1. Default is [1]. + */ + private float[] cOne; + + /** + * Required for Type 2: The interpolation exponent. + * Each value x will return n results. + * Must be greater than 0. + */ + private double interpolationExponentN = 1; + + /* *************************TYPE 3************************** */ + + /** + * Required for Type 3: An vector of PDFFunctions which + * form an array of k single input functions making up + * the stitching function. + */ + private List<Function> functions; + + /** + * Optional for Type 3: An array of (k-1) Doubles that, + * in combination with Domain, define the intervals to which + * each function from the Functions array apply. Bounds + * elements must be in order of increasing magnitude, + * and each value must be within the value of Domain. + * k is the number of functions. + * If you pass null, it will output (1/k) in an array of k-1 elements. + * This makes each function responsible for an equal amount of the stitching function. + * It makes the gradient even. + */ + private List<Float> bounds; + + /** + * create an complete Function object of Type 2, an Exponential Interpolation function. + * + * Use null for an optional object parameter if you choose not to use it. + * For optional int parameters, pass the default. + * @param domain List objects of Double objects. + * This is the domain of the function. + * See page 264 of the PDF 1.3 Spec. + * @param range List of Doubles that is the Range of the function. + * See page 264 of the PDF 1.3 Spec. + * @param cZero This is a vector of Double objects which defines the function result + * when x=0. + * + * This attribute is optional. + * It's described on page 268 of the PDF 1.3 spec. + * @param cOne This is a vector of Double objects which defines the function result + * when x=1. + * + * This attribute is optional. + * It's described on page 268 of the PDF 1.3 spec. + * @param interpolationExponentN This is the inerpolation exponent. + * + * This attribute is required. + * PDF Spec page 268 + */ + public Function(List<Double> domain, List<Double> range, float[] cZero, float[] cOne, + double interpolationExponentN) { + this(2, domain, range); + this.cZero = cZero; + this.cOne = cOne; + this.interpolationExponentN = interpolationExponentN; + } + + /** + * create an complete Function object of Type 3, a Stitching function. + * + * Use null for an optional object parameter if you choose not to use it. + * For optional int parameters, pass the default. + * @param domain List objects of Double objects. + * This is the domain of the function. + * See page 264 of the PDF 1.3 Spec. + * @param range List objects of Double objects. + * This is the Range of the function. + * See page 264 of the PDF 1.3 Spec. + * @param functions A List of the PDFFunction objects that the stitching function stitches. + * + * This attributed is required. + * It is described on page 269 of the PDF spec. + * @param bounds This is a vector of Doubles representing the numbers that, + * in conjunction with Domain define the intervals to which each function from + * the 'functions' object applies. It must be in order of increasing magnitude, + * and each must be within Domain. + * + * It basically sets how much of the gradient each function handles. + * + * This attributed is required. + * It's described on page 269 of the PDF 1.3 spec. + * @param encode List objects of Double objects. + * This is the linear mapping of input values intop the domain + * of the function's sample table. Default is hard to represent in + * ascii, but basically [0 (Size0 1) 0 (Size1 1)...]. + * This attribute is required. + * + * See page 270 in the PDF 1.3 spec. + */ + public Function(List<Double> domain, List<Double> range, List<Function> functions, + List<Float> bounds, List<Double> encode) { + this(3, domain, range); + this.functions = functions; + this.bounds = bounds; + this.encode = makeEncode(encode); + } + + private List<Double> makeEncode(List<Double> encode) { + if (encode != null) { + return encode; + } else { + encode = new ArrayList<Double>(functions.size() * 2); + for (int i = 0; i < functions.size(); i++) { + encode.add(0.0); + encode.add(1.0); + } + return encode; + } + } + + private Function(int functionType, List<Double> domain, List<Double> range) { + this.functionType = functionType; + this.domain = (domain == null) ? Arrays.asList(0.0, 1.0) : domain; + this.range = range; + } + + /** + * Gets the function type + */ + public int getFunctionType() { + return functionType; + } + + /** + * Gets the function bounds + */ + public List<Float> getBounds() { + return bounds; + } + + /** + * The function domain + */ + public List<Double> getDomain() { + return domain; + } + + /** + * Gets the function encoding + */ + public List<Double> getEncode() { + return encode; + } + + /** + * Gets the sub-functions + */ + public List<Function> getFunctions() { + if (functions == null) { + return Collections.emptyList(); + } else { + return functions; + } + } + + /** + * Gets the bits per sample of the function + */ + public int getBitsPerSample() { + return bitsPerSample; + } + + /** + * Gets the interpolation exponent of the function + */ + public double getInterpolationExponentN() { + return interpolationExponentN; + } + + /** + * Gets the function order + */ + public int getOrder() { + return order; + } + + /** + * Gets the function range + */ + public List<Double> getRange() { + return range; + } + + /** + * Gets the function C0 value (color for gradient) + */ + public float[] getCZero() { + return cZero; + } + + /** + * Gets the function C1 value (color for gradient) + */ + public float[] getCOne() { + return cOne; + } + + public String output(StringBuilder out, DoubleFormatter doubleFormatter, + SubFunctionRenderer subFunctionRenderer) { + out.append("<<\n/FunctionType " + functionType + "\n"); + outputDomain(out, doubleFormatter); + if (this.functionType == 0) { + outputEncode(out, doubleFormatter); + outputBitsPerSample(out); + outputOrder(out); + outputRange(out, doubleFormatter); + out.append(">>"); + } else if (functionType == 2) { + outputRange(out, doubleFormatter); + outputCZero(out, doubleFormatter); + outputCOne(out, doubleFormatter); + outputInterpolationExponentN(out, doubleFormatter); + out.append(">>"); + } else if (functionType == 3) { + outputRange(out, doubleFormatter); + if (!functions.isEmpty()) { + out.append("/Functions [ "); + for (int i = 0; i < functions.size(); i++) { + subFunctionRenderer.outputFunction(out, i); + out.append(' '); + } + out.append("]\n"); + } + outputEncode(out, doubleFormatter); + out.append("/Bounds "); + if (bounds != null) { + GradientMaker.outputDoubles(out, doubleFormatter, bounds); + } else if (!functions.isEmpty()) { + // if there are n functions, + // there must be n-1 bounds. + // so let each function handle an equal portion + // of the whole. e.g. if there are 4, then [ 0.25 0.25 0.25 ] + int numberOfFunctions = functions.size(); + String functionsFraction = doubleFormatter.formatDouble(1.0 / numberOfFunctions); + out.append("[ "); + for (int i = 0; i + 1 < numberOfFunctions; i++) { + out.append(functionsFraction); + out.append(" "); + } + out.append("]"); + } + out.append("\n>>"); + } else if (functionType == 4) { + outputRange(out, doubleFormatter); + out.append(">>"); + } + return out.toString(); + } + + private void outputDomain(StringBuilder p, DoubleFormatter doubleFormatter) { + p.append("/Domain "); + GradientMaker.outputDoubles(p, doubleFormatter, domain); + p.append("\n"); + } + + private void outputBitsPerSample(StringBuilder out) { + out.append("/BitsPerSample " + bitsPerSample + "\n"); + } + + private void outputOrder(StringBuilder out) { + if (order == 1 || order == 3) { + out.append("\n/Order " + order + "\n"); + } + } + + private void outputRange(StringBuilder out, DoubleFormatter doubleFormatter) { + if (range != null) { + out.append("/Range "); + GradientMaker.outputDoubles(out, doubleFormatter, range); + out.append("\n"); + } + } + + private void outputEncode(StringBuilder out, DoubleFormatter doubleFormatter) { + out.append("/Encode "); + GradientMaker.outputDoubles(out, doubleFormatter, encode); + out.append("\n"); + } + + private void outputCZero(StringBuilder out, DoubleFormatter doubleFormatter) { + if (cZero != null) { + out.append("/C0 [ "); + for (float c : cZero) { + out.append(doubleFormatter.formatDouble(c)); + out.append(" "); + } + out.append("]\n"); + } + } + + private void outputCOne(StringBuilder out, DoubleFormatter doubleFormatter) { + if (cOne != null) { + out.append("/C1 [ "); + for (float c : cOne) { + out.append(doubleFormatter.formatDouble(c)); + out.append(" "); + } + out.append("]\n"); + } + } + + private void outputInterpolationExponentN(StringBuilder out, DoubleFormatter doubleFormatter) { + out.append("/N "); + out.append(doubleFormatter.formatDouble(interpolationExponentN)); + out.append("\n"); + } + +} diff --git a/src/java/org/apache/fop/render/gradient/GradientMaker.java b/src/java/org/apache/fop/render/gradient/GradientMaker.java new file mode 100644 index 000000000..3c847a843 --- /dev/null +++ b/src/java/org/apache/fop/render/gradient/GradientMaker.java @@ -0,0 +1,168 @@ +/* + * 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.render.gradient; + +import java.awt.Color; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.List; + +import org.apache.batik.ext.awt.LinearGradientPaint; +import org.apache.batik.ext.awt.MultipleGradientPaint; +import org.apache.batik.ext.awt.RadialGradientPaint; + +import org.apache.xmlgraphics.java2d.color.ColorUtil; + +import org.apache.fop.pdf.PDFDeviceColorSpace; + +public final class GradientMaker { + + public interface DoubleFormatter { + + String formatDouble(double d); + } + + private GradientMaker() { } + + public static Pattern makeLinearGradient(LinearGradientPaint gp, + AffineTransform baseTransform, AffineTransform transform) { + Point2D startPoint = gp.getStartPoint(); + Point2D endPoint = gp.getEndPoint(); + List<Double> coords = new java.util.ArrayList<Double>(4); + coords.add(Double.valueOf(startPoint.getX())); + coords.add(Double.valueOf(startPoint.getY())); + coords.add(Double.valueOf(endPoint.getX())); + coords.add(Double.valueOf(endPoint.getY())); + return makeGradient(gp, coords, baseTransform, transform); + } + + public static Pattern makeRadialGradient(RadialGradientPaint gradient, + AffineTransform baseTransform, AffineTransform transform) { + double radius = gradient.getRadius(); + Point2D center = gradient.getCenterPoint(); + Point2D focus = gradient.getFocusPoint(); + double dx = focus.getX() - center.getX(); + double dy = focus.getY() - center.getY(); + double d = Math.sqrt(dx * dx + dy * dy); + if (d > radius) { + // The focal point must be within the circle with + // radius radius centered at center so limit it to that. + double scale = (radius * .9999) / d; + dx *= scale; + dy *= scale; + } + List<Double> coords = new java.util.ArrayList<Double>(6); + coords.add(Double.valueOf(center.getX() + dx)); + coords.add(Double.valueOf(center.getY() + dy)); + coords.add(Double.valueOf(0)); + coords.add(Double.valueOf(center.getX())); + coords.add(Double.valueOf(center.getY())); + coords.add(Double.valueOf(radius)); + return makeGradient(gradient, coords, baseTransform, transform); + } + + private static Pattern makeGradient(MultipleGradientPaint gradient, List<Double> coords, + AffineTransform baseTransform, AffineTransform transform) { + List<Double> matrix = makeTransform(gradient, baseTransform, transform); + List<Float> bounds = makeBounds(gradient); + List<Function> functions = makeFunctions(gradient); + // Gradients are currently restricted to sRGB + PDFDeviceColorSpace colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); + Function function = new Function(null, null, functions, bounds, null); + int shadingType = gradient instanceof LinearGradientPaint ? 2 : 3; + Shading shading = new Shading(shadingType, colorSpace, coords, function); + return new Pattern(2, shading, matrix); + } + + private static List<Double> makeTransform(MultipleGradientPaint gradient, + AffineTransform baseTransform, AffineTransform transform) { + AffineTransform gradientTransform = new AffineTransform(baseTransform); + gradientTransform.concatenate(transform); + gradientTransform.concatenate(gradient.getTransform()); + List<Double> matrix = new ArrayList<Double>(6); + double[] m = new double[6]; + gradientTransform.getMatrix(m); + for (double d : m) { + matrix.add(Double.valueOf(d)); + } + return matrix; + } + + private static Color getsRGBColor(Color c) { + // Color space must be consistent, so convert to sRGB if necessary + // TODO really? + return c.getColorSpace().isCS_sRGB() ? c : ColorUtil.toSRGBColor(c); + } + + private static List<Float> makeBounds(MultipleGradientPaint gradient) { + float[] fractions = gradient.getFractions(); + List<Float> bounds = new java.util.ArrayList<Float>(fractions.length); + for (float offset : fractions) { + if (0f < offset && offset < 1f) { + bounds.add(offset); + } + } + return bounds; + } + + private static List<Function> makeFunctions(MultipleGradientPaint gradient) { + List<Color> colors = makeColors(gradient); + List<Function> functions = new ArrayList<Function>(); + for (int currentPosition = 0, lastPosition = colors.size() - 1; + currentPosition < lastPosition; + currentPosition++) { + Color currentColor = colors.get(currentPosition); + Color nextColor = colors.get(currentPosition + 1); + float[] c0 = currentColor.getColorComponents(null); + float[] c1 = nextColor.getColorComponents(null); + Function function = new Function(null, null, c0, c1, 1.0); + functions.add(function); + } + return functions; + } + + private static List<Color> makeColors(MultipleGradientPaint gradient) { + Color[] svgColors = gradient.getColors(); + List<Color> gradientColors = new ArrayList<Color>(svgColors.length + 2); + float[] fractions = gradient.getFractions(); + if (fractions[0] > 0f) { + gradientColors.add(getsRGBColor(svgColors[0])); + } + for (Color c : svgColors) { + gradientColors.add(getsRGBColor(c)); + } + if (fractions[fractions.length - 1] < 1f) { + gradientColors.add(getsRGBColor(svgColors[svgColors.length - 1])); + } + return gradientColors; + } + + static void outputDoubles(StringBuilder out, DoubleFormatter doubleFormatter, + List<? extends Number> numbers) { + out.append("[ "); + for (Number n : numbers) { + out.append(doubleFormatter.formatDouble(n.doubleValue())); + out.append(" "); + } + out.append("]"); + } + +} diff --git a/src/java/org/apache/fop/render/shading/Function.java b/src/java/org/apache/fop/render/gradient/Pattern.java index 5bd44087e..cc244f58c 100644 --- a/src/java/org/apache/fop/render/shading/Function.java +++ b/src/java/org/apache/fop/render/gradient/Pattern.java @@ -15,25 +15,37 @@ * limitations under the License. */ -package org.apache.fop.render.shading; +package org.apache.fop.render.gradient; import java.util.List; -public interface Function { - int getFunctionType(); - List<Double> getBounds(); - List<Double> getDomain(); - List<Double> getSize(); - List<String> getFilter(); - List<Double> getEncode(); - List<Function> getFunctions(); - int getBitsPerSample(); - double getInterpolationExponentN(); - int getOrder(); - List<Double> getRange(); - List<Double> getDecode(); - StringBuffer getDataStream(); - List<Double> getCZero(); - List<Double> getCOne(); - byte[] toByteString(); +public class Pattern { + + private final int patternType; + + private final Shading shading; + + private final List<Double> matrix; + + Pattern(int patternType, Shading shading, List<Double> matrix) { + this.patternType = patternType; + this.shading = shading; + this.matrix = matrix; + } + + /** + * Either one (1) for tiling, or two (2) for shading. + */ + public int getPatternType() { + return patternType; + } + + public Shading getShading() { + return shading; + } + + public List<Double> getMatrix() { + return matrix; + } + } diff --git a/src/java/org/apache/fop/render/gradient/Shading.java b/src/java/org/apache/fop/render/gradient/Shading.java new file mode 100644 index 000000000..843081b4a --- /dev/null +++ b/src/java/org/apache/fop/render/gradient/Shading.java @@ -0,0 +1,263 @@ +/* + * 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. + */ + +package org.apache.fop.render.gradient; + +import java.util.Arrays; +import java.util.List; + +import org.apache.fop.pdf.PDFDeviceColorSpace; +import org.apache.fop.render.gradient.GradientMaker.DoubleFormatter; + + +public class Shading { + + public interface FunctionRenderer { + + void outputFunction(StringBuilder out); + } + + /** + * Required: The Type of shading (1,2,3,4,5,6,7) + */ + private final int shadingType; + + /** + * A ColorSpace representing the colorspace. "DeviceRGB" is an example. + */ + private final PDFDeviceColorSpace colorSpace; + + /** + * Required for Type 2: An Array of four numbers specifying + * the starting and ending coordinate pairs + * Required for Type 3: An Array of six numbers [x0,y0,r0,x1,y1,r1] + * specifying the centers and radii of + * the starting and ending circles. + */ + private final List<Double> coords; + + /** + * Required for Type 1, 2, and 3: + * The object of the color mapping function (usually type 2 or 3). + * Optional for Type 4,5,6, and 7: When it's nearly the same thing. + */ + private final Function function; + + /** + * Required for Type 2+3: An Array of two boolean values specifying + * whether to extend the start and end colors past the start + * and end points, respectively. + * Default is false, false. + */ + private final List<Boolean> extend; + + /** + * Required for Type 4,5,6, and 7: Specifies the number of bits used + * to represent each vertex coordinate. + * Allowed to be 1,2,4,8,12,16,24, or 32. + */ + private final int bitsPerCoordinate; + + /** + * Required for Type 4,5,6, and 7: Specifies the number of bits used + * to represent the edge flag for each vertex. + * Allowed to be 2,4,or 8, while the Edge flag itself is allowed to + * be 0,1 or 2. + */ + private final int bitsPerFlag; + + /** + * Optional: A flag whether or not to filter the shading function + * to prevent aliasing artifacts. Default is false. + */ + private final boolean antiAlias; + + /** + * Required for Type 4,5,6, and 7: Specifies the number of bits used + * to represent each color coordinate. + * Allowed to be 1,2,4,8,12, or 16 + */ + private final int bitsPerComponent; + + /** + * Required for Type 5:The number of vertices in each "row" of + * the lattice; it must be greater than or equal to 2. + */ + private final int verticesPerRow; + + public Shading(int shadingType, PDFDeviceColorSpace colorSpace, + List<Double> coords, Function function) { + this.shadingType = shadingType; + this.colorSpace = colorSpace; + this.antiAlias = false; + this.coords = coords; + this.function = function; + this.extend = Arrays.asList(true, true); + this.bitsPerCoordinate = 0; + this.bitsPerFlag = 0; + this.bitsPerComponent = 0; + this.verticesPerRow = 0; + } + + public int getShadingType() { + return shadingType; + } + + public PDFDeviceColorSpace getColorSpace() { + return colorSpace; + } + + public List<Double> getCoords() { + return coords; + } + + public Function getFunction() { + return function; + } + + public List<Boolean> getExtend() { + return extend; + } + + public int getBitsPerCoordinate() { + return bitsPerCoordinate; + } + + public int getBitsPerFlag() { + return bitsPerFlag; + } + + public boolean isAntiAlias() { + return antiAlias; + } + + public int getBitsPerComponent() { + return bitsPerComponent; + } + + public int getVerticesPerRow() { + return verticesPerRow; + } + + public void output(StringBuilder out, DoubleFormatter doubleFormatter, FunctionRenderer functionRenderer) { + out.append("<<\n/ShadingType " + shadingType + "\n"); + if (colorSpace != null) { + out.append("/ColorSpace /" + colorSpace.getName() + "\n"); + } + + if (antiAlias) { + out.append("/AntiAlias " + antiAlias + "\n"); + } + + switch (shadingType) { + // Function based shading + case 1: outputShadingType1(out, doubleFormatter, functionRenderer); break; + // Axial shading + case 2: + // Radial shading + case 3: outputShadingType2or3(out, doubleFormatter, functionRenderer); break; + // Free-form Gouraud-shaded triangle meshes + case 4: + // Coons patch meshes + case 6: + // Tensor product patch meshes + case 7: outputShadingType4or6or7(out, doubleFormatter, functionRenderer); break; + // Lattice Free form gouraud-shaded triangle mesh + case 5: outputShadingType5(out, doubleFormatter, functionRenderer); break; + default: throw new UnsupportedOperationException("Shading type " + shadingType); + } + + out.append(">>"); + } + + private void outputShadingType1(StringBuilder out, DoubleFormatter doubleFormatter, + Shading.FunctionRenderer functionRenderer) { + outputFunction(out, functionRenderer); + } + + private void outputShadingType2or3(StringBuilder out, DoubleFormatter doubleFormatter, + Shading.FunctionRenderer functionRenderer) { + if (coords != null) { + out.append("/Coords "); + GradientMaker.outputDoubles(out, doubleFormatter, coords); + out.append("\n"); + } + + out.append("/Extend [ "); + for (Boolean b : extend) { + out.append(b); + out.append(" "); + } + out.append("]\n"); + + outputFunction(out, functionRenderer); + } + + private void outputShadingType4or6or7(StringBuilder out, DoubleFormatter doubleFormatter, + Shading.FunctionRenderer functionRenderer) { + if (bitsPerCoordinate > 0) { + out.append("/BitsPerCoordinate " + bitsPerCoordinate + "\n"); + } else { + out.append("/BitsPerCoordinate 1 \n"); + } + + if (bitsPerComponent > 0) { + out.append("/BitsPerComponent " + bitsPerComponent + "\n"); + } else { + out.append("/BitsPerComponent 1 \n"); + } + + if (bitsPerFlag > 0) { + out.append("/BitsPerFlag " + bitsPerFlag + "\n"); + } else { + out.append("/BitsPerFlag 2 \n"); + } + + outputFunction(out, functionRenderer); + } + + private void outputShadingType5(StringBuilder out, DoubleFormatter doubleFormatter, + Shading.FunctionRenderer functionRenderer) { + if (bitsPerCoordinate > 0) { + out.append("/BitsPerCoordinate " + bitsPerCoordinate + "\n"); + } else { + out.append("/BitsPerCoordinate 1 \n"); + } + + if (bitsPerComponent > 0) { + out.append("/BitsPerComponent " + bitsPerComponent + "\n"); + } else { + out.append("/BitsPerComponent 1 \n"); + } + + outputFunction(out, functionRenderer); + + if (verticesPerRow > 0) { + out.append("/VerticesPerRow " + verticesPerRow + "\n"); + } else { + out.append("/VerticesPerRow 2 \n"); + } + } + + private void outputFunction(StringBuilder out, FunctionRenderer functionRenderer) { + if (function != null) { + out.append("/Function "); + functionRenderer.outputFunction(out); + out.append("\n"); + } + } +} diff --git a/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java b/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java index 4d215926b..be479ec31 100644 --- a/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java +++ b/src/java/org/apache/fop/render/ps/PSImageHandlerSVG.java @@ -33,8 +33,6 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.imageio.ImageIO; @@ -314,19 +312,6 @@ public class PSImageHandlerSVG implements ImageHandler { } } String nodeName = curNode.getLocalName(); - //Special case where rasterization needed for radial gradients - if (nodeName != null && nodeName.equals("ellipse")) { - String found = ""; - String ellipseFill = curNode.getAttributes().getNamedItem("fill").getNodeValue(); - Pattern pattern = Pattern.compile("#(.*?)\\)"); - Matcher matcher = pattern.matcher(ellipseFill); - if (matcher.find()) { - found = matcher.group(1); - } - if (gradientsFound.get(found) != null) { - return true; - } - } boolean inMatch = false; if (!isMatched) { inMatch = nodeName != null && gradMatches.contains(nodeName); diff --git a/src/java/org/apache/fop/render/ps/svg/PSFunction.java b/src/java/org/apache/fop/render/ps/svg/PSFunction.java deleted file mode 100644 index b03e0b590..000000000 --- a/src/java/org/apache/fop/render/ps/svg/PSFunction.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.ps.svg; - -import java.io.UnsupportedEncodingException; -import java.util.List; - -import org.apache.fop.render.shading.Function; -import org.apache.fop.render.shading.FunctionDelegate; -import org.apache.fop.render.shading.FunctionPattern; - -public class PSFunction implements Function { - - private FunctionDelegate delegate; - - /** - * Creates a Postscript function dictionary - * @param theFunctionType The function type (0 = Sampled, 2 = Exponential - * Interpolation, 3 = Stitching) - * @param theDomain The function domain - * @param theRange Range used for clipping - * @param theFunctions An array of sub-functions such as determining the - * colour values used in a gradient. - * @param theBounds Bounds determines where each boundary exists for whatever - * the function is mean't. In a gradient case, it would be the point between - * colours. - * @param theEncode The function encoding - */ - public PSFunction(int theFunctionType, List<Double> theDomain, - List<Double> theRange, List<Function> theFunctions, - List<Double> theBounds, List<Double> theEncode) { - delegate = new FunctionDelegate(this, theFunctionType, theDomain, theRange, theFunctions, - theBounds, theEncode); - } - - /** - * Creates a Postscript function dictionary - * @param theFunctionType The function type (0 = Sampled, 2 = Exponential - * Interpolation, 3 = Stitching) - * @param theDomain The function domain - * @param theRange Range used for clipping - * @param theCZero In a gradient, this would be the first colour - * @param theCOne In a gradient, this would be the second colour - * @param theInterpolationExponentN Determines the number of values - * the function returns. - */ - public PSFunction(int theFunctionType, List<Double> theDomain, - List<Double> theRange, List<Double> theCZero, List<Double> theCOne, - double theInterpolationExponentN) { - delegate = new FunctionDelegate(this, theFunctionType, theDomain, theRange, theCZero, - theCOne, theInterpolationExponentN); - } - - /** - * Outputs the function to a byte array - */ - public byte[] toByteString() { - FunctionPattern pattern = new FunctionPattern(this); - try { - return pattern.toWriteableString().getBytes("UTF-8"); - } catch (UnsupportedEncodingException ex) { - //This should have been made an enum type to avoid throwing exceptions. - return new byte[0]; - } - } - - public int getFunctionType() { - return delegate.getFunctionType(); - } - - public List<Double> getBounds() { - return delegate.getBounds(); - } - - public List<Double> getDomain() { - return delegate.getDomain(); - } - - public List<Double> getSize() { - return delegate.getSize(); - } - - public List<String> getFilter() { - return delegate.getFilter(); - } - - public List<Double> getEncode() { - return delegate.getEncode(); - } - - public List<Function> getFunctions() { - return delegate.getFunctions(); - } - - public int getBitsPerSample() { - return delegate.getBitsPerSample(); - } - - public double getInterpolationExponentN() { - return delegate.getInterpolationExponentN(); - } - - public int getOrder() { - return delegate.getOrder(); - } - - public List<Double> getRange() { - return delegate.getRange(); - } - - public List<Double> getDecode() { - return delegate.getDecode(); - } - - public StringBuffer getDataStream() { - return delegate.getDataStream(); - } - - public List<Double> getCZero() { - return delegate.getCZero(); - } - - public List<Double> getCOne() { - return delegate.getCOne(); - } -} diff --git a/src/java/org/apache/fop/render/ps/svg/PSPattern.java b/src/java/org/apache/fop/render/ps/svg/PSPattern.java deleted file mode 100644 index 57a5ad355..000000000 --- a/src/java/org/apache/fop/render/ps/svg/PSPattern.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.ps.svg; - -import java.util.List; - -import org.apache.fop.render.shading.Pattern; -import org.apache.fop.render.shading.Shading; - -public class PSPattern implements Pattern { - - /** - * Either one (1) for tiling, or two (2) for shading. - */ - protected int patternType = 2; // Default - - /** - * The Shading object comprising the Type 2 pattern - */ - protected PSShading shading; - - /** - * List of Integers represetning the Extended unique Identifier - */ - protected List xUID; - - /** - * TODO use PDFGState - * String representing the extended Graphics state. - * Probably will never be used like this. - */ - protected StringBuffer extGState; - - /** - * Creates a radial or axial shading pattern - * @param thePatternType The pattern type which will be 3 for radial and 2 for axial - * @param theShading The shading object to determine how the gradient - * is drawn - * @param theXUID The XUID - * @param theExtGState The exit state - */ - public PSPattern(int thePatternType, Shading theShading, List theXUID, - StringBuffer theExtGState) { - this.patternType = 2; // thePatternType; - assert theShading instanceof PSShading; - this.shading = (PSShading)theShading; - this.xUID = theXUID; - this.extGState = theExtGState; // always null - } - - /** - * Outputs the radial or axial pattern as a string dictionary to insert - * into a postscript document. - */ - public String toString() { - int vectorSize = 0; - int tempInt = 0; - StringBuffer p = new StringBuffer(64); - p.append("/Pattern setcolorspace\n"); - p.append("<< \n/Type /Pattern \n"); - - p.append("/PatternType " + this.patternType + " \n"); - - if (this.shading != null) { - p.append("/Shading " + this.shading.toString() + " \n"); - } - - if (this.xUID != null) { - vectorSize = this.xUID.size(); - p.append("/XUID [ "); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append((this.xUID.get(tempInt)) + " "); - } - p.append("] \n"); - } - - if (this.extGState != null) { - p.append("/ExtGState " + this.extGState + " \n"); - } - - p.append(">> \n"); - p.append("matrix makepattern setcolor\n"); - - return p.toString(); - } -} diff --git a/src/java/org/apache/fop/render/ps/svg/PSSVGGraphics2D.java b/src/java/org/apache/fop/render/ps/svg/PSSVGGraphics2D.java index 1c15e569b..28fa4ec9c 100644 --- a/src/java/org/apache/fop/render/ps/svg/PSSVGGraphics2D.java +++ b/src/java/org/apache/fop/render/ps/svg/PSSVGGraphics2D.java @@ -19,34 +19,29 @@ package org.apache.fop.render.ps.svg; -import java.awt.Color; import java.awt.Graphics; import java.awt.Paint; import java.awt.geom.AffineTransform; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.batik.ext.awt.LinearGradientPaint; -import org.apache.batik.ext.awt.MultipleGradientPaint; import org.apache.batik.ext.awt.RadialGradientPaint; import org.apache.xmlgraphics.java2d.ps.PSGraphics2D; import org.apache.xmlgraphics.ps.PSGenerator; -import org.apache.fop.pdf.PDFDeviceColorSpace; -import org.apache.fop.render.shading.Function; -import org.apache.fop.render.shading.GradientFactory; -import org.apache.fop.render.shading.GradientRegistrar; -import org.apache.fop.render.shading.PSGradientFactory; -import org.apache.fop.render.shading.Pattern; -import org.apache.fop.render.shading.Shading; +import org.apache.fop.render.gradient.Function; +import org.apache.fop.render.gradient.Function.SubFunctionRenderer; +import org.apache.fop.render.gradient.GradientMaker; +import org.apache.fop.render.gradient.GradientMaker.DoubleFormatter; +import org.apache.fop.render.gradient.Pattern; +import org.apache.fop.render.gradient.Shading; -public class PSSVGGraphics2D extends PSGraphics2D implements GradientRegistrar { +public class PSSVGGraphics2D extends PSGraphics2D { private static final Log LOG = LogFactory.getLog(PSSVGGraphics2D.class); @@ -79,167 +74,72 @@ public class PSSVGGraphics2D extends PSGraphics2D implements GradientRegistrar { protected void applyPaint(Paint paint, boolean fill) { super.applyPaint(paint, fill); - if (paint instanceof RadialGradientPaint) { - RadialGradientPaint rgp = (RadialGradientPaint)paint; + if (paint instanceof LinearGradientPaint) { + Pattern pattern = GradientMaker.makeLinearGradient((LinearGradientPaint) paint, + getBaseTransform(), getTransform()); try { - handleRadialGradient(rgp, gen); + gen.write(outputPattern(pattern)); } catch (IOException ioe) { handleIOException(ioe); } - } else if (paint instanceof LinearGradientPaint) { - LinearGradientPaint lgp = (LinearGradientPaint)paint; + } else if (paint instanceof RadialGradientPaint) { + Pattern pattern = GradientMaker.makeRadialGradient((RadialGradientPaint) paint, + getBaseTransform(), getTransform()); try { - handleLinearGradient(lgp, gen); + gen.write(outputPattern(pattern)); } catch (IOException ioe) { handleIOException(ioe); } } } - private void handleLinearGradient(LinearGradientPaint lgp, PSGenerator gen) throws IOException { - MultipleGradientPaint.CycleMethodEnum cycle = lgp.getCycleMethod(); - if (cycle != MultipleGradientPaint.NO_CYCLE) { - return; - } - float[] fractions = lgp.getFractions(); - Color[] cols = lgp.getColors(); - - AffineTransform transform = new AffineTransform(getBaseTransform()); - transform.concatenate(getTransform()); - transform.concatenate(lgp.getTransform()); - - List theMatrix = new ArrayList(); - double [] mat = new double[6]; - transform.getMatrix(mat); - for (int idx = 0; idx < mat.length; idx++) { - theMatrix.add(Double.valueOf(mat[idx])); - } - - - List<Double> theCoords = new java.util.ArrayList<Double>(); - - - AffineTransform start = applyTransform(lgp.getTransform(), - lgp.getStartPoint().getX(), lgp.getStartPoint().getY()); - AffineTransform end = applyTransform(lgp.getTransform(), lgp.getEndPoint().getX(), lgp.getEndPoint().getY()); - double startX = start.getTranslateX(); - double startY = start.getTranslateY(); - double endX = end.getTranslateX(); - double endY = end.getTranslateY(); - - double width = endX - startX; - double height = endY - startY; - - startX = startX + width * fractions[0]; - endX = endX - width * (1 - fractions[fractions.length - 1]); - startY = startY + (height * fractions[0]); - endY = endY - height * (1 - fractions[fractions.length - 1]); - - theCoords.add(startX); - theCoords.add(startY); - theCoords.add(endX); - theCoords.add(endY); + private String outputPattern(Pattern pattern) { + StringBuilder p = new StringBuilder(64); + p.append("/Pattern setcolorspace\n"); + p.append("<< \n/Type /Pattern \n"); + p.append("/PatternType " + pattern.getPatternType() + " \n"); - List<Color> someColors = new java.util.ArrayList<Color>(); - for (int count = 0; count < cols.length; count++) { - Color c1 = cols[count]; - if (c1.getAlpha() != 255) { - LOG.warn("Opacity is not currently supported for Postscript output"); - } - someColors.add(c1); + if (pattern.getShading() != null) { + p.append("/Shading "); + outputShading(p, pattern.getShading()); + p.append(" \n"); } - List<Double> theBounds = new java.util.ArrayList<Double>(); - for (int count = 1; count < fractions.length - 1; count++) { - float offset = fractions[count]; - theBounds.add(Double.valueOf(offset)); + p.append(">> \n"); + p.append("[ "); + for (double m : pattern.getMatrix()) { + p.append(getPSGenerator().formatDouble(m)); + p.append(" "); } - PDFDeviceColorSpace colSpace; - colSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); - - PSGradientFactory gradientFactory = (PSGradientFactory)GradientFactory.newInstance(this); - PSPattern myPattern = gradientFactory.createGradient(false, colSpace, - someColors, theBounds, theCoords, theMatrix); - - gen.write(myPattern.toString()); + p.append("] "); + p.append("makepattern setcolor\n"); + return p.toString(); } + private void outputShading(StringBuilder out, Shading shading) { + final GradientMaker.DoubleFormatter doubleFormatter = new DoubleFormatter() { - - private void handleRadialGradient(RadialGradientPaint rgp, PSGenerator gen) throws IOException { - MultipleGradientPaint.CycleMethodEnum cycle = rgp.getCycleMethod(); - if (cycle != MultipleGradientPaint.NO_CYCLE) { - return; - } - - AffineTransform transform; - transform = new AffineTransform(getBaseTransform()); - transform.concatenate(getTransform()); - transform.concatenate(rgp.getTransform()); - - AffineTransform resultCentre = applyTransform(rgp.getTransform(), - rgp.getCenterPoint().getX(), rgp.getCenterPoint().getY()); - AffineTransform resultFocus = applyTransform(rgp.getTransform(), - rgp.getFocusPoint().getX(), rgp.getFocusPoint().getY()); - double scale = Math.sqrt(rgp.getTransform().getDeterminant()); - double radius = rgp.getRadius() * scale; - double centreX = resultCentre.getTranslateX(); - double centreY = resultCentre.getTranslateY(); - double focusX = resultFocus.getTranslateX(); - double focusY = resultFocus.getTranslateY(); - - List<Double> theMatrix = new java.util.ArrayList<Double>(); - double [] mat = new double[6]; - transform.getMatrix(mat); - for (int idx = 0; idx < mat.length; idx++) { - theMatrix.add(Double.valueOf(mat[idx])); - } - - List<Double> theCoords = new java.util.ArrayList<Double>(); - float[] fractions = rgp.getFractions(); - - theCoords.add(centreX); - theCoords.add(centreY); - theCoords.add(radius * rgp.getFractions()[0]); - theCoords.add(focusX); - theCoords.add(focusY); - theCoords.add(radius * fractions[fractions.length - 1]); - - Color[] cols = rgp.getColors(); - List<Color> someColors = new java.util.ArrayList<Color>(); - for (int count = 0; count < cols.length; count++) { - Color cc = cols[count]; - if (cc.getAlpha() != 255) { - /* This should never happen because radial gradients with opacity should now - * be rasterized in the PSImageHandlerSVG class. Please see the shouldRaster() - * method for more information. */ - LOG.warn("Opacity is not currently supported for Postscript output"); + public String formatDouble(double d) { + return getPSGenerator().formatDouble(d); } - - someColors.add(cc); - } - - List<Double> theBounds = new java.util.ArrayList<Double>(); - for (int count = 1; count < fractions.length - 1; count++) { - float offset = fractions[count]; - theBounds.add(Double.valueOf(offset)); - } - PDFDeviceColorSpace colSpace; - colSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); - - PSGradientFactory gradientFactory = (PSGradientFactory)GradientFactory.newInstance(this); - PSPattern myPattern = gradientFactory.createGradient(true, colSpace, - someColors, theBounds, theCoords, theMatrix); - - gen.write(myPattern.toString()); - } - - private AffineTransform applyTransform(AffineTransform base, double posX, double posY) { - AffineTransform result = AffineTransform.getTranslateInstance(posX, posY); - AffineTransform orig = base; - orig.concatenate(result); - return orig; + }; + final Function function = shading.getFunction(); + Shading.FunctionRenderer functionRenderer = new Shading.FunctionRenderer() { + + public void outputFunction(StringBuilder out) { + SubFunctionRenderer subFunctionRenderer = new Function.SubFunctionRenderer() { + + public void outputFunction(StringBuilder out, int functionIndex) { + Function subFunction = function.getFunctions().get(functionIndex); + assert subFunction.getFunctions().isEmpty(); + subFunction.output(out, doubleFormatter, null); + } + }; + function.output(out, doubleFormatter, subFunctionRenderer); + } + }; + shading.output(out, doubleFormatter, functionRenderer); } protected AffineTransform getBaseTransform() { @@ -259,36 +159,4 @@ public class PSSVGGraphics2D extends PSGraphics2D implements GradientRegistrar { return new PSSVGGraphics2D(this); } - /** - * Registers a function object against the output format document - * @param function The function object to register - * @return Returns either the function which has already been registered - * or the current new registered object. - */ - public Function registerFunction(Function function) { - //Objects aren't needed to be registered in Postscript - return function; - } - - /** - * Registers a shading object against the otuput format document - * @param shading The shading object to register - * @return Returs either the shading which has already been registered - * or the current new registered object - */ - public Shading registerShading(Shading shading) { - //Objects aren't needed to be registered in Postscript - return shading; - } - - /** - * Registers a pattern object against the output format document - * @param pattern The pattern object to register - * @return Returns either the pattern which has already been registered - * or the current new registered object - */ - public Pattern registerPattern(Pattern pattern) { - // TODO Auto-generated method stub - return pattern; - } } diff --git a/src/java/org/apache/fop/render/ps/svg/PSShading.java b/src/java/org/apache/fop/render/ps/svg/PSShading.java deleted file mode 100644 index e6eba11ad..000000000 --- a/src/java/org/apache/fop/render/ps/svg/PSShading.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.ps.svg; - -import java.io.UnsupportedEncodingException; -import java.util.List; - -import org.apache.fop.pdf.PDFDeviceColorSpace; -import org.apache.fop.pdf.PDFNumber; -import org.apache.fop.render.shading.Function; -import org.apache.fop.render.shading.Shading; -import org.apache.fop.render.shading.ShadingPattern; - -public class PSShading implements Shading { - - /** - * Required: The Type of shading (1,2,3,4,5,6,7) - */ - protected int shadingType = 3; // Default - - /** - * A ColorSpace representing the colorspace. "DeviceRGB" is an example. - */ - protected PDFDeviceColorSpace colorSpace; - - /** - * The background color. Since shading is opaque, - * this is very rarely used. - */ - protected List background; - - /** - * Optional: A List specifying the clipping rectangle - */ - protected List bBox; - - /** - * Optional: A flag whether or not to filter the shading function - * to prevent aliasing artifacts. Default is false. - */ - protected boolean antiAlias; - - /** - * Optional for Type 1: Array of four numbers, xmin, xmax, ymin, ymax. - * Default is [0 1 0 1] - * Optional for Type 2: An array of two numbers between which the blend - * varies between start and end points. Default is 0, 1. - * Optional for Type 3: An array of two numbers between which the blend - * varies between start and end points. Default is 0, 1. - */ - protected List domain; - - /** - * Required for Type 1, 2, and 3: - * The object of the color mapping function (usually type 2 or 3). - * Optional for Type 4,5,6, and 7: When it's nearly the same thing. - */ - protected PSFunction function; - - /** - * Required for Type 2: An Array of four numbers specifying - * the starting and ending coordinate pairs - * Required for Type 3: An Array of six numbers [x0,y0,r0,x1,y1,r1] - * specifying the centers and radii of - * the starting and ending circles. - */ - protected List coords; - - /** - * Required for Type 2+3: An Array of two boolean values specifying - * whether to extend the start and end colors past the start - * and end points, respectively. - * Default is false, false. - */ - protected List extend; - - /** - * Constructor for Type 2 and 3 - * - * @param theShadingType 2 or 3 for axial or radial shading - * @param theColorSpace "DeviceRGB" or similar. - * @param theBackground theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox List of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Default is false - * @param theCoords List of four (type 2) or 6 (type 3) Double - * @param theDomain List of Doubles specifying the domain - * @param theFunction the Stitching (PDFfunction type 3) function, - * even if it's stitching a single function - * @param theExtend List of Booleans of whether to extend the start - * and end colors past the start and end points - * The default is [false, false] - */ - public PSShading(int theShadingType, PDFDeviceColorSpace theColorSpace, - List<Double> theBackground, List<Double> theBBox, - boolean theAntiAlias, List<Double> theCoords, - List<Double> theDomain, Function theFunction, - List<Integer> theExtend) { - this.shadingType = theShadingType; // 2 or 3 - this.colorSpace = theColorSpace; - this.background = theBackground; - this.bBox = theBBox; - this.antiAlias = theAntiAlias; - - this.coords = theCoords; - this.domain = theDomain; - assert theFunction instanceof PSFunction; - this.function = (PSFunction)theFunction; - this.extend = theExtend; - } - - /** - * represent as PS. Whatever the shadingType is, the correct - * representation spits out. The sets of required and optional - * attributes are different for each type, but if a required - * attribute's object was constructed as null, then no error - * is raised. Instead, the malformed PS that was requested - * by the construction is dutifully output. - * This policy should be reviewed. - * - * @return the PDF string. - */ - public String toString() { - ShadingPattern pattern = new ShadingPattern(this); - return pattern.toString(colorSpace, shadingType, background, bBox, antiAlias); - } - - /** - * A method to write a type 2 or 3 shading object - * @param p The StringBuffer to write the shading object - * @return Returns the StringBuffer to which the shading object was written - */ - public StringBuffer handleShadingType2or3(StringBuffer p) { - if (this.coords != null) { - p.append("\t/Coords [ "); - for (int coordIndex = 0; coordIndex < coords.size(); coordIndex++) { - p.append(PDFNumber.doubleOut((Double)this.coords.get(coordIndex)) - + " "); - } - p.append("] \n"); - } - - // DOMAIN - if (this.domain != null) { - p.append("\t/Domain [ "); - for (int domainIndex = 0; domainIndex < domain.size(); domainIndex++) { - p.append(PDFNumber.doubleOut((Double)this.domain.get(domainIndex)) - + " "); - } - p.append("] \n"); - } else { - p.append("\t/Domain [ 0 1 ] \n"); - } - - if (this.extend != null) { - p.append("\t/Extend [ "); - for (int extendIndex = 0; extendIndex < extend.size(); extendIndex++) { - p.append((this.extend.get(extendIndex)) + " "); - } - - p.append("] \n"); - } else { - p.append("\t/Extend [ true true ] \n"); - } - - - if (this.function != null) { - p.append("\t/Function "); - try { - p.append(new String(this.function.toByteString(), "UTF-8") + " \n"); - } catch (UnsupportedEncodingException ex) { - //This should have been made an enum type to avoid throwing exceptions. - } - } - return p; - } - - /** - * A method to write a type 1 shading object - * @param p The StringBuffer to write the shading object - * @return Returns the StringBuffer to which the shading object was written - */ - public StringBuffer handleShadingType1(StringBuffer p) { - // TODO Auto-generated method stub - return null; - } - - /** - * A method to write a type 4, 6 or 7 shading object - * @param p The StringBuffer to write the shading object - * @return Returns the StringBuffer to which the shading object was written - */ - public StringBuffer handleShadingType4or6or7(StringBuffer p) { - // TODO Auto-generated method stub - return null; - } - - /** - * A method to write a type 5 shading object - * @param p The StringBuffer to write the shading object - * @return Returns the StringBuffer to which the shading object was written - */ - public StringBuffer handleShadingType5(StringBuffer p) { - // TODO Auto-generated method stub - return null; - } -} diff --git a/src/java/org/apache/fop/render/shading/FunctionDelegate.java b/src/java/org/apache/fop/render/shading/FunctionDelegate.java deleted file mode 100644 index 66a8db9ed..000000000 --- a/src/java/org/apache/fop/render/shading/FunctionDelegate.java +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.fop.render.shading; - -import java.util.List; - -public class FunctionDelegate implements Function { - - private Function parentFunction; - - /** - * Required: The Type of function (0,2,3,4) default is 0. - */ - protected int functionType; // Default - - /** - * Required: 2 * m Array of Double numbers which are possible inputs to the function - */ - protected List<Double> domain; - - /** - * Required: 2 * n Array of Double numbers which are possible outputs to the function - */ - protected List<Double> range; - - /* ********************TYPE 0***************************** */ - // FunctionType 0 specific function guts - - /** - * Required: Array containing the Integer size of the Domain and Range, respectively. - * Note: This is really more like two seperate integers, sizeDomain, and sizeRange, - * but since they're expressed as an array in PDF, my implementation reflects that. - */ - protected List<Double> size; - - /** - * Required for Type 0: Number of Bits used to represent each sample value. - * Limited to 1,2,4,8,12,16,24, or 32 - */ - protected int bitsPerSample = 1; - - /** - * Optional for Type 0: order of interpolation between samples. - * Limited to linear (1) or cubic (3). Default is 1 - */ - protected int order = 1; - - /** - * Optional for Type 0: A 2 * m array of Doubles which provides a - * linear mapping of input values to the domain. - * - * Required for Type 3: A 2 * k array of Doubles that, taken - * in pairs, map each subset of the domain defined by Domain - * and the Bounds array to the domain of the corresponding function. - * Should be two values per function, usually (0,1), - * as in [0 1 0 1] for 2 functions. - */ - protected List<Double> encode; - - /** - * Optional for Type 0: A 2 * n array of Doubles which provides - * a linear mapping of sample values to the range. Defaults to Range. - */ - protected List<Double> decode; - - /** - * Optional For Type 0: A stream of sample values - */ - - /** - * Required For Type 4: Postscript Calculator function - * composed of arithmetic, boolean, and stack operators + boolean constants - */ - protected StringBuffer functionDataStream; - - /** - * Required (possibly) For Type 0: A vector of Strings for the - * various filters to be used to decode the stream. - * These are how the string is compressed. Flate, LZW, etc. - */ - protected List<String> filter; - /* *************************TYPE 2************************** */ - - /** - * Required For Type 2: An Array of n Doubles defining - * the function result when x=0. Default is [0]. - */ - protected List<Double> cZero; - - /** - * Required For Type 2: An Array of n Doubles defining - * the function result when x=1. Default is [1]. - */ - protected List<Double> cOne; - - /** - * Required for Type 2: The interpolation exponent. - * Each value x will return n results. - * Must be greater than 0. - */ - protected double interpolationExponentN = 1; - - /* *************************TYPE 3************************** */ - - /** - * Required for Type 3: An vector of PDFFunctions which - * form an array of k single input functions making up - * the stitching function. - */ - protected List<Function> functions; - - /** - * Optional for Type 3: An array of (k-1) Doubles that, - * in combination with Domain, define the intervals to which - * each function from the Functions array apply. Bounds - * elements must be in order of increasing magnitude, - * and each value must be within the value of Domain. - * k is the number of functions. - * If you pass null, it will output (1/k) in an array of k-1 elements. - * This makes each function responsible for an equal amount of the stitching function. - * It makes the gradient even. - */ - protected List<Double> bounds; - - /** - * create an complete Function object of Type 0, A Sampled function. - * - * Use null for an optional object parameter if you choose not to use it. - * For optional int parameters, pass the default. - * - * @param theDomain List objects of Double objects. - * This is the domain of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theRange List objects of Double objects. - * This is the Range of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theSize A List object of Integer objects. - * This is the number of samples in each input dimension. - * I can't imagine there being more or less than two input dimensions, - * so maybe this should be an array of length 2. - * - * See page 265 of the PDF 1.3 Spec. - * @param theBitsPerSample An int specifying the number of bits - used to represent each sample value. - * Limited to 1,2,4,8,12,16,24 or 32. - * See page 265 of the 1.3 PDF Spec. - * @param theOrder The order of interpolation between samples. Default is 1 (one). Limited - * to 1 (one) or 3, which means linear or cubic-spline interpolation. - * - * This attribute is optional. - * - * See page 265 in the PDF 1.3 spec. - * @param theEncode List objects of Double objects. - * This is the linear mapping of input values intop the domain - * of the function's sample table. Default is hard to represent in - * ascii, but basically [0 (Size0 1) 0 (Size1 1)...]. - * This attribute is optional. - * - * See page 265 in the PDF 1.3 spec. - * @param theDecode List objects of Double objects. - * This is a linear mapping of sample values into the range. - * The default is just the range. - * - * This attribute is optional. - * Read about it on page 265 of the PDF 1.3 spec. - * @param theFunctionDataStream The sample values that specify - * the function are provided in a stream. - * - * This is optional, but is almost always used. - * - * Page 265 of the PDF 1.3 spec has more. - * @param theFilter This is a vector of String objects which are the various filters that - * have are to be applied to the stream to make sense of it. Order matters, - * so watch out. - * - * This is not documented in the Function section of the PDF 1.3 spec, - * it was deduced from samples that this is sometimes used, even if we may never - * use it in FOP. It is added for completeness sake. - * @param theFunctionType This is the type of function (0,2,3, or 4). - * It should be 0 as this is the constructor for sampled functions. - */ - public FunctionDelegate(Function parentFunction, int theFunctionType, List<Double> theDomain, - List<Double> theRange, List<Double> theSize, int theBitsPerSample, - int theOrder, List<Double> theEncode, List<Double> theDecode, - StringBuffer theFunctionDataStream, List<String> theFilter) { - this.parentFunction = parentFunction; - this.functionType = 0; // dang well better be 0; - this.size = theSize; - this.bitsPerSample = theBitsPerSample; - this.order = theOrder; // int - this.encode = theEncode; // vector of int - this.decode = theDecode; // vector of int - this.functionDataStream = theFunctionDataStream; - this.filter = theFilter; // vector of Strings - - // the domain and range are actually two dimensional arrays. - // so if there's not an even number of items, bad stuff - // happens. - this.domain = theDomain; - this.range = theRange; - } - - /** - * create an complete Function object of Type 2, an Exponential Interpolation function. - * - * Use null for an optional object parameter if you choose not to use it. - * For optional int parameters, pass the default. - * - * @param theDomain List objects of Double objects. - * This is the domain of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theRange List of Doubles that is the Range of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theCZero This is a vector of Double objects which defines the function result - * when x=0. - * - * This attribute is optional. - * It's described on page 268 of the PDF 1.3 spec. - * @param theCOne This is a vector of Double objects which defines the function result - * when x=1. - * - * This attribute is optional. - * It's described on page 268 of the PDF 1.3 spec. - * @param theInterpolationExponentN This is the inerpolation exponent. - * - * This attribute is required. - * PDF Spec page 268 - * @param theFunctionType The type of the function, which should be 2. - */ - public FunctionDelegate(Function parentFunction, int theFunctionType, List<Double> theDomain, - List<Double> theRange, List<Double> theCZero, List<Double> theCOne, - double theInterpolationExponentN) { - this.parentFunction = parentFunction; - this.functionType = 2; // dang well better be 2; - - this.cZero = theCZero; - this.cOne = theCOne; - this.interpolationExponentN = theInterpolationExponentN; - - this.domain = theDomain; - this.range = theRange; - - } - - /** - * create an complete Function object of Type 3, a Stitching function. - * - * Use null for an optional object parameter if you choose not to use it. - * For optional int parameters, pass the default. - * - * @param theDomain List objects of Double objects. - * This is the domain of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theRange List objects of Double objects. - * This is the Range of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theFunctions A List of the PDFFunction objects that the stitching function stitches. - * - * This attributed is required. - * It is described on page 269 of the PDF spec. - * @param theBounds This is a vector of Doubles representing the numbers that, - * in conjunction with Domain define the intervals to which each function from - * the 'functions' object applies. It must be in order of increasing magnitude, - * and each must be within Domain. - * - * It basically sets how much of the gradient each function handles. - * - * This attributed is required. - * It's described on page 269 of the PDF 1.3 spec. - * @param theEncode List objects of Double objects. - * This is the linear mapping of input values intop the domain - * of the function's sample table. Default is hard to represent in - * ascii, but basically [0 (Size0 1) 0 (Size1 1)...]. - * This attribute is required. - * - * See page 270 in the PDF 1.3 spec. - * @param theFunctionType This is the function type. It should be 3, - * for a stitching function. - */ - public FunctionDelegate(Function parentFunction, int theFunctionType, List<Double> theDomain, - List<Double> theRange, List<Function> theFunctions, - List<Double> theBounds, List<Double> theEncode) { - this.parentFunction = parentFunction; - this.functionType = 3; // dang well better be 3; - - this.functions = theFunctions; - this.bounds = theBounds; - this.encode = theEncode; - this.domain = theDomain; - this.range = theRange; - - } - - /** - * create an complete Function object of Type 4, a postscript calculator function. - * - * Use null for an optional object parameter if you choose not to use it. - * For optional int parameters, pass the default. - * - * @param theDomain List object of Double objects. - * This is the domain of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theRange List object of Double objects. - * This is the Range of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theFunctionDataStream This is a stream of arithmetic, - * boolean, and stack operators and boolean constants. - * I end up enclosing it in the '{' and '}' braces for you, so don't do it - * yourself. - * - * This attribute is required. - * It's described on page 269 of the PDF 1.3 spec. - * @param theFunctionType The type of function which should be 4, as this is - * a Postscript calculator function - */ - public FunctionDelegate(Function parentFunction, int theFunctionType, List<Double> theDomain, - List<Double> theRange, StringBuffer theFunctionDataStream) { - this.parentFunction = parentFunction; - this.functionType = 4; // dang well better be 4; - this.functionDataStream = theFunctionDataStream; - - this.domain = theDomain; - - this.range = theRange; - - } - - /** - * Gets the function type - */ - public int getFunctionType() { - return functionType; - } - - /** - * Gets the function bounds - */ - public List<Double> getBounds() { - return bounds; - } - - /** - * The function domain - */ - public List<Double> getDomain() { - return domain; - } - - /** - * The function size - */ - public List<Double> getSize() { - return size; - } - - /** - * Gets the function encoding - */ - public List<Double> getEncode() { - return encode; - } - - /** - * Gets the sub-functions - */ - public List<Function> getFunctions() { - return functions; - } - - /** - * Gets the function filter - */ - public List<String> getFilter() { - return filter; - } - - /** - * Gets the bits per sample of the function - */ - public int getBitsPerSample() { - return bitsPerSample; - } - - /** - * Gets the interpolation exponent of the function - */ - public double getInterpolationExponentN() { - return interpolationExponentN; - } - - /** - * Gets the function order - */ - public int getOrder() { - return order; - } - - /** - * Gets the function range - */ - public List<Double> getRange() { - return range; - } - - /** - * Gets the function decoding - */ - public List<Double> getDecode() { - return decode; - } - - /** - * Gets the function data stream - */ - public StringBuffer getDataStream() { - return functionDataStream; - } - - /** - * Gets the function C0 value (color for gradient) - */ - public List<Double> getCZero() { - return cZero; - } - - /** - * Gets the function C1 value (color for gradient) - */ - public List<Double> getCOne() { - return cOne; - } - - public byte[] toByteString() { - return parentFunction.toByteString(); - } -} diff --git a/src/java/org/apache/fop/render/shading/FunctionPattern.java b/src/java/org/apache/fop/render/shading/FunctionPattern.java deleted file mode 100644 index 044053a8b..000000000 --- a/src/java/org/apache/fop/render/shading/FunctionPattern.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.shading; - -import java.io.UnsupportedEncodingException; - -import org.apache.fop.pdf.PDFFunction; -import org.apache.fop.pdf.PDFNumber; -import org.apache.fop.render.ps.svg.PSFunction; - -/** - * A class for writing function objects for different output formats - */ -public class FunctionPattern { - - private Function function; - - /** - * Constructor - * @param function The function from which to write the output - */ - public FunctionPattern(Function function) { - this.function = function; - } - - /** - * Outputs the function to a byte array - */ - public String toWriteableString() { - int vectorSize = 0; - int numberOfFunctions = 0; - int tempInt = 0; - StringBuffer p = new StringBuffer(256); - p.append("<< \n/FunctionType " + function.getFunctionType() + " \n"); - - // FunctionType 0 - if (this.function.getFunctionType() == 0) { - if (function.getDomain() != null) { - // DOMAIN - p.append("/Domain [ "); - vectorSize = function.getDomain().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getDomain().get(tempInt)) - + " "); - } - - p.append("] \n"); - } else { - p.append("/Domain [ 0 1 ] \n"); - } - - // SIZE - if (function.getSize() != null) { - p.append("/Size [ "); - vectorSize = function.getSize().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getSize().get(tempInt)) - + " "); - } - p.append("] \n"); - } - // ENCODE - if (function.getEncode() != null) { - p.append("/Encode [ "); - vectorSize = function.getEncode().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getEncode().get(tempInt)) - + " "); - } - p.append("] \n"); - } else { - p.append("/Encode [ "); - vectorSize = function.getFunctions().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append("0 1 "); - } - p.append("] \n"); - - } - - // BITSPERSAMPLE - p.append("/BitsPerSample " + function.getBitsPerSample()); - - // ORDER (optional) - if (function.getOrder() == 1 || function.getOrder() == 3) { - p.append(" \n/Order " + function.getOrder() + " \n"); - } - - // RANGE - if (function.getRange() != null) { - p.append("/Range [ "); - vectorSize = function.getRange().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getRange().get(tempInt)) - + " "); - } - - p.append("] \n"); - } - - // DECODE - if (function.getDecode() != null) { - p.append("/Decode [ "); - vectorSize = function.getDecode().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getDecode().get(tempInt)) - + " "); - } - - p.append("] \n"); - } - - // LENGTH - if (function.getDataStream() != null) { - p.append("/Length " + (function.getDataStream().length() + 1) - + " \n"); - } - - // FILTER? - if (function.getFilter() != null) { // if there's a filter - vectorSize = function.getFilter().size(); - p.append("/Filter "); - if (vectorSize == 1) { - p.append("/" + (function.getFilter().get(0)) - + " \n"); - } else { - p.append("[ "); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append("/" + (function.getFilter().get(0)) - + " "); - } - p.append("] \n"); - } - } - p.append(">>"); - - // stream representing the function - if (function.getDataStream() != null) { - p.append("\nstream\n" + function.getDataStream() - + "\nendstream"); - } - - // end of if FunctionType 0 - - } else if (function.getFunctionType() == 2) { - // DOMAIN - if (function.getDomain() != null) { - p.append("/Domain [ "); - vectorSize = function.getDomain().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getDomain().get(tempInt)) - + " "); - } - - p.append("] \n"); - } else { - p.append("/Domain [ 0 1 ] \n"); - } - - - // RANGE - if (function.getRange() != null) { - p.append("/Range [ "); - vectorSize = function.getRange().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getRange().get(tempInt)) - + " "); - } - - p.append("] \n"); - } - - // FunctionType, C0, C1, N are required in PDF - - // C0 - if (function.getCZero() != null) { - p.append("/C0 [ "); - vectorSize = function.getCZero().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getCZero().get(tempInt)) - + " "); - } - p.append("] \n"); - } - - // C1 - if (function.getCOne() != null) { - p.append("/C1 [ "); - vectorSize = function.getCOne().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getCOne().get(tempInt)) - + " "); - } - p.append("] \n"); - } - - // N: The interpolation Exponent - p.append("/N " - + PDFNumber.doubleOut(Double.valueOf(function.getInterpolationExponentN())) - + " \n"); - - p.append(">>"); - - } else if (function.getFunctionType() - == 3) { // fix this up when my eyes uncross - // DOMAIN - if (function.getDomain() != null) { - p.append("/Domain [ "); - vectorSize = function.getDomain().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getDomain().get(tempInt)) - + " "); - } - p.append("] \n"); - } else { - p.append("/Domain [ 0 1 ] \n"); - } - - // RANGE - if (function.getRange() != null) { - p.append("/Range [ "); - vectorSize = function.getRange().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getRange().get(tempInt)) - + " "); - } - - p.append("] \n"); - } - - // FUNCTIONS - if (function.getFunctions() != null) { - p.append("/Functions [ "); - numberOfFunctions = function.getFunctions().size(); - for (tempInt = 0; tempInt < numberOfFunctions; tempInt++) { - try { - if (function instanceof PSFunction) { - p.append(new String(function.getFunctions().get(tempInt).toByteString(), "UTF-8") - + " "); - } else { - p.append(((PDFFunction)function.getFunctions().get(tempInt)).referencePDF() - + " "); - } - } catch (UnsupportedEncodingException ex) { - //This should have been made an enum type to avoid throwing exceptions. - } - } - p.append("] \n"); - } - - - // ENCODE - if (function.getEncode() != null) { - p.append("/Encode [ "); - vectorSize = function.getEncode().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getEncode().get(tempInt)) - + " "); - } - - p.append("] \n"); - } else { - p.append("/Encode [ "); - vectorSize = function.getFunctions().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append("0 1 "); - } - p.append("] \n"); - - } - - - // BOUNDS, required, but can be empty - p.append("/Bounds [ "); - if (function.getBounds() != null) { - - vectorSize = function.getBounds().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getBounds().get(tempInt)) - + " "); - } - - } else { - if (function.getFunctions() != null) { - // if there are n functions, - // there must be n-1 bounds. - // so let each function handle an equal portion - // of the whole. e.g. if there are 4, then [ 0.25 0.25 0.25 ] - - String functionsFraction = PDFNumber.doubleOut(Double.valueOf(1.0 - / (numberOfFunctions))); - - for (tempInt = 0; tempInt + 1 < numberOfFunctions; - tempInt++) { - - p.append(functionsFraction + " "); - } - } - - } - p.append("]\n>>"); - } else if (function.getFunctionType() - == 4) { // fix this up when my eyes uncross - // DOMAIN - if (function.getDomain() != null) { - p.append("/Domain [ "); - vectorSize = function.getDomain().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getDomain().get(tempInt)) - + " "); - } - - p.append("] \n"); - } else { - p.append("/Domain [ 0 1 ] \n"); - } - - // RANGE - if (function.getRange() != null) { - p.append("/Range [ "); - vectorSize = function.getRange().size(); - for (tempInt = 0; tempInt < vectorSize; tempInt++) { - p.append(PDFNumber.doubleOut(function.getRange().get(tempInt)) - + " "); - } - - p.append("] \n"); - } - - // LENGTH - if (function.getDataStream() != null) { - p.append("/Length " + (function.getDataStream().length() + 1) - + " \n"); - } - - p.append(">>"); - - // stream representing the function - if (function.getDataStream() != null) { - p.append("\nstream\n{ " + function.getDataStream() - + " }\nendstream"); - } - } - return p.toString(); - } -} diff --git a/src/java/org/apache/fop/render/shading/GradientFactory.java b/src/java/org/apache/fop/render/shading/GradientFactory.java deleted file mode 100644 index 87ac11c83..000000000 --- a/src/java/org/apache/fop/render/shading/GradientFactory.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.shading; - -import java.awt.Color; -import java.util.ArrayList; -import java.util.List; - -import org.apache.xmlgraphics.java2d.color.ColorUtil; - -import org.apache.fop.pdf.PDFDeviceColorSpace; -import org.apache.fop.render.ps.svg.PSSVGGraphics2D; - -public abstract class GradientFactory { - - static GradientRegistrar registrar; - - /** - * Constructor - * @param registrar The object used to register new embedded objects in the - * output format. - */ - public static GradientFactory newInstance(GradientRegistrar theRegistrar) { - registrar = theRegistrar; - if (registrar instanceof PSSVGGraphics2D) { - return new PSGradientFactory(); - } else { - return new PDFGradientFactory(); - } - } - - /** - * Creates a new gradient - * @param radial Determines whether the gradient is radial - * @param theColorspace The colorspace used in PDF and Postscript - * @param theColors The colors to be used in the gradient - * @param theBounds The bounds of each color - * @param theCoords The co-ordinates of the gradient - * @param theMatrix The matrix for any transformations - * @return Returns the Pattern object of the gradient - */ - public abstract Pattern createGradient(boolean radial, - PDFDeviceColorSpace theColorspace, List<Color> theColors, List<Double> theBounds, - List<Double> theCoords, List<Double> theMatrix); - - protected Pattern makeGradient(boolean radial, PDFDeviceColorSpace theColorspace, - List<Color> theColors, List<Double> theBounds, - List<Double> theCoords, List<Double> theMatrix) { - Shading myShad; - Function myfunky; - Function myfunc; - List<Double> theCzero; - List<Double> theCone; - double interpolation = 1.000; - List<Function> theFunctions = new ArrayList<Function>(); - - int currentPosition; - int lastPosition = theColors.size() - 1; - - - // if 5 elements, the penultimate element is 3. - // do not go beyond that, because you always need - // to have a next color when creating the function. - - for (currentPosition = 0; currentPosition < lastPosition; - currentPosition++) { // for every consecutive color pair - Color currentColor = theColors.get(currentPosition); - Color nextColor = 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 (!nextColor.getColorSpace().isCS_sRGB()) { - //Convert to sRGB - nextColor = ColorUtil.toSRGBColor(nextColor); - theColors.set(currentPosition + 1, nextColor); - } - - theCzero = toColorVector(currentColor); - theCone = toColorVector(nextColor); - - myfunc = makeFunction(2, null, null, theCzero, theCone, - interpolation); - - theFunctions.add(myfunc); - - } // end of for every consecutive color pair - - myfunky = makeFunction(3, null, null, theFunctions, theBounds, - null); - - if (radial) { - if (theCoords.size() == 6) { - // make Shading of Type 2 or 3 - myShad = makeShading(3, theColorspace, null, null, false, theCoords, - null, myfunky, null); - } else { // if the center x, center y, and radius specifiy - // the gradient, then assume the same center x, center y, - // and radius of zero for the other necessary component - List<Double> newCoords = new ArrayList<Double>(); - newCoords.add(theCoords.get(0)); - newCoords.add(theCoords.get(1)); - newCoords.add(theCoords.get(2)); - newCoords.add(theCoords.get(0)); - newCoords.add(theCoords.get(1)); - newCoords.add(Double.valueOf(0.0)); - - myShad = makeShading(3, theColorspace, null, null, false, newCoords, - null, myfunky, null); - } - } else { - myShad = makeShading(2, theColorspace, null, null, false, theCoords, - null, myfunky, null); - } - return makePattern(2, myShad, null, null, theMatrix); - } - - public abstract Function makeFunction(int functionType, List<Double> theDomain, - List<Double> theRange, List<Function> theFunctions, - List<Double> theBounds, List<Double> theEncode); - - public abstract Function makeFunction(int functionType, List<Double> theDomain, - List<Double> theRange, List<Double> theCZero, List<Double> theCOne, - double theInterpolationExponentN); - - public abstract Shading makeShading(int theShadingType, - PDFDeviceColorSpace theColorSpace, List<Double> theBackground, List<Double> theBBox, - boolean theAntiAlias, List<Double> theCoords, List<Double> theDomain, - Function theFunction, List<Integer> theExtend); - - public abstract Pattern makePattern(int thePatternType, Shading theShading, List theXUID, - StringBuffer theExtGState, List<Double> theMatrix); - - private List<Double> toColorVector(Color nextColor) { - List<Double> vector = new java.util.ArrayList<Double>(); - float[] comps = nextColor.getColorComponents(null); - for (int i = 0, c = comps.length; i < c; i++) { - vector.add(Double.valueOf(comps[i])); - } - return vector; - } -} diff --git a/src/java/org/apache/fop/render/shading/GradientRegistrar.java b/src/java/org/apache/fop/render/shading/GradientRegistrar.java deleted file mode 100644 index 617fcd4fb..000000000 --- a/src/java/org/apache/fop/render/shading/GradientRegistrar.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.fop.render.shading; - -public interface GradientRegistrar { - - /** - * Registers a function object against the output format document - * @param function The function object to register - * @return Returns either the function which has already been registered - * or the current new registered object. - */ - Function registerFunction(Function function); - - /** - * Registers a shading object against the output format document - * @param shading The shading object to register - * @return Returns either the shading which has already been registered - * or the current new registered object - */ - Shading registerShading(Shading shading); - - /** - * Registers a pattern object against the output format document - * @param pattern The pattern object to register - * @return Returns either the pattern which has already been registered - * or the current new registered object - */ - Pattern registerPattern(Pattern pattern); -} diff --git a/src/java/org/apache/fop/render/shading/PDFGradientFactory.java b/src/java/org/apache/fop/render/shading/PDFGradientFactory.java deleted file mode 100644 index 3b3dcab75..000000000 --- a/src/java/org/apache/fop/render/shading/PDFGradientFactory.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.fop.render.shading; - -import java.awt.Color; -import java.util.List; - -import org.apache.fop.pdf.PDFDeviceColorSpace; -import org.apache.fop.pdf.PDFFunction; -import org.apache.fop.pdf.PDFPattern; -import org.apache.fop.pdf.PDFShading; - -public class PDFGradientFactory extends GradientFactory { - - @Override - public PDFPattern createGradient(boolean radial, PDFDeviceColorSpace theColorspace, List<Color> theColors, - List<Double> theBounds, List<Double> theCoords, List<Double> theMatrix) { - return (PDFPattern)makeGradient(radial, theColorspace, theColors, theBounds, - theCoords, theMatrix); - } - - @Override - public Function makeFunction(int functionType, List<Double> theDomain, - List<Double> theRange, List<Function> theFunctions, - List<Double> theBounds, List<Double> theEncode) { - Function newFunction = new PDFFunction(functionType, theDomain, theRange, theFunctions, - theBounds, theEncode); - newFunction = registrar.registerFunction(newFunction); - return newFunction; - } - - public Function makeFunction(int functionType, List<Double> theDomain, - List<Double> theRange, List<Double> theCZero, List<Double> theCOne, - double theInterpolationExponentN) { - Function newFunction = new PDFFunction(functionType, theDomain, theRange, theCZero, - theCOne, theInterpolationExponentN); - newFunction = registrar.registerFunction(newFunction); - return newFunction; - } - - @Override - public Shading makeShading(int theShadingType, - PDFDeviceColorSpace theColorSpace, List<Double> theBackground, List<Double> theBBox, - boolean theAntiAlias, List<Double> theCoords, List<Double> theDomain, - Function theFunction, List<Integer> theExtend) { - Shading newShading = new PDFShading(theShadingType, theColorSpace, theBackground, - theBBox, theAntiAlias, theCoords, theDomain, theFunction, theExtend); - newShading = registrar.registerShading(newShading); - return newShading; - } - - @Override - public Pattern makePattern(int thePatternType, Shading theShading, List theXUID, - StringBuffer theExtGState, List<Double> theMatrix) { - Pattern newPattern = new PDFPattern(thePatternType, theShading, theXUID, theExtGState, - theMatrix); - newPattern = registrar.registerPattern(newPattern); - return newPattern; - } - -} diff --git a/src/java/org/apache/fop/render/shading/PSGradientFactory.java b/src/java/org/apache/fop/render/shading/PSGradientFactory.java deleted file mode 100644 index cd47de93a..000000000 --- a/src/java/org/apache/fop/render/shading/PSGradientFactory.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.fop.render.shading; - -import java.awt.Color; -import java.util.List; - -import org.apache.fop.pdf.PDFDeviceColorSpace; -import org.apache.fop.render.ps.svg.PSFunction; -import org.apache.fop.render.ps.svg.PSPattern; -import org.apache.fop.render.ps.svg.PSShading; - -public class PSGradientFactory extends GradientFactory { - - @Override - public PSPattern createGradient(boolean radial, PDFDeviceColorSpace theColorspace, - List<Color> theColors, List<Double> theBounds, List<Double> theCoords, - List<Double> theMatrix) { - return (PSPattern)makeGradient(radial, theColorspace, theColors, theBounds, - theCoords, theMatrix); - } - - public Function makeFunction(int functionType, List<Double> theDomain, - List<Double> theRange, List<Function> theFunctions, - List<Double> theBounds, List<Double> theEncode) { - Function newFunction = new PSFunction(functionType, theDomain, theRange, theFunctions, - theBounds, theEncode); - return newFunction; - } - - @Override - public Function makeFunction(int functionType, List<Double> theDomain, - List<Double> theRange, List<Double> theCZero, List<Double> theCOne, - double theInterpolationExponentN) { - Function newFunction = new PSFunction(functionType, theDomain, theRange, theCZero, - theCOne, theInterpolationExponentN); - return newFunction; - } - - @Override - public Shading makeShading(int theShadingType, - PDFDeviceColorSpace theColorSpace, List<Double> theBackground, List<Double> theBBox, - boolean theAntiAlias, List<Double> theCoords, List<Double> theDomain, - Function theFunction, List<Integer> theExtend) { - Shading newShading = new PSShading(theShadingType, theColorSpace, theBackground, theBBox, - theAntiAlias, theCoords, theDomain, theFunction, theExtend); - return newShading; - } - - @Override - public Pattern makePattern(int thePatternType, Shading theShading, List theXUID, - StringBuffer theExtGState, List<Double> theMatrix) { - return new PSPattern(thePatternType, theShading, theXUID, theExtGState); - } -} diff --git a/src/java/org/apache/fop/render/shading/Pattern.java b/src/java/org/apache/fop/render/shading/Pattern.java deleted file mode 100644 index b66926e53..000000000 --- a/src/java/org/apache/fop/render/shading/Pattern.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.fop.render.shading; - -public interface Pattern { - -} diff --git a/src/java/org/apache/fop/render/shading/Shading.java b/src/java/org/apache/fop/render/shading/Shading.java deleted file mode 100644 index 385cb112b..000000000 --- a/src/java/org/apache/fop/render/shading/Shading.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.fop.render.shading; - - -public interface Shading { - StringBuffer handleShadingType1(StringBuffer p); - StringBuffer handleShadingType2or3(StringBuffer p); - StringBuffer handleShadingType4or6or7(StringBuffer p); - StringBuffer handleShadingType5(StringBuffer p); -} diff --git a/src/java/org/apache/fop/render/shading/ShadingPattern.java b/src/java/org/apache/fop/render/shading/ShadingPattern.java deleted file mode 100644 index 6dac65f55..000000000 --- a/src/java/org/apache/fop/render/shading/ShadingPattern.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.fop.render.shading; - -import java.util.List; - -import org.apache.fop.pdf.PDFDeviceColorSpace; -import org.apache.fop.pdf.PDFNumber; - -/** - * A class for writing shading objects for different output formats - */ -public class ShadingPattern { - - private Shading shading; - - /** - * Constructor - * @param shading The shading object from which to write the output - */ - public ShadingPattern(Shading shading) { - this.shading = shading; - } - - /** - * Outputs the given shading object to a String - * @param colorSpace The Colospace (PDF and Postscript) - * @param shadingType The shading type - * @param background The background - * @param bBox The bounding box - * @param antiAlias Anti-aliasing - * @return Returns the output string - */ - public String toString(PDFDeviceColorSpace colorSpace, int shadingType, List background, - List bBox, boolean antiAlias) { - StringBuffer p = new StringBuffer(128); - p.append("<<\n/ShadingType " + shadingType + " \n"); - if (colorSpace != null) { - p.append("/ColorSpace /" - + colorSpace.getName() + " \n"); - } - - if (background != null) { - p.append("/Background [ "); - for (int bgIndex = 0; bgIndex < background.size(); bgIndex++) { - p.append(PDFNumber.doubleOut((Double)background.get(bgIndex)) - + " "); - } - p.append("] \n"); - } - - if (bBox - != null) { // I've never seen an example, so I guess this is right. - p.append("/BBox [ "); - for (int bboxIndex = 0; bboxIndex < bBox.size(); bboxIndex++) { - p.append(PDFNumber.doubleOut((Double)bBox.get(bboxIndex)) - + " "); - } - p.append("] \n"); - } - - if (antiAlias) { - p.append("/AntiAlias " + antiAlias + " \n"); - } - - // Here's where we differentiate based on what type it is. - switch (shadingType) { - //Function based shading - case 1: p = shading.handleShadingType1(p); break; - //Axial shading - case 2: - //Radial shading - case 3: p = shading.handleShadingType2or3(p); break; - //Free-form Gouraud-shaded triangle meshes - case 4: - //Coons patch meshes - case 6: - //Tensor product patch meshes - case 7: p = shading.handleShadingType4or6or7(p); break; - //Lattice Free form gouraud-shaded triangle mesh - case 5: p = shading.handleShadingType5(p); break; - default: //Shading pattern outside expecting values - break; - } - - p.append(">>"); - - return (p.toString()); - } -} diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java index 6344e37e6..c9ec79d0d 100644 --- a/src/java/org/apache/fop/svg/PDFGraphics2D.java +++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java @@ -36,7 +36,6 @@ import java.awt.Stroke; import java.awt.color.ColorSpace; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; -import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; @@ -50,6 +49,7 @@ import java.awt.image.renderable.RenderableImage; import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -93,15 +93,13 @@ import org.apache.fop.pdf.PDFResources; import org.apache.fop.pdf.PDFShading; import org.apache.fop.pdf.PDFText; import org.apache.fop.pdf.PDFXObject; +import org.apache.fop.render.gradient.Function; +import org.apache.fop.render.gradient.GradientMaker; +import org.apache.fop.render.gradient.Pattern; +import org.apache.fop.render.gradient.Shading; import org.apache.fop.render.pdf.ImageRawCCITTFaxAdapter; import org.apache.fop.render.pdf.ImageRawJPEGAdapter; import org.apache.fop.render.pdf.ImageRenderedAdapter; -import org.apache.fop.render.shading.Function; -import org.apache.fop.render.shading.GradientFactory; -import org.apache.fop.render.shading.GradientRegistrar; -import org.apache.fop.render.shading.PDFGradientFactory; -import org.apache.fop.render.shading.Pattern; -import org.apache.fop.render.shading.Shading; /** * <p>PDF Graphics 2D. @@ -112,7 +110,7 @@ import org.apache.fop.render.shading.Shading; * * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D */ -public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHandler, GradientRegistrar { +public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHandler { private static final AffineTransform IDENTITY_TRANSFORM = new AffineTransform(); /** The number of decimal places. */ @@ -818,159 +816,18 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand new Color[] {gpaint.getColor1(), gpaint.getColor2()}, gpaint.isCyclic() ? LinearGradientPaint.REPEAT : LinearGradientPaint.NO_CYCLE); } - if (paint instanceof LinearGradientPaint) { - LinearGradientPaint gp = (LinearGradientPaint)paint; - - // This code currently doesn't support 'repeat'. - // For linear gradients it is possible to construct - // a 'tile' that is repeated with a PDF pattern, but - // it would be very tricky as you would have to rotate - // the coordinate system so the repeat was axially - // aligned. At this point I'm just going to rasterize it. - MultipleGradientPaint.CycleMethodEnum cycle = gp.getCycleMethod(); - if (cycle != MultipleGradientPaint.NO_CYCLE) { - return false; - } - - Color[] cols = gp.getColors(); - float[] fractions = gp.getFractions(); - - // Build proper transform from gradient space to page space - // ('Patterns' don't get userspace transform). - AffineTransform transform; - transform = new AffineTransform(getBaseTransform()); - transform.concatenate(getTransform()); - transform.concatenate(gp.getTransform()); - - List<Double> theMatrix = new java.util.ArrayList<Double>(); - double [] mat = new double[6]; - transform.getMatrix(mat); - for (int idx = 0; idx < mat.length; idx++) { - theMatrix.add(new Double(mat[idx])); - } - - Point2D p1 = gp.getStartPoint(); - Point2D p2 = gp.getEndPoint(); - List<Double> theCoords = new java.util.ArrayList<Double>(); - theCoords.add(new Double(p1.getX())); - theCoords.add(new Double(p1.getY())); - theCoords.add(new Double(p2.getX())); - theCoords.add(new Double(p2.getY())); - - List<Boolean> theExtend = new java.util.ArrayList<Boolean>(); - theExtend.add(Boolean.TRUE); - theExtend.add(Boolean.TRUE); - - List<Double> theDomain = new java.util.ArrayList<Double>(); - theDomain.add(new Double(0)); - theDomain.add(new Double(1)); - - List<Double> theEncode = new java.util.ArrayList<Double>(); - theEncode.add(new Double(0)); - theEncode.add(new Double(1)); - theEncode.add(new Double(0)); - theEncode.add(new Double(1)); - - List<Double> theBounds = new java.util.ArrayList<Double>(); - - List<Color> someColors = new java.util.ArrayList<Color>(); - - for (int count = 0; count < cols.length; count++) { - Color c1 = cols[count]; - if (c1.getAlpha() != 255) { - return false; // PDF can't do alpha - } - - //PDFColor color1 = new PDFColor(c1.getRed(), c1.getGreen(), - // c1.getBlue()); - someColors.add(c1); - if (count > 0 && count < cols.length - 1) { - theBounds.add(new Double(fractions[count])); - } - } - - //Gradients are currently restricted to sRGB - PDFDeviceColorSpace colSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); - PDFGradientFactory gradientFactory = (PDFGradientFactory)GradientFactory.newInstance(this); - PDFPattern myPat = gradientFactory.createGradient(false, colSpace, someColors, theBounds, - theCoords, theMatrix); - currentStream.write(myPat.getColorSpaceOut(fill)); - + if (paint instanceof LinearGradientPaint && gradientSupported((LinearGradientPaint) paint)) { + Pattern pattern = GradientMaker.makeLinearGradient((LinearGradientPaint) paint, + getBaseTransform(), getTransform()); + PDFPattern pdfPattern = createPDFPattern(pattern); + currentStream.write(pdfPattern.getColorSpaceOut(fill)); return true; } - if (paint instanceof RadialGradientPaint) { - RadialGradientPaint rgp = (RadialGradientPaint)paint; - - // There is essentially no way to support repeats - // in PDF for radial gradients (the one option would - // be to 'grow' the outer circle until it fully covered - // the bounds and then grow the stops accordingly, the - // problem is that this may require an extremely large - // number of stops for cases where the focus is near - // the edge of the outer circle). so we rasterize. - MultipleGradientPaint.CycleMethodEnum cycle = rgp.getCycleMethod(); - if (cycle != MultipleGradientPaint.NO_CYCLE) { - return false; - } - - AffineTransform transform; - transform = new AffineTransform(getBaseTransform()); - transform.concatenate(getTransform()); - transform.concatenate(rgp.getTransform()); - - List<Double> theMatrix = new java.util.ArrayList<Double>(); - double [] mat = new double[6]; - transform.getMatrix(mat); - for (int idx = 0; idx < mat.length; idx++) { - theMatrix.add(new Double(mat[idx])); - } - - double ar = rgp.getRadius(); - Point2D ac = rgp.getCenterPoint(); - Point2D af = rgp.getFocusPoint(); - - List<Double> theCoords = new java.util.ArrayList<Double>(); - double dx = af.getX() - ac.getX(); - double dy = af.getY() - ac.getY(); - double d = Math.sqrt(dx * dx + dy * dy); - if (d > ar) { - // the center point af must be within the circle with - // radius ar centered at ac so limit it to that. - double scale = (ar * .9999) / d; - dx = dx * scale; - dy = dy * scale; - } - - theCoords.add(new Double(ac.getX() + dx)); // Fx - theCoords.add(new Double(ac.getY() + dy)); // Fy - theCoords.add(new Double(0)); - theCoords.add(new Double(ac.getX())); - theCoords.add(new Double(ac.getY())); - theCoords.add(new Double(ar)); - - Color[] cols = rgp.getColors(); - List<Color> someColors = new java.util.ArrayList<Color>(); - for (int count = 0; count < cols.length; count++) { - Color cc = cols[count]; - if (cc.getAlpha() != 255) { - return false; // PDF can't do alpha - } - - someColors.add(cc); - } - - float[] fractions = rgp.getFractions(); - List<Double> theBounds = new java.util.ArrayList<Double>(); - for (int count = 1; count < fractions.length - 1; count++) { - float offset = fractions[count]; - theBounds.add(new Double(offset)); - } - PDFDeviceColorSpace colSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); - PDFGradientFactory gradientFactory = (PDFGradientFactory) GradientFactory.newInstance(this); - PDFPattern myPat = gradientFactory.createGradient(true, colSpace, someColors, theBounds, - theCoords, theMatrix); - currentStream.write(myPat.getColorSpaceOut(fill)); - + if (paint instanceof RadialGradientPaint && gradientSupported((RadialGradientPaint) paint)) { + Pattern pattern = GradientMaker.makeRadialGradient((RadialGradientPaint) paint, + getBaseTransform(), getTransform()); + PDFPattern pdfPattern = createPDFPattern(pattern); + currentStream.write(pdfPattern.getColorSpaceOut(fill)); return true; } if (paint instanceof PatternPaint) { @@ -980,6 +837,47 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand return false; // unknown paint } + private PDFPattern createPDFPattern(Pattern pattern) { + Shading shading = pattern.getShading(); + Function function = shading.getFunction(); + List<PDFFunction> pdfFunctions = new ArrayList<PDFFunction>(function.getFunctions().size()); + for (Function f : function.getFunctions()) { + pdfFunctions.add(registerFunction(new PDFFunction(f))); + } + PDFFunction pdfFunction = registerFunction(new PDFFunction(function, pdfFunctions)); + PDFShading pdfShading = new PDFShading(shading.getShadingType(), shading.getColorSpace(), shading.getCoords(), + pdfFunction); + pdfShading = registerShading(pdfShading); + PDFPattern pdfPattern = new PDFPattern(pattern.getPatternType(), pdfShading, null, null, pattern.getMatrix()); + return registerPattern(pdfPattern); + } + + private boolean gradientSupported(MultipleGradientPaint gradient) { + return !(gradientContainsTransparency(gradient) || gradientIsRepeated(gradient)); + } + + private boolean gradientContainsTransparency(MultipleGradientPaint gradient) { + for (Color color : gradient.getColors()) { + if (color.getAlpha() != 255) { + return true; + } + } + return false; + } + + private boolean gradientIsRepeated(MultipleGradientPaint gradient) { + // For linear gradients it is possible to construct a 'tile' that is repeated with + // a PDF pattern, but it would be very tricky as the coordinate system would have + // to be rotated so the repeat is axially aligned. + + // For radial gradients there is essentially no way to support repeats in PDF (the + // one option would be to 'grow' the outer circle until it fully covers the + // bounds and then grow the stops accordingly, the problem is that this may + // require an extremely large number of stops for cases where the focus is near + // the edge of the outer circle). + return (gradient.getCycleMethod() != MultipleGradientPaint.NO_CYCLE); + } + private boolean createPattern(PatternPaint pp, boolean fill) { preparePainting(); @@ -1883,8 +1781,8 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand * @return Returns either the function which has already been registered * or the current new registered object. */ - public Function registerFunction(Function function) { - return pdfDoc.getFactory().registerFunction((PDFFunction)function); + public PDFFunction registerFunction(PDFFunction function) { + return pdfDoc.getFactory().registerFunction(function); } /** @@ -1893,9 +1791,8 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand * @return Returs either the shading which has already been registered * or the current new registered object */ - public Shading registerShading(Shading shading) { - assert shading instanceof PDFShading; - return pdfDoc.getFactory().registerShading(resourceContext, (PDFShading)shading); + public PDFShading registerShading(PDFShading shading) { + return pdfDoc.getFactory().registerShading(resourceContext, shading); } /** @@ -1904,9 +1801,8 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand * @return Returns either the pattern which has already been registered * or the current new registered object */ - public Pattern registerPattern(Pattern pattern) { - assert pattern instanceof PDFPattern; - return pdfDoc.getFactory().registerPattern(resourceContext, (PDFPattern)pattern); + public PDFPattern registerPattern(PDFPattern pattern) { + return pdfDoc.getFactory().registerPattern(resourceContext, pattern); } } |