/* * $Id: PDFShader.java,v 1.4 2010-05-23 22:07:06 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.pattern; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.util.Map; import com.sun.pdfview.PDFFile; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFPaint; import com.sun.pdfview.PDFParseException; import com.sun.pdfview.colorspace.PDFColorSpace; /** * <p>A PDFShader fills a given region with a shading, such as a gradient.</p> * * <p> * Shading Dictionaries (section 4.6)<br> * A shading dictionary specifies details of a particular gradient fill, * including the type of shading to be used, the geometry of the area to * be shaded, and the geometry of the gradient fill. Various shading types * are available, depending on the value of the dictionary’s ShadingType entry: * * <li>Function-based shadings (type 1) define the color of every point in the * domain using a mathematical function (not necessarily smooth or continuous).</li> * * <li>Axial shadings (type 2) define a color blend along a line between two * points, optionally extended beyond the boundary points by continuing * the boundary colors.</li> * * <li>Radial shadings (type 3) define a blend between two circles, * optionally extended beyond the boundary circles by continuing the * boundary colors. This type of shading is commonly used to represent * three-dimensional spheres and cones.</li> * * <li>Free-form Gouraud-shaded triangle meshes (type 4) define a * common construct used by many three-dimensional applications to * represent complex colored and shaded shapes. Vertices are specified * in free-form geometry.</li> * * <li>Lattice-form Gouraud-shaded triangle meshes (type 5) are based on * the same geometrical construct as type 4 but with vertices specified * as a pseudorectangular lattice.</li> * * <li>Coons patch meshes (type 6) construct a shading from one or more * color patches, each bounded by four cubic Bézier curves.</li> * * <li>Tensor-product patch meshes (type 7) are similar to type 6 but * with additional control points in each patch, affording greater * control over color mapping.</li> * * Table 4.28 shows the entries that all shading dictionaries share * in common; entries specific to particular shading types are * described in the relevant sections below.</p> */ public abstract class PDFShader { public final static int FUNCTION_SHADING = 1; public final static int AXIAL_SHADING = 2; public final static int RADIAL_SHADING = 3; public final static int FREE_FORM_SHADING = 4; public final static int LATTICE_SHADING = 5; public final static int COONS_PATCH_MESH_SHADING = 6; public final static int TENSOR_PRODUCTS_MESH_SHADING = 7; /** the type of the shading (1 through 7)*/ private int type; /** the colorspace */ private PDFColorSpace colorSpace; /** the background color */ private PDFPaint background; /** the bounding box of the pattern */ private Rectangle2D bbox; /** Creates a new instance of PDFShader */ protected PDFShader(int type) { this.type = type; } /** * Parse a pdf shader into a shader object */ public static PDFShader getShader(PDFObject shaderObj, Map resources) throws IOException { // first see if the shader is already cached PDFShader shader = (PDFShader) shaderObj.getCache(); if (shader != null) { return shader; } // read the type (required) PDFObject typeObj = shaderObj.getDictRef("ShadingType"); if (typeObj == null) { throw new PDFParseException("No shader type defined!"); } int type = typeObj.getIntValue(); // create the shader switch (type) { case AXIAL_SHADING: shader = new ShaderType2(); break; case FUNCTION_SHADING: case RADIAL_SHADING: case FREE_FORM_SHADING: case LATTICE_SHADING: case COONS_PATCH_MESH_SHADING: case TENSOR_PRODUCTS_MESH_SHADING: default: throw new PDFParseException("Unsupported shader type: " + type); } // read the color space (required) PDFObject csObj = shaderObj.getDictRef("ColorSpace"); if (csObj == null) { throw new PDFParseException("No colorspace defined!"); } PDFColorSpace cs = PDFColorSpace.getColorSpace(csObj, resources); shader.setColorSpace(cs); // read the background color (optional) PDFObject bgObj = shaderObj.getDictRef("Background"); if (bgObj != null) { PDFObject[] bgObjs = bgObj.getArray(); float[] bgArray = new float[bgObjs.length]; for (int i = 0; i < bgArray.length; i++) { bgArray[i] = bgObjs[i].getFloatValue(); } PDFPaint paint = cs.getPaint(bgArray); shader.setBackground(paint); } // read the bounding box (optional) PDFObject bboxObj = shaderObj.getDictRef("BBox"); if (bboxObj != null) { shader.setBBox(PDFFile.parseNormalisedRectangle(bboxObj)); } // parse the shader-specific attributes shader.parse(shaderObj); // set the cache shaderObj.setCache(shader); return shader; } /** * Get the type */ public int getType() { return type; } /** * Get the color space */ public PDFColorSpace getColorSpace() { return colorSpace; } /** * Set the color space */ protected void setColorSpace(PDFColorSpace colorSpace) { this.colorSpace = colorSpace; } /** * Get the background color */ public PDFPaint getBackground() { return background; } /** * Set the background color */ protected void setBackground(PDFPaint background) { this.background = background; } /** * Get the bounding box */ public Rectangle2D getBBox() { return bbox; } /** * Set the bounding box */ protected void setBBox(Rectangle2D bbox) { this.bbox = bbox; } /** * Parse the shader-specific data */ public abstract void parse(PDFObject shareObj) throws IOException; /** * Returns paint that represents the selected shader */ public abstract PDFPaint getPaint(); }