Author: lehmi Date: Wed Feb 1 20:37:39 2012 New Revision: 1239309 URL: http://svn.apache.org/viewvc?rev=1239309&view=rev Log: PDFBOX-615, PDFBOX-1094: added the implementation of a radial shading
Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingPaint.java Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDShadingPatternResources.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDShadingPatternResources.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDShadingPatternResources.java?rev=1239309&r1=1239308&r2=1239309&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDShadingPatternResources.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDShadingPatternResources.java Wed Feb 1 20:37:39 2012 @@ -33,6 +33,8 @@ import org.apache.pdfbox.pdmodel.graphic import org.apache.pdfbox.pdmodel.graphics.shading.AxialShadingPaint; import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingResources; import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType2; +import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType3; +import org.apache.pdfbox.pdmodel.graphics.shading.RadialShadingPaint; import org.apache.pdfbox.util.Matrix; /** @@ -206,8 +208,10 @@ public class PDShadingPatternResources e case PDShadingResources.SHADING_TYPE2: paint = new AxialShadingPaint((PDShadingType2)getShading(), null, pageHeight); break; - case PDShadingResources.SHADING_TYPE1: case PDShadingResources.SHADING_TYPE3: + paint = new RadialShadingPaint((PDShadingType3)getShading(), null, pageHeight); + break; + case PDShadingResources.SHADING_TYPE1: case PDShadingResources.SHADING_TYPE4: case PDShadingResources.SHADING_TYPE5: case PDShadingResources.SHADING_TYPE6: Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java?rev=1239309&view=auto ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java (added) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java Wed Feb 1 20:37:39 2012 @@ -0,0 +1,325 @@ +/* + * 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.pdfbox.pdmodel.graphics.shading; + +import java.awt.PaintContext; +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.pdfbox.cos.COSArray; +import org.apache.pdfbox.cos.COSBoolean; +import org.apache.pdfbox.pdmodel.common.function.PDFunction; +import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; +import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB; +import org.apache.pdfbox.util.Matrix; + +/** + * This class represents the PaintContext of an radial shading. + * + * @author lehmi + * @version $Revision: $ + * + */ +public class RadialShadingContext implements PaintContext +{ + + private ColorModel colorModel; + private PDFunction function; + private ColorSpace shadingColorSpace; + + private float[] coords; + private float[] domain; + private boolean[] extend; + private double x1x0; + private double y1y0; + private double r1r0; + private double x1x0pow2; + private double y1y0pow2; + private double r0pow2; + + private float d1d0; + private double denom; + + /** + * Log instance. + */ + private static final Log LOG = LogFactory.getLog(AxialShadingContext.class); + + /** + * Constructor creates an instance to be used for fill operations. + * + * @param shadingType3 the shading type to be used + * @param colorModelValue the color model to be used + * @param xform transformation for user to device space + * @param ctm current transformation matrix + * @param pageHeight height of the current page + * + */ + public RadialShadingContext(PDShadingType3 shadingType3, ColorModel colorModelValue, + AffineTransform xform, Matrix ctm, int pageHeight) + { + coords = shadingType3.getCoords().toFloatArray(); + if (ctm != null) + { + // the shading is used in combination with the sh-operator + float[] coordsTemp = new float[coords.length]; + // transform the coords from shading to user space + ctm.createAffineTransform().transform(coords, 0, coordsTemp, 0, 1); + ctm.createAffineTransform().transform(coords, 3, coordsTemp, 3, 1); + // move the 0,0-reference + coordsTemp[1] = pageHeight - coordsTemp[1]; + coordsTemp[4] = pageHeight - coordsTemp[4]; + // transform the coords from user to device space + xform.transform(coordsTemp, 0, coords, 0, 1); + xform.transform(coordsTemp, 3, coords, 3, 1); + } + else + { + // the shading is used as pattern colorspace in combination + // with a fill-, stroke- or showText-operator + float translateY = (float)xform.getTranslateY(); + // move the 0,0-reference including the y-translation from user to device space + coords[1] = pageHeight + translateY - coords[1]; + coords[4] = pageHeight + translateY - coords[4]; + } + // colorSpace + try + { + PDColorSpace cs = shadingType3.getColorSpace(); + if (!(cs instanceof PDDeviceRGB)) + { + // we have to create an instance of the shading colorspace if it isn't RGB + shadingColorSpace = cs.getJavaColorSpace(); + } + } + catch (IOException exception) + { + LOG.error("error while creating colorSpace", exception); + } + // colorModel + if (colorModelValue != null) + { + colorModel = colorModelValue; + } + else + { + try + { + // TODO bpc != 8 ?? + colorModel = shadingType3.getColorSpace().createColorModel(8); + } + catch(IOException exception) + { + LOG.error("error while creating colorModel", exception); + } + } + // shading function + try + { + function = shadingType3.getFunction(); + } + catch(IOException exception) + { + LOG.error("error while creating a function", exception); + } + // domain values + if (shadingType3.getDomain() != null) + { + domain = shadingType3.getDomain().toFloatArray(); + } + else + { + // set default values + domain = new float[]{0,1}; + } + // extend values + COSArray extendValues = shadingType3.getExtend(); + if (shadingType3.getExtend() != null) + { + extend = new boolean[2]; + extend[0] = ((COSBoolean)extendValues.get(0)).getValue(); + extend[1] = ((COSBoolean)extendValues.get(1)).getValue(); + } + else + { + // set default values + extend = new boolean[]{false,false}; + } + // calculate some constants to be used in getRaster + x1x0 = coords[3] - coords[0]; + y1y0 = coords[4] - coords[1]; + r1r0 = coords[5] - coords[2]; + x1x0pow2 = Math.pow(x1x0,2); + y1y0pow2 = Math.pow(y1y0,2); + r0pow2 = Math.pow(coords[2],2); + denom = x1x0pow2 + y1y0pow2 - Math.pow(r1r0, 2); + d1d0 = domain[1]-domain[0]; + // TODO take a possible Background value into account + + } + /** + * {@inheritDoc} + */ + public void dispose() + { + colorModel = null; + function = null; + } + + /** + * {@inheritDoc} + */ + public ColorModel getColorModel() + { + return colorModel; + } + + /** + * {@inheritDoc} + */ + public Raster getRaster(int x, int y, int w, int h) + { + // create writable raster + WritableRaster raster = getColorModel().createCompatibleWritableRaster(w, h); + float[] input = new float[1]; + float inputValue; + int[] data = new int[w * h * 3]; + for (int j = 0; j < h; j++) + { + for (int i = 0; i < w; i++) + { + float[] inputValues = calculateInputValues(x + i, y + j); + // choose 1 of the 2 values + if (inputValues[0] >= domain[0] && inputValues[0] <= domain[1]) + { + // both values are in the domain -> choose the larger one + if(inputValues[1] >= domain[0] && inputValues[1] <= domain[1]) + { + inputValue = Math.max(inputValues[0], inputValues[1]); + } + // first value is in the domain, the second not -> choose first value + else + { + inputValue = inputValues[0]; + } + } + else + { + // first value is not in the domain, but the second -> choose second value + if(inputValues[1] >= domain[0] && inputValues[1] <= domain[1]) + { + inputValue = inputValues[1]; + } + // TODO + // both are not in the domain -> choose the first as I don't know it better + else + { + inputValue = inputValues[0]; + } + } + // input value is out of range + if (inputValue < domain[0]) + { + // the shading has to be extended if extend[0] == true + if (extend[0]) + { + inputValue = domain[0]; + } + else + { + continue; + } + } + // input value is out of range + else if (inputValue > domain[1]) + { + // the shading has to be extended if extend[1] == true + if (extend[1]) + { + inputValue = domain[1]; + } + else + { + continue; + } + } + input[0] = (float)(domain[0] + (d1d0*inputValue)); + float[] values = null; + try + { + values = function.eval(input); + } + catch (IOException exception) + { + LOG.error("error while processing a function", exception); + } + int index = (j * w + i) * 3; + // convert color values from shading colorspace to RGB + if (shadingColorSpace != null) + { + values = shadingColorSpace.toRGB(values); + } + data[index] = (int)(values[0]*255); + data[index+1] = (int)(values[1]*255); + data[index+2] = (int)(values[2]*255); + } + } + raster.setPixels(0, 0, w, h, data); + return raster; + } + + private float[] calculateInputValues(int x, int y) + { + + /** + * According to Adobes Technical Note #5600 we have to do the following + * + * x0, y0, r0 defines the start circle + * x1, y1, r1 defines the end circle + * + * The parametric equations for the center and radius of the gradient fill + * circle moving between the start circle and the end circle as a function + * of s are as follows: + * + * xc(s) = x0 + s * (x1 - x0) + * yc(s) = y0 + s * (y1 - y0) + * r(s) = r0 + s * (r1 - r0) + * + * Given a geometric coordinate position (x, y) in or along the gradient fill, + * the corresponding value of s can be determined by solving the quadratic + * constraint equation: + * + * [x - xc(s)]2 + [y - yc(s)]2 = [r(s)]2 + * + * The following code calculates the 2 possible values of s + */ + + float[] values = new float[2]; + double p = (-0.25)*((x - coords[0])*x1x0 + (y - coords[1])*y1y0 - r1r0) / denom; + double q = (Math.pow(x - coords[0],2) + Math.pow(y - coords[1],2) - r0pow2) / denom; + double root = Math.sqrt(Math.pow(p , 2) - q); + values[0] = (float)((-1)*p + root); + values[1] = (float)((-1)*p - root); + return values; + } +} Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingPaint.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingPaint.java?rev=1239309&view=auto ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingPaint.java (added) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingPaint.java Wed Feb 1 20:37:39 2012 @@ -0,0 +1,73 @@ +/* + * 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.pdfbox.pdmodel.graphics.shading; + +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; + +import org.apache.pdfbox.util.Matrix; + +/** + * This represents the Paint of an radial shading. + * + * @author lehmi + * @version $Revision: $ + * + */ +public class RadialShadingPaint implements Paint +{ + + private PDShadingType3 shading; + private Matrix currentTransformationMatrix; + private int pageHeight; + + /** + * Constructor. + * + * @param shadingType3 the shading resources + * @param ctm current transformation matrix + * @param pageSizeValue size of the current page + */ + public RadialShadingPaint(PDShadingType3 shadingType3, Matrix ctm, int pageHeightValue) + { + shading = shadingType3; + currentTransformationMatrix = ctm; + pageHeight = pageHeightValue; + } + /** + * {@inheritDoc} + */ + public int getTransparency() + { + return 0; + } + + /** + * {@inheritDoc} + */ + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) + { + return new RadialShadingContext(shading, cm, xform, currentTransformationMatrix, pageHeight); + } + +} Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java?rev=1239309&r1=1239308&r2=1239309&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java Wed Feb 1 20:37:39 2012 @@ -167,8 +167,11 @@ public class PDJpeg extends PDXObjectIma { for(int x = 0; x < alphaWidth; x++) { - Color color = new Color(alpha.getRGB(x, y)); - if(color.getRed() != 0 && color.getGreen() != 0 && color.getBlue() != 0) + int colorValues = alpha.getRGB(x, y); + // TODO check condition PDFBOX-626 + if( ((colorValues >> 16) & 0xFF) != 0 + && ((colorValues >> 8) & 0xFF) != 0 + && ((colorValues >> 0) & 0xFF) != 0 ) { alpha.setRGB(x, y, whiteRGB); }