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