/* * Copyright 2006-2017 ICEsoft Technologies Canada Corp. * * Licensed 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.icepdf.core.pobjects.graphics; import org.icepdf.core.pobjects.Dictionary; import org.icepdf.core.pobjects.Name; import org.icepdf.core.pobjects.Reference; import org.icepdf.core.pobjects.Stream; import org.icepdf.core.pobjects.functions.Function; import org.icepdf.core.util.Library; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.util.HashMap; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * <p>Shading Pattern is a Base class for a all shading Types. It contains * all common dictionary entries and acts a factory examing the patternType * entry and returning a know Pattern Type implementation. Currently the * factory only support Shading Type2 and Type3 patterns, as thses are the only * types we have concrete examples of. </p> * * @author ICEsoft Technologies Inc. * @since 3.0 */ public abstract class ShadingPattern extends Dictionary implements Pattern { private static final Logger logger = Logger.getLogger(ShadingPattern.class.toString()); public static final Name PATTERN_TYPE_KEY = new Name("PatternType"); public static final Name EXTGSTATE_KEY = new Name("ExtGState"); public static final Name MATRIX_KEY = new Name("Matrix"); public static final Name SHADING_KEY = new Name("Shading"); public static final Name SHADING_TYPE_KEY = new Name("ShadingType"); public static final Name BBOX_KEY = new Name("BBox"); public static final Name COLORSPACE_KEY = new Name("ColorSpace"); public static final Name BACKGROUND_KEY = new Name("Background"); public static final Name ANTIALIAS_KEY = new Name("AntiAlias"); public static final Name DOMAIN_KEY = new Name("Domain"); public static final Name COORDS_KEY = new Name("Coords"); public static final Name EXTEND_KEY = new Name("Extend"); public static final Name FUNCTION_KEY = new Name("Function"); // pattern types by number. public static final int SHADING_PATTERN_TYPE_1 = 1; public static final int SHADING_PATTERN_TYPE_2 = 2; public static final int SHADING_PATTERN_TYPE_3 = 3; public static final int SHADING_PATTERN_TYPE_4 = 4; public static final int SHADING_PATTERN_TYPE_5 = 5; public static final int SHADING_PATTERN_TYPE_6 = 6; public static final int SHADING_PATTERN_TYPE_7 = 7; // type of PObject, should always be "Pattern" protected Name type; // A code identifying the type of pattern that this dictionary describes protected int patternType; // shadingDictionary dictionary, entries vary depending on shading type. protected HashMap shadingDictionary; // shadingDictionary type 1-7, most common, 2,3,6.. protected int shadingType; // start of common shading dictionary entries. // A 1-in, n-out function or an array of n 1-in, 1-out functions (where n // is the number of colour components in the shadingDictionary dictionary's colour // space). The function(s) are called with values of the parametric variables // t in the domain defined by the domain entry. Each function's domain must // be a superset of that of the shadingDictionary dictionary. If the return value // is out of range it is adjusted to the nearest value. protected Function[] function; // An array of four numbers in the pattern coordinate system giving the // coordinates of the left, bottom, right, and top edges, respectively, of // the pattern cell's bounding box. These boundaries are used to clip the // pattern cell. protected Rectangle2D bBox; // any device, cie-based or special color except Pattern, required. protected PColorSpace colorSpace; // background colors (optional), not applicable on 'sh' protected List background; // turn on/off antiAliasing. (optional) protected boolean antiAlias; // end of common shading dictionary entries. // An array of six numbers specifying the pattern matrix. The default value // is the identity matrix [1 0 0 1 0 0]. protected AffineTransform matrix; // graphics state for shading pattern protected ExtGState extGState; // initiated flag protected boolean inited; public ShadingPattern(Library library, HashMap entries) { super(library, entries); type = library.getName(entries, TYPE_KEY); patternType = library.getInt(entries, PATTERN_TYPE_KEY); Object attribute = library.getObject(entries, EXTGSTATE_KEY); if (attribute instanceof HashMap) { extGState = new ExtGState(library, (HashMap) attribute); } else if (attribute instanceof Reference) { extGState = new ExtGState(library, (HashMap) library.getObject( (Reference) attribute)); } List v = (List) library.getObject(entries, MATRIX_KEY); if (v != null) { matrix = getAffineTransform(v); } else { // default is identity matrix matrix = new AffineTransform(); } } /** * Factory method to resolve the shading dictionaries ShadingType 1 - 3. * * @param library library for document * @param attribute dictionary for potential shading object. * @return returns a Shading object based ont he shadingType criteria. * if the proper constructor cannot be found then null is returned. */ public static ShadingPattern getShadingPattern(Library library, HashMap attribute) { // factory type approach, find shading entries and get type Object shading = library.getObject(attribute, SHADING_KEY); // setup 1-3 as they are dictionary based. if (shading != null && shading instanceof HashMap) { return shadingFactory(library, attribute, (HashMap) shading); } else if (shading != null && shading instanceof Stream) { return getShadingPattern(library, attribute, (Stream) shading); } return null; } /** * Factory method to resolve the shadingDictionary dictionaries ShadingType 4- 6 which are Stream based. * * @param library library for document * @param attribute dictionary for potential shadingDictionary object. * @return returns a ShadingPattern object based ont he shadingType criteria. * if the proper constructor cannot be found then null is returned. */ public static ShadingPattern getShadingPattern(Library library, HashMap attribute, Stream shadingStream) { int shadingType = library.getInt(shadingStream.getEntries(), SHADING_TYPE_KEY); switch (shadingType) { case SHADING_PATTERN_TYPE_4: return new ShadingType4Pattern(library, attribute, shadingStream); case SHADING_PATTERN_TYPE_5: return new ShadingType5Pattern(library, attribute, shadingStream); case SHADING_PATTERN_TYPE_6: return new ShadingType6Pattern(library, attribute, shadingStream); case SHADING_PATTERN_TYPE_7: return new ShadingType7Pattern(library, attribute, shadingStream); } return null; } /** * Factory call create a support pattern type. Currently only types 2 and * 3 are supported. * * @param library document library * @param entries entries in the the currently dictionary. * @param shading shading dictionary. * @return shading pattern */ public static ShadingPattern getShadingPattern(Library library, HashMap entries, HashMap shading) { // resolve shading pattern if (entries != null) { ShadingPattern shadingPattern = shadingFactory(library, shading, shading); // assign shading dictionary for sh instances that only define // the shading dictionary and not the full pattern dictionary. shadingPattern.setShadingDictionary(shading); return shadingPattern; } return null; } // create a new shading pattern. private static ShadingPattern shadingFactory(Library library, HashMap attribute, HashMap patternDictionary) { int shadingType = library.getInt(patternDictionary, SHADING_TYPE_KEY); if (shadingType == ShadingPattern.SHADING_PATTERN_TYPE_2) { return new ShadingType2Pattern(library, attribute); } else if (shadingType == ShadingPattern.SHADING_PATTERN_TYPE_3) { return new ShadingType3Pattern(library, attribute); } else if (shadingType == ShadingPattern.SHADING_PATTERN_TYPE_1) { return new ShadingType1Pattern(library, attribute); } else { if (logger.isLoggable(Level.FINE)) { logger.fine("Shading pattern of Type " + shadingType + " are not currently supported"); } } return null; } /** * Utility method for parsing a vector of affinetranform values to an * affine transform. * * @param v vector containing affine transform values. * @return affine transform based on v */ private static AffineTransform getAffineTransform(List v) { float f[] = new float[6]; for (int i = 0; i < 6; i++) { f[i] = ((Number) v.get(i)).floatValue(); } return new AffineTransform(f); } /** * Applies the function data to the values array. * @param values values to feed functions. * @return new values after function execution. */ protected float[] calculateValues(float[] values) { float[] output; int length = function.length; if (length == 1) { output = function[0].calculate(values); } else { // vector of function for each colour component, 1 in 1 out. output = new float[length]; for (int i = 0; i < length; i++) { output[i] = function[i].calculate(values)[0]; } } return output; } /** * Gets the Paint object need to fill a shape etc. Each individual * implementation will return a particular paint type. * * @return Paint type for fill. */ public abstract Paint getPaint() throws InterruptedException; /** * Initialized shading dictionary attributes. Discrepancies between sh and * scn tokens cause us to handle initialization at a later time. */ public abstract void init(GraphicsState graphicsState); public void setParentGraphicState(GraphicsState graphicsState) { // nothing to be done for shading. } public void setMatrix(AffineTransform matrix) { this.matrix = matrix; } public int getPatternType() { return patternType; } public Rectangle2D getBBox() { return bBox; } public AffineTransform getMatrix() { return matrix; } public int getShadingType() { return shadingType; } public void setShadingDictionary(HashMap shadingDictionary) { this.shadingDictionary = shadingDictionary; } public Name getType() { return type; } public PColorSpace getColorSpace() { return colorSpace; } public List getBackground() { return background; } public boolean isAntiAlias() { return antiAlias; } public ExtGState getExtGState() { return extGState; } public boolean isInited() { return inited; } public String toString() { return "Shading Pattern: \n" + " type: pattern " + "\n patternType: shadingDictionary" + "\n matrix: " + matrix + "\n extGState: " + extGState + "\n shading dictionary: " + shadingDictionary + "\n shadingType: " + shadingType + "\n colourSpace: " + colorSpace + "\n background: " + background + "\n bbox: " + bBox + "\n antiAlias: " + antiAlias; } }