/* * 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.functions.Function; import org.icepdf.core.pobjects.graphics.batik.ext.awt.MultipleGradientPaint; import org.icepdf.core.pobjects.graphics.batik.ext.awt.RadialGradientPaint; import org.icepdf.core.util.Library; import java.awt.*; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.logging.Logger; /** * <p>Type 3 (radial) shading define a colour blend that varies between two * circles. Shading of this type are commonly used to depict three-dimensional * spheres and cones.</p> * * @author ICEsoft Technologies Inc. * @since 3.0 */ public class ShadingType3Pattern extends ShadingPattern { private static final Logger logger = Logger.getLogger(ShadingType3Pattern.class.toString()); // An array of two numbers [t0, t1] specifying the limiting values of a // parametric variable t. The variable is considered to vary linearly between // these two values as the colour gradient varies between the starting and // ending points of the axis. The variable t becomes the argument to the // colour function(s). Default [0,1]. protected List<Number> domain; // An array of six numbers [x0, y0, r0, x1, y1, r1] specifying the centers // and radii of the starting and ending circles. Expressed in the shading // target coordinate space. The radii r0 and r1 must both be greater than // or equal to 0. If both are zero nothing is painted. protected List coords; // An array of two Boolean values specifying whether to extend the shading // beyond the starting and ending points of the axis, Default [false, false]. protected List<Boolean> extend; // radial gradient paint that is used by java for paint. protected RadialGradientPaint radialGradientPaint; public ShadingType3Pattern(Library library, HashMap entries) { super(library, entries); } @SuppressWarnings("unchecked") public synchronized void init(GraphicsState graphicsState) { if (inited) { return; } // shadingDictionary dictionary if (shadingDictionary == null) { shadingDictionary = library.getDictionary(entries, SHADING_KEY); } shadingType = library.getInt(shadingDictionary, SHADING_TYPE_KEY); bBox = library.getRectangle(shadingDictionary, BBOX_KEY); colorSpace = PColorSpace.getColorSpace(library, library.getObject(shadingDictionary, COLORSPACE_KEY)); if (library.getObject(shadingDictionary, BACKGROUND_KEY) != null && library.getObject(shadingDictionary, BACKGROUND_KEY) instanceof List) { background = (List) library.getObject(shadingDictionary, BACKGROUND_KEY); } antiAlias = library.getBoolean(shadingDictionary, ANTIALIAS_KEY); // get type 2 specific data. Object tmp = library.getObject(shadingDictionary, DOMAIN_KEY); if (tmp instanceof List) { domain = (List<Number>) tmp; } else { domain = new ArrayList<Number>(2); domain.add(0.0f); domain.add(1.0f); } tmp = library.getObject(shadingDictionary, COORDS_KEY); if (tmp instanceof List) { coords = (List) tmp; } tmp = library.getObject(shadingDictionary, EXTEND_KEY); if (tmp instanceof List) { extend = (List) tmp; } else { extend = new ArrayList<Boolean>(2); extend.add(false); extend.add(false); } tmp = library.getObject(shadingDictionary, FUNCTION_KEY); if (tmp != null) { if (!(tmp instanceof List)) { function = new Function[]{Function.getFunction(library, tmp)}; } else { List functionTemp = (List) tmp; function = new Function[functionTemp.size()]; for (int i = 0; i < functionTemp.size(); i++) { function[i] = Function.getFunction(library, functionTemp.get(i)); } } } float t0 = domain.get(0).floatValue(); float t1 = domain.get(1).floatValue(); float s[] = new float[]{0.0f, 0.25f, 0.5f, 0.75f, 1.0f}; Point2D.Float center = new Point2D.Float( ((Number) coords.get(0)).floatValue(), ((Number) coords.get(1)).floatValue()); Point2D.Float focus = new Point2D.Float( ((Number) coords.get(3)).floatValue(), ((Number) coords.get(4)).floatValue()); float radius = ((Number) coords.get(2)).floatValue(); float radius2 = ((Number) coords.get(5)).floatValue(); // approximation, as we don't full support radial point via the paint // class. if (radius2 > radius) { radius = radius2; } try { // get the number off components in the colour Color color1 = calculateColour(colorSpace, s[0], t0, t1); Color color2 = calculateColour(colorSpace, s[1], t0, t1); Color color3 = calculateColour(colorSpace, s[2], t0, t1); Color color4 = calculateColour(colorSpace, s[3], t0, t1); Color color5 = calculateColour(colorSpace, s[4], t0, t1); if (color1 == null || color2 == null) { return; } // Construct a LinearGradientPaint object to be use by java2D Color[] colors = {color1, color2, color3, color4, color5}; radialGradientPaint = new RadialGradientPaint( center, radius, focus, s, colors, MultipleGradientPaint.NO_CYCLE, MultipleGradientPaint.LINEAR_RGB, matrix); // get type 3 specific data. inited = true; } catch (Exception e) { logger.finer("Failed ot initialize gradient paint type 3."); } } private Color calculateColour(PColorSpace colorSpace, float s, float t0, float t1) { // find colour at point 1 float t = parametrixValue(s, t0, t1, extend); // find colour at point float[] input = new float[1]; input[0] = t; if (function != null) { float[] output = calculateValues(input); if (output != null) { if (!(colorSpace instanceof DeviceN)) { output = PColorSpace.reverse(output); } return colorSpace.getColor(output); } else { return null; } } else { logger.fine("Error processing Shading Type 3 Pattern."); return null; } } /** * Parametric variable t calculation as defined in Section 4.6, Type 2 * (axial) shadings. * * @param linearMapping linear mapping of some point x' * @param t0 domain of axial shading, limit 1 * @param t1 domain of axial shading, limit 2 * @param extended 2 element vector, indicating line extension along domain * @return parametric value. */ private float parametrixValue(float linearMapping, float t0, float t1, List extended) { return t0 + ((t1 - t0) * linearMapping); } public Paint getPaint() throws InterruptedException { init(); return radialGradientPaint; } public String toSting() { return super.toString() + "\n domain: " + domain + "\n coords: " + coords + "\n extend: " + extend + "\n function: " + function; } }