import java.util.Collections;
import java.util.List;
-import org.apache.fop.render.shading.Function;
+import org.apache.fop.render.gradient.Function;
/**
* class representing a PDF Function.
import java.util.List;
-import org.apache.fop.render.shading.Shading;
+import org.apache.fop.render.gradient.Shading;
/**
--- /dev/null
+/*
+ * 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.Collections;
+import java.util.List;
+
+import org.apache.fop.pdf.PDFNumber;
+
+public class Function {
+
+ /**
+ * 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;
+
+ /* ********************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
+ */
+ 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;
+
+ /**
+ * Optional for Type 0: A 2 * n array of Doubles which provides
+ * a linear mapping of sample values to the range. Defaults to Range.
+ */
+ private 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
+ */
+ private 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.
+ */
+ private List<String> filter;
+ /* *************************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<Double> 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 functionType The type of the function, which should be 2.
+ * @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(int functionType, List<Double> domain, List<Double> range,
+ float[] cZero, float[] cOne, double interpolationExponentN) {
+ this.functionType = 2; // dang well better be 2;
+
+ this.cZero = cZero;
+ this.cOne = cOne;
+ this.interpolationExponentN = interpolationExponentN;
+
+ this.domain = domain;
+ this.range = range;
+
+ }
+
+ /**
+ * 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 functionType This is the function type. It should be 3,
+ * for a stitching function.
+ * @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(int functionType, List<Double> domain, List<Double> range,
+ List<Function> functions, List<Double> bounds,
+ List<Double> encode) {
+ this.functionType = 3; // dang well better be 3;
+
+ this.functions = functions;
+ this.bounds = bounds;
+ this.encode = encode;
+ this.domain = domain;
+ this.range = range;
+
+ }
+
+ /**
+ * 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() {
+ if (functions == null) {
+ return Collections.emptyList();
+ } else {
+ 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 float[] getCZero() {
+ return cZero;
+ }
+
+ /**
+ * Gets the function C1 value (color for gradient)
+ */
+ public float[] getCOne() {
+ return cOne;
+ }
+
+ public String toWriteableString(List<String> functionsStrings) {
+ StringBuilder out = new StringBuilder(256);
+ out.append("<<\n/FunctionType " + functionType + "\n");
+ outputDomain(out);
+ if (this.functionType == 0) {
+ outputSize(out);
+ outputEncode(out);
+ outputBitsPerSample(out);
+ outputOrder(out);
+ outputRange(out);
+ outputDecode(out);
+ if (functionDataStream != null) {
+ out.append("/Length " + (functionDataStream.length() + 1) + "\n");
+ }
+ outputFilter(out);
+ out.append(">>");
+ if (functionDataStream != null) {
+ out.append("\nstream\n" + functionDataStream + "\nendstream");
+ }
+ } else if (functionType == 2) {
+ outputRange(out);
+ outputCZero(out);
+ outputCOne(out);
+ outputInterpolationExponentN(out);
+ out.append(">>");
+ } else if (functionType == 3) {
+ outputRange(out);
+ if (!functions.isEmpty()) {
+ out.append("/Functions [ ");
+ for (String f : functionsStrings) {
+ out.append(f);
+ out.append(' ');
+ }
+ out.append("]\n");
+ }
+ outputEncode(out);
+ out.append("/Bounds ");
+ if (bounds != null) {
+ outputDoubles(out, 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 = PDFNumber.doubleOut(Double.valueOf(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);
+ if (functionDataStream != null) {
+ out.append("/Length " + (functionDataStream.length() + 1) + "\n");
+ }
+ out.append(">>");
+ if (functionDataStream != null) {
+ out.append("\nstream\n{ " + functionDataStream + " }\nendstream");
+ }
+ }
+ return out.toString();
+ }
+
+ private void outputDomain(StringBuilder p) {
+ if (domain != null) {
+ p.append("/Domain ");
+ outputDoubles(p, domain);
+ p.append("\n");
+ } else {
+ p.append("/Domain [ 0 1 ]\n");
+ }
+ }
+
+ private void outputSize(StringBuilder out) {
+ if (size != null) {
+ out.append("/Size ");
+ outputDoubles(out, size);
+ out.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) {
+ if (range != null) {
+ out.append("/Range ");
+ outputDoubles(out, range);
+ out.append("\n");
+ }
+ }
+
+ private void outputEncode(StringBuilder out) {
+ if (encode != null) {
+ out.append("/Encode ");
+ outputDoubles(out, encode);
+ out.append("\n");
+ } else {
+ out.append("/Encode [ ");
+ int size = functions.size();
+ for (int i = 0; i < size; i++) {
+ out.append("0 1 ");
+ }
+ out.append("]\n");
+ }
+ }
+
+ private void outputDecode(StringBuilder out) {
+ if (decode != null) {
+ out.append("/Decode ");
+ outputDoubles(out, decode);
+ out.append("\n");
+ }
+ }
+
+ private void outputFilter(StringBuilder out) {
+ if (filter != null) {
+ int size = filter.size();
+ out.append("/Filter ");
+ if (size == 1) {
+ out.append("/" + filter.get(0) + "\n");
+ } else {
+ out.append("[ ");
+ for (int i = 0; i < size; i++) {
+ out.append("/" + filter.get(0) + " ");
+ }
+ out.append("]\n");
+ }
+ }
+ }
+
+ private void outputCZero(StringBuilder out) {
+ if (cZero != null) {
+ out.append("/C0 [ ");
+ for (float c : cZero) {
+ out.append(PDFNumber.doubleOut(c));
+ out.append(" ");
+ }
+ out.append("]\n");
+ }
+ }
+
+ private void outputCOne(StringBuilder out) {
+ if (cOne != null) {
+ out.append("/C1 [ ");
+ for (float c : cOne) {
+ out.append(PDFNumber.doubleOut(c));
+ out.append(" ");
+ }
+ out.append("]\n");
+ }
+ }
+
+ private void outputInterpolationExponentN(StringBuilder out) {
+ out.append("/N ");
+ out.append(PDFNumber.doubleOut(Double.valueOf(interpolationExponentN)));
+ out.append("\n");
+ }
+
+ private void outputDoubles(StringBuilder out, List<Double> doubles) {
+ out.append("[ ");
+ for (Double d : doubles) {
+ out.append(PDFNumber.doubleOut(d));
+ out.append(" ");
+ }
+ out.append("]");
+ }
+
+}
--- /dev/null
+/*
+ * 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 {
+
+ 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(new Double(startPoint.getX()));
+ coords.add(new Double(startPoint.getY()));
+ coords.add(new Double(endPoint.getX()));
+ coords.add(new Double(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 center 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<Double> 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(3, 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<Double> makeBounds(MultipleGradientPaint gradient) {
+ // TODO is the conversion to double necessary?
+ float[] fractions = gradient.getFractions();
+ List<Double> bounds = new java.util.ArrayList<Double>(fractions.length);
+ for (float offset : fractions) {
+ if (0f < offset && offset < 1f) {
+ bounds.add(Double.valueOf(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(2, 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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.List;
+
+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;
+ }
+
+}
--- /dev/null
+/*
+ * 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.List;
+
+import org.apache.fop.pdf.PDFDeviceColorSpace;
+import org.apache.fop.pdf.PDFNumber;
+
+
+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;
+
+ /**
+ * Optional: A List specifying the clipping rectangle
+ */
+ private final List<Double> bbox;
+
+ /**
+ * Optional for Type 1: A transformation matrix
+ */
+ private final List<Double> matrix;
+
+ /**
+ * The background color. Since shading is opaque,
+ * this is very rarely used.
+ */
+ private final List<Double> background;
+
+ /**
+ * 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.
+ */
+ private final List<Double> domain;
+
+ /**
+ * 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
+ */
+ private final List<Double> decode;
+
+ /**
+ * 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.background = null;
+ this.bbox = null;
+ this.antiAlias = false;
+ this.coords = coords;
+ this.domain = null;
+ this.function = function;
+ this.extend = null;
+ this.matrix = null;
+ this.decode = null;
+ 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<Double> getBBox() {
+ return bbox;
+ }
+
+ public List<Double> getMatrix() {
+ return matrix;
+ }
+
+ public List<Double> getBackground() {
+ return background;
+ }
+
+ public List<Double> getDomain() {
+ return domain;
+ }
+
+ public List<Double> getDecode() {
+ return decode;
+ }
+
+ 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, FunctionRenderer functionRenderer) {
+ out.append("<<\n/ShadingType " + shadingType + "\n");
+ if (colorSpace != null) {
+ out.append("/ColorSpace /" + colorSpace.getName() + "\n");
+ }
+
+ if (background != null) {
+ out.append("/Background ");
+ outputDoubles(out, background);
+ out.append("\n");
+ }
+
+ if (bbox != null) {
+ out.append("/BBox");
+ outputDoubles(out, bbox);
+ out.append("\n");
+ }
+
+ if (antiAlias) {
+ out.append("/AntiAlias " + antiAlias + "\n");
+ }
+
+ switch (shadingType) {
+ // Function based shading
+ case 1: outputShadingType1(out, functionRenderer); break;
+ // Axial shading
+ case 2:
+ // Radial shading
+ case 3: outputShadingType2or3(out, functionRenderer); break;
+ // Free-form Gouraud-shaded triangle meshes
+ case 4:
+ // Coons patch meshes
+ case 6:
+ // Tensor product patch meshes
+ case 7: outputShadingType4or6or7(out, functionRenderer); break;
+ // Lattice Free form gouraud-shaded triangle mesh
+ case 5: outputShadingType5(out, functionRenderer); break;
+ default: throw new UnsupportedOperationException("Shading type " + shadingType);
+ }
+
+ out.append(">>");
+ }
+
+ private void outputDoubles(StringBuilder out, List<Double> doubles) {
+ out.append("[ ");
+ for (Double d : doubles) {
+ out.append(PDFNumber.doubleOut(d));
+ out.append(" ");
+ }
+ out.append("]");
+ }
+
+ private void outputShadingType1(StringBuilder out, Shading.FunctionRenderer functionRenderer) {
+ if (domain != null) {
+ out.append("/Domain ");
+ outputDoubles(out, domain);
+ out.append("\n");
+ } else {
+ out.append("/Domain [ 0 1 ] \n");
+ }
+
+ if (matrix != null) {
+ out.append("/Matrix ");
+ outputDoubles(out, matrix);
+ out.append("\n");
+ }
+ outputFunction(out, functionRenderer);
+ }
+
+ private void outputShadingType2or3(StringBuilder out, Shading.FunctionRenderer functionRenderer) {
+ if (coords != null) {
+ out.append("/Coords ");
+ outputDoubles(out, coords);
+ out.append("\n");
+ }
+
+ if (domain != null) {
+ out.append("/Domain ");
+ outputDoubles(out, domain);
+ out.append("\n");
+ } else {
+ out.append("/Domain [ 0 1 ] \n");
+ }
+
+ if (extend != null) {
+ out.append("/Extend [");
+ for (Boolean b : extend) {
+ out.append(b);
+ out.append(" ");
+ }
+ out.append("\n");
+ } else {
+ out.append("/Extend [ true true ] \n");
+ }
+
+ outputFunction(out, functionRenderer);
+ }
+
+ private void outputShadingType4or6or7(StringBuilder out, 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");
+ }
+
+ if (decode != null) {
+ out.append("/Decode ");
+ outputDoubles(out, decode);
+ out.append("\n");
+ }
+
+ outputFunction(out, functionRenderer);
+ }
+
+ private void outputShadingType5(StringBuilder out, 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 (decode != null) {
+ out.append("/Decode ");
+ outputDoubles(out, decode);
+ out.append("\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");
+ }
+ }
+}
import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
import org.apache.xmlgraphics.ps.PSGenerator;
-import org.apache.fop.render.shading.Function;
-import org.apache.fop.render.shading.GradientMaker;
-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.GradientMaker;
+import org.apache.fop.render.gradient.Pattern;
+import org.apache.fop.render.gradient.Shading;
public class PSSVGGraphics2D extends PSGraphics2D {
+++ /dev/null
-/*
- * 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.Collections;
-import java.util.List;
-
-import org.apache.fop.pdf.PDFNumber;
-
-public class Function {
-
- /**
- * 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;
-
- /* ********************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
- */
- 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;
-
- /**
- * Optional for Type 0: A 2 * n array of Doubles which provides
- * a linear mapping of sample values to the range. Defaults to Range.
- */
- private 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
- */
- private 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.
- */
- private List<String> filter;
- /* *************************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<Double> 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 functionType The type of the function, which should be 2.
- * @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(int functionType, List<Double> domain, List<Double> range,
- float[] cZero, float[] cOne, double interpolationExponentN) {
- this.functionType = 2; // dang well better be 2;
-
- this.cZero = cZero;
- this.cOne = cOne;
- this.interpolationExponentN = interpolationExponentN;
-
- this.domain = domain;
- this.range = range;
-
- }
-
- /**
- * 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 functionType This is the function type. It should be 3,
- * for a stitching function.
- * @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(int functionType, List<Double> domain, List<Double> range,
- List<Function> functions, List<Double> bounds,
- List<Double> encode) {
- this.functionType = 3; // dang well better be 3;
-
- this.functions = functions;
- this.bounds = bounds;
- this.encode = encode;
- this.domain = domain;
- this.range = range;
-
- }
-
- /**
- * 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() {
- if (functions == null) {
- return Collections.emptyList();
- } else {
- 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 float[] getCZero() {
- return cZero;
- }
-
- /**
- * Gets the function C1 value (color for gradient)
- */
- public float[] getCOne() {
- return cOne;
- }
-
- public String toWriteableString(List<String> functionsStrings) {
- StringBuilder out = new StringBuilder(256);
- out.append("<<\n/FunctionType " + functionType + "\n");
- outputDomain(out);
- if (this.functionType == 0) {
- outputSize(out);
- outputEncode(out);
- outputBitsPerSample(out);
- outputOrder(out);
- outputRange(out);
- outputDecode(out);
- if (functionDataStream != null) {
- out.append("/Length " + (functionDataStream.length() + 1) + "\n");
- }
- outputFilter(out);
- out.append(">>");
- if (functionDataStream != null) {
- out.append("\nstream\n" + functionDataStream + "\nendstream");
- }
- } else if (functionType == 2) {
- outputRange(out);
- outputCZero(out);
- outputCOne(out);
- outputInterpolationExponentN(out);
- out.append(">>");
- } else if (functionType == 3) {
- outputRange(out);
- if (!functions.isEmpty()) {
- out.append("/Functions [ ");
- for (String f : functionsStrings) {
- out.append(f);
- out.append(' ');
- }
- out.append("]\n");
- }
- outputEncode(out);
- out.append("/Bounds ");
- if (bounds != null) {
- outputDoubles(out, 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 = PDFNumber.doubleOut(Double.valueOf(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);
- if (functionDataStream != null) {
- out.append("/Length " + (functionDataStream.length() + 1) + "\n");
- }
- out.append(">>");
- if (functionDataStream != null) {
- out.append("\nstream\n{ " + functionDataStream + " }\nendstream");
- }
- }
- return out.toString();
- }
-
- private void outputDomain(StringBuilder p) {
- if (domain != null) {
- p.append("/Domain ");
- outputDoubles(p, domain);
- p.append("\n");
- } else {
- p.append("/Domain [ 0 1 ]\n");
- }
- }
-
- private void outputSize(StringBuilder out) {
- if (size != null) {
- out.append("/Size ");
- outputDoubles(out, size);
- out.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) {
- if (range != null) {
- out.append("/Range ");
- outputDoubles(out, range);
- out.append("\n");
- }
- }
-
- private void outputEncode(StringBuilder out) {
- if (encode != null) {
- out.append("/Encode ");
- outputDoubles(out, encode);
- out.append("\n");
- } else {
- out.append("/Encode [ ");
- int size = functions.size();
- for (int i = 0; i < size; i++) {
- out.append("0 1 ");
- }
- out.append("]\n");
- }
- }
-
- private void outputDecode(StringBuilder out) {
- if (decode != null) {
- out.append("/Decode ");
- outputDoubles(out, decode);
- out.append("\n");
- }
- }
-
- private void outputFilter(StringBuilder out) {
- if (filter != null) {
- int size = filter.size();
- out.append("/Filter ");
- if (size == 1) {
- out.append("/" + filter.get(0) + "\n");
- } else {
- out.append("[ ");
- for (int i = 0; i < size; i++) {
- out.append("/" + filter.get(0) + " ");
- }
- out.append("]\n");
- }
- }
- }
-
- private void outputCZero(StringBuilder out) {
- if (cZero != null) {
- out.append("/C0 [ ");
- for (float c : cZero) {
- out.append(PDFNumber.doubleOut(c));
- out.append(" ");
- }
- out.append("]\n");
- }
- }
-
- private void outputCOne(StringBuilder out) {
- if (cOne != null) {
- out.append("/C1 [ ");
- for (float c : cOne) {
- out.append(PDFNumber.doubleOut(c));
- out.append(" ");
- }
- out.append("]\n");
- }
- }
-
- private void outputInterpolationExponentN(StringBuilder out) {
- out.append("/N ");
- out.append(PDFNumber.doubleOut(Double.valueOf(interpolationExponentN)));
- out.append("\n");
- }
-
- private void outputDoubles(StringBuilder out, List<Double> doubles) {
- out.append("[ ");
- for (Double d : doubles) {
- out.append(PDFNumber.doubleOut(d));
- out.append(" ");
- }
- out.append("]");
- }
-
-}
+++ /dev/null
-/*
- * 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.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 {
-
- 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(new Double(startPoint.getX()));
- coords.add(new Double(startPoint.getY()));
- coords.add(new Double(endPoint.getX()));
- coords.add(new Double(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 center 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<Double> 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(3, 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<Double> makeBounds(MultipleGradientPaint gradient) {
- // TODO is the conversion to double necessary?
- float[] fractions = gradient.getFractions();
- List<Double> bounds = new java.util.ArrayList<Double>(fractions.length);
- for (float offset : fractions) {
- if (0f < offset && offset < 1f) {
- bounds.add(Double.valueOf(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(2, 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;
- }
-
-}
+++ /dev/null
-/*
- * 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 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;
- }
-
-}
+++ /dev/null
-/*
- * 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;
-
-
-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;
-
- /**
- * Optional: A List specifying the clipping rectangle
- */
- private final List<Double> bbox;
-
- /**
- * Optional for Type 1: A transformation matrix
- */
- private final List<Double> matrix;
-
- /**
- * The background color. Since shading is opaque,
- * this is very rarely used.
- */
- private final List<Double> background;
-
- /**
- * 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.
- */
- private final List<Double> domain;
-
- /**
- * 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
- */
- private final List<Double> decode;
-
- /**
- * 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.background = null;
- this.bbox = null;
- this.antiAlias = false;
- this.coords = coords;
- this.domain = null;
- this.function = function;
- this.extend = null;
- this.matrix = null;
- this.decode = null;
- 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<Double> getBBox() {
- return bbox;
- }
-
- public List<Double> getMatrix() {
- return matrix;
- }
-
- public List<Double> getBackground() {
- return background;
- }
-
- public List<Double> getDomain() {
- return domain;
- }
-
- public List<Double> getDecode() {
- return decode;
- }
-
- 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, FunctionRenderer functionRenderer) {
- out.append("<<\n/ShadingType " + shadingType + "\n");
- if (colorSpace != null) {
- out.append("/ColorSpace /" + colorSpace.getName() + "\n");
- }
-
- if (background != null) {
- out.append("/Background ");
- outputDoubles(out, background);
- out.append("\n");
- }
-
- if (bbox != null) {
- out.append("/BBox");
- outputDoubles(out, bbox);
- out.append("\n");
- }
-
- if (antiAlias) {
- out.append("/AntiAlias " + antiAlias + "\n");
- }
-
- switch (shadingType) {
- // Function based shading
- case 1: outputShadingType1(out, functionRenderer); break;
- // Axial shading
- case 2:
- // Radial shading
- case 3: outputShadingType2or3(out, functionRenderer); break;
- // Free-form Gouraud-shaded triangle meshes
- case 4:
- // Coons patch meshes
- case 6:
- // Tensor product patch meshes
- case 7: outputShadingType4or6or7(out, functionRenderer); break;
- // Lattice Free form gouraud-shaded triangle mesh
- case 5: outputShadingType5(out, functionRenderer); break;
- default: throw new UnsupportedOperationException("Shading type " + shadingType);
- }
-
- out.append(">>");
- }
-
- private void outputDoubles(StringBuilder out, List<Double> doubles) {
- out.append("[ ");
- for (Double d : doubles) {
- out.append(PDFNumber.doubleOut(d));
- out.append(" ");
- }
- out.append("]");
- }
-
- private void outputShadingType1(StringBuilder out, Shading.FunctionRenderer functionRenderer) {
- if (domain != null) {
- out.append("/Domain ");
- outputDoubles(out, domain);
- out.append("\n");
- } else {
- out.append("/Domain [ 0 1 ] \n");
- }
-
- if (matrix != null) {
- out.append("/Matrix ");
- outputDoubles(out, matrix);
- out.append("\n");
- }
- outputFunction(out, functionRenderer);
- }
-
- private void outputShadingType2or3(StringBuilder out, Shading.FunctionRenderer functionRenderer) {
- if (coords != null) {
- out.append("/Coords ");
- outputDoubles(out, coords);
- out.append("\n");
- }
-
- if (domain != null) {
- out.append("/Domain ");
- outputDoubles(out, domain);
- out.append("\n");
- } else {
- out.append("/Domain [ 0 1 ] \n");
- }
-
- if (extend != null) {
- out.append("/Extend [");
- for (Boolean b : extend) {
- out.append(b);
- out.append(" ");
- }
- out.append("\n");
- } else {
- out.append("/Extend [ true true ] \n");
- }
-
- outputFunction(out, functionRenderer);
- }
-
- private void outputShadingType4or6or7(StringBuilder out, 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");
- }
-
- if (decode != null) {
- out.append("/Decode ");
- outputDoubles(out, decode);
- out.append("\n");
- }
-
- outputFunction(out, functionRenderer);
- }
-
- private void outputShadingType5(StringBuilder out, 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 (decode != null) {
- out.append("/Decode ");
- outputDoubles(out, decode);
- out.append("\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");
- }
- }
-}
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.GradientMaker;
-import org.apache.fop.render.shading.Pattern;
-import org.apache.fop.render.shading.Shading;
/**
* <p>PDF Graphics 2D.