"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java" between
pdfbox-2.0.23-src.zip and pdfbox-2.0.24-src.zip

About: Apache PDFBox is a Java PDF library tool that allows creation of new PDF documents, manipulation of existing documents and the ability to extract content from documents.

PageDrawer.java  (pdfbox-2.0.23-src):PageDrawer.java  (pdfbox-2.0.24-src)
skipping to change at line 31 skipping to change at line 31
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration; import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice; import java.awt.GraphicsDevice;
import java.awt.Image; import java.awt.Image;
import java.awt.Paint; import java.awt.Paint;
import java.awt.Point; import java.awt.Point;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.RenderingHints; import java.awt.RenderingHints;
import java.awt.Shape; import java.awt.Shape;
import java.awt.Stroke;
import java.awt.TexturePaint; import java.awt.TexturePaint;
import java.awt.Transparency; import java.awt.Transparency;
import java.awt.color.ColorSpace; import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.geom.Area; import java.awt.geom.Area;
import java.awt.geom.GeneralPath; import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator; import java.awt.geom.PathIterator;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.awt.image.ColorModel; import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel; import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer; import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte; import java.awt.image.DataBufferByte;
import java.awt.image.Raster; import java.awt.image.Raster;
import java.awt.image.WritableRaster; import java.awt.image.WritableRaster;
skipping to change at line 386 skipping to change at line 388
{ {
LOG.error("shadingPattern is null, will be filled with trans parency"); LOG.error("shadingPattern is null, will be filled with trans parency");
return new Color(0,0,0,0); return new Color(0,0,0,0);
} }
return shading.toPaint(Matrix.concatenate(getInitialMatrix(), return shading.toPaint(Matrix.concatenate(getInitialMatrix(),
shadingPattern.getMatr ix())); shadingPattern.getMatr ix()));
} }
} }
} }
// sets the clipping path using caching for performance, we track lastClip m /**
anually because * Sets the clipping path using caching for performance. We track lastClip m
// Graphics2D#getClip() returns a new object instead of the same one passed anually because
to setClip * {@link Graphics2D#getClip()} returns a new object instead of the same one
private void setClip() passed to
* {@link Graphics2D#setClip(java.awt.Shape) setClip()}. You may need to cal
l this if you
* override {@link #showGlyph(Matrix, PDFont, int, Vector) showGlyph()}. See
* <a href="https://issues.apache.org/jira/browse/PDFBOX-5093">PDFBOX-5093</
a> for more.
*/
protected final void setClip()
{ {
Area clippingPath = getGraphicsState().getCurrentClippingPath(); Area clippingPath = getGraphicsState().getCurrentClippingPath();
if (clippingPath != lastClip) if (clippingPath != lastClip)
{ {
if (clippingPath.getPathIterator(null).isDone()) if (clippingPath.getPathIterator(null).isDone())
{ {
// PDFBOX-4821: avoid bug with java printing that empty clipping path is ignored by // PDFBOX-4821: avoid bug with java printing that empty clipping path is ignored by
// replacing with empty rectangle, works because this is not an empty path // replacing with empty rectangle, works because this is not an empty path
graphics.setClip(new Rectangle()); graphics.setClip(new Rectangle());
} }
skipping to change at line 447 skipping to change at line 454
private void endTextClip() private void endTextClip()
{ {
PDGraphicsState state = getGraphicsState(); PDGraphicsState state = getGraphicsState();
RenderingMode renderingMode = state.getTextState().getRenderingMode(); RenderingMode renderingMode = state.getTextState().getRenderingMode();
// apply the buffered clip as one area // apply the buffered clip as one area
if (renderingMode.isClip() && !textClippings.isEmpty()) if (renderingMode.isClip() && !textClippings.isEmpty())
{ {
// PDFBOX-4150: this is much faster than using textClippingArea.add( new Area(glyph)) // PDFBOX-4150: this is much faster than using textClippingArea.add( new Area(glyph))
// https://stackoverflow.com/questions/21519007/fast-union-of-shapes -in-java // https://stackoverflow.com/questions/21519007/fast-union-of-shapes -in-java
GeneralPath path = new GeneralPath(); GeneralPath path = new GeneralPath(Path2D.WIND_NON_ZERO, textClippin gs.size());
for (Shape shape : textClippings) for (Shape shape : textClippings)
{ {
path.append(shape, false); path.append(shape, false);
} }
state.intersectClippingPath(path); state.intersectClippingPath(path);
textClippings = new ArrayList<Shape>(); textClippings = new ArrayList<Shape>();
// PDFBOX-3681: lastClip needs to be reset, because after intersecti on it is still the same // PDFBOX-3681: lastClip needs to be reset, because after intersecti on it is still the same
// object, thus setClip() would believe that it is cached. // object, thus setClip() would believe that it is cached.
lastClip = null; lastClip = null;
skipping to change at line 641 skipping to change at line 648
private Paint applySoftMaskToPaint(Paint parentPaint, PDSoftMask softMask) t hrows IOException private Paint applySoftMaskToPaint(Paint parentPaint, PDSoftMask softMask) t hrows IOException
{ {
if (softMask == null || softMask.getGroup() == null) if (softMask == null || softMask.getGroup() == null)
{ {
return parentPaint; return parentPaint;
} }
PDColor backdropColor = null; PDColor backdropColor = null;
if (COSName.LUMINOSITY.equals(softMask.getSubType())) if (COSName.LUMINOSITY.equals(softMask.getSubType()))
{ {
COSArray backdropColorArray = softMask.getBackdropColor(); COSArray backdropColorArray = softMask.getBackdropColor();
PDTransparencyGroup form = softMask.getGroup(); if (backdropColorArray != null)
PDColorSpace colorSpace = form.getGroup().getColorSpace(form.getReso
urces());
if (colorSpace != null && backdropColorArray != null)
{ {
backdropColor = new PDColor(backdropColorArray, colorSpace); PDTransparencyGroup form = softMask.getGroup();
PDColorSpace colorSpace = form.getGroup().getColorSpace(form.get
Resources());
if (colorSpace != null)
{
backdropColor = new PDColor(backdropColorArray, colorSpace);
}
} }
} }
TransparencyGroup transparencyGroup = new TransparencyGroup(softMask.get Group(), true, TransparencyGroup transparencyGroup = new TransparencyGroup(softMask.get Group(), true,
softMask.getInitialTransformationMatrix(), backdropColor); softMask.getInitialTransformationMatrix(), backdropColor);
BufferedImage image = transparencyGroup.getImage(); BufferedImage image = transparencyGroup.getImage();
if (image == null) if (image == null)
{ {
// Adobe Reader ignores empty softmasks instead of using bc color // Adobe Reader ignores empty softmasks instead of using bc color
// sample file: PDFJS-6967_reduced_outside_softmask.pdf // sample file: PDFJS-6967_reduced_outside_softmask.pdf
return parentPaint; return parentPaint;
skipping to change at line 725 skipping to change at line 735
} }
// returns the stroking AWT Paint // returns the stroking AWT Paint
private Paint getStrokingPaint() throws IOException private Paint getStrokingPaint() throws IOException
{ {
return applySoftMaskToPaint( return applySoftMaskToPaint(
getPaint(getGraphicsState().getStrokingColor()), getPaint(getGraphicsState().getStrokingColor()),
getGraphicsState().getSoftMask()); getGraphicsState().getSoftMask());
} }
// returns the non-stroking AWT Paint /**
private Paint getNonStrokingPaint() throws IOException * Returns the non-stroking AWT Paint. You may need to call this if you over
ride
* {@link #showGlyph(Matrix, PDFont, int, Vector) showGlyph()}. See
* <a href="https://issues.apache.org/jira/browse/PDFBOX-5093">PDFBOX-5093</
a> for more.
*
* @return The non-stroking AWT Paint.
* @throws IOException
*/
protected final Paint getNonStrokingPaint() throws IOException
{ {
return applySoftMaskToPaint( return applySoftMaskToPaint(
getPaint(getGraphicsState().getNonStrokingColor()), getPaint(getGraphicsState().getNonStrokingColor()),
getGraphicsState().getSoftMask()); getGraphicsState().getSoftMask());
} }
// create a new stroke based on the current CTM and the current stroke // create a new stroke based on the current CTM and the current stroke
private BasicStroke getStroke() private Stroke getStroke()
{ {
PDGraphicsState state = getGraphicsState(); PDGraphicsState state = getGraphicsState();
// apply the CTM // apply the CTM
float lineWidth = transformWidth(state.getLineWidth()); float lineWidth = transformWidth(state.getLineWidth());
// minimum line width as used by Adobe Reader // minimum line width as used by Adobe Reader
if (lineWidth < 0.25) if (lineWidth < 0.25)
{ {
lineWidth = 0.25f; lineWidth = 0.25f;
} }
PDLineDashPattern dashPattern = state.getLineDashPattern(); PDLineDashPattern dashPattern = state.getLineDashPattern();
float phaseStart = dashPattern.getPhase(); // PDFBOX-5168: show an all-zero dash array line invisible like Adobe do
float[] dashArray = getDashArray(dashPattern); es
phaseStart = transformWidth(phaseStart); // must do it here because getDashArray() sets minimum width because of
JVM bugs
// empty dash array is illegal float[] dashArray = dashPattern.getDashArray();
// avoid also infinite and NaN values (PDFBOX-3360) if (isAllZeroDash(dashArray))
if (dashArray.length == 0 || Float.isInfinite(phaseStart) || Float.isNaN
(phaseStart))
{
dashArray = null;
}
else
{ {
for (int i = 0; i < dashArray.length; ++i) return new Stroke()
{ {
if (Float.isInfinite(dashArray[i]) || Float.isNaN(dashArray[i])) @Override
public Shape createStrokedShape(Shape p)
{ {
dashArray = null; return new Area();
break;
} }
} };
} }
float phaseStart = dashPattern.getPhase();
dashArray = getDashArray(dashPattern);
phaseStart = transformWidth(phaseStart);
int lineCap = Math.min(2, Math.max(0, state.getLineCap())); int lineCap = Math.min(2, Math.max(0, state.getLineCap()));
int lineJoin = Math.min(2, Math.max(0, state.getLineJoin())); int lineJoin = Math.min(2, Math.max(0, state.getLineJoin()));
float miterLimit = state.getMiterLimit(); float miterLimit = state.getMiterLimit();
if (miterLimit < 1) if (miterLimit < 1)
{ {
LOG.warn("Miter limit must be >= 1, value " + miterLimit + " is igno red"); LOG.warn("Miter limit must be >= 1, value " + miterLimit + " is igno red");
miterLimit = 10; miterLimit = 10;
} }
return new BasicStroke(lineWidth, lineCap, lineJoin, return new BasicStroke(lineWidth, lineCap, lineJoin,
miterLimit, dashArray, phaseStart); miterLimit, dashArray, phaseStart);
} }
private boolean isAllZeroDash(float[] dashArray)
{
if (dashArray.length > 0)
{
for (int i = 0; i < dashArray.length; ++i)
{
if (dashArray[i] != 0)
{
return false;
}
}
return true;
}
return false;
}
private float[] getDashArray(PDLineDashPattern dashPattern) private float[] getDashArray(PDLineDashPattern dashPattern)
{ {
float[] dashArray = dashPattern.getDashArray(); float[] dashArray = dashPattern.getDashArray();
int phase = dashPattern.getPhase();
// avoid empty, infinite and NaN values (PDFBOX-3360)
if (dashArray.length == 0 || Float.isInfinite(phase) || Float.isNaN(phas
e))
{
return null;
}
for (int i = 0; i < dashArray.length; ++i)
{
if (Float.isInfinite(dashArray[i]) || Float.isNaN(dashArray[i]))
{
return null;
}
}
if (JAVA_VERSION < 10) if (JAVA_VERSION < 10)
{ {
float scalingFactorX = new Matrix(xform).getScalingFactorX(); float scalingFactorX = new Matrix(xform).getScalingFactorX();
for (int i = 0; i < dashArray.length; ++i) for (int i = 0; i < dashArray.length; ++i)
{ {
// apply the CTM // apply the CTM
float w = transformWidth(dashArray[i]); float w = transformWidth(dashArray[i]);
// minimum line dash width avoids JVM crash, // minimum line dash width avoids JVM crash,
// see PDFBOX-2373, PDFBOX-2929, PDFBOX-3204, PDFBOX-3813 // see PDFBOX-2373, PDFBOX-2929, PDFBOX-3204, PDFBOX-3813
// also avoid 0 in array like "[ 0 1000 ] 0 d", see PDFBOX-3724 // also avoid 0 in array like "[ 0 1000 ] 0 d", see PDFBOX-3724
skipping to change at line 1415 skipping to change at line 1458
// need to do it here and not in shading getRaster() because it may have been rotated // need to do it here and not in shading getRaster() because it may have been rotated
PDRectangle bbox = shading.getBBox(); PDRectangle bbox = shading.getBBox();
Area area; Area area;
if (bbox != null) if (bbox != null)
{ {
area = new Area(bbox.transform(ctm)); area = new Area(bbox.transform(ctm));
area.intersect(getGraphicsState().getCurrentClippingPath()); area.intersect(getGraphicsState().getCurrentClippingPath());
} }
else else
{ {
area = getGraphicsState().getCurrentClippingPath(); Rectangle2D bounds = shading.getBounds(new AffineTransform(), ctm);
if (bounds != null)
{
bounds.add(new Point2D.Double(Math.floor(bounds.getMinX() - 1),
Math.floor(bounds.getMinY() - 1)));
bounds.add(new Point2D.Double(Math.ceil(bounds.getMaxX() + 1),
Math.ceil(bounds.getMaxY() + 1)));
area = new Area(bounds);
area.intersect(getGraphicsState().getCurrentClippingPath());
}
else
{
area = getGraphicsState().getCurrentClippingPath();
}
} }
if (isContentRendered()) if (isContentRendered())
{ {
graphics.fill(area); graphics.fill(area);
} }
} }
@Override @Override
public void showAnnotation(PDAnnotation annotation) throws IOException public void showAnnotation(PDAnnotation annotation) throws IOException
{ {
lastClip = null; lastClip = null;
int deviceType = -1; int deviceType = -1;
if (graphics.getDeviceConfiguration() != null && GraphicsConfiguration graphicsConfiguration = graphics.getDeviceConfigur
graphics.getDeviceConfiguration().getDevice() != null) ation();
if (graphicsConfiguration != null)
{ {
deviceType = graphics.getDeviceConfiguration().getDevice().getType() GraphicsDevice graphicsDevice = graphicsConfiguration.getDevice();
; if (graphicsDevice != null)
{
deviceType = graphicsDevice.getType();
}
} }
if (deviceType == GraphicsDevice.TYPE_PRINTER && !annotation.isPrinted() ) if (deviceType == GraphicsDevice.TYPE_PRINTER && !annotation.isPrinted() )
{ {
return; return;
} }
if (deviceType == GraphicsDevice.TYPE_RASTER_SCREEN && annotation.isNoVi ew()) if (deviceType == GraphicsDevice.TYPE_RASTER_SCREEN && annotation.isNoVi ew())
{ {
return; return;
} }
if (annotation.isHidden()) if (annotation.isHidden())
skipping to change at line 1677 skipping to change at line 1737
BufferedImage backdropImage = null; BufferedImage backdropImage = null;
// Position of this group in parent group's coordinates // Position of this group in parent group's coordinates
int backdropX = 0; int backdropX = 0;
int backdropY = 0; int backdropY = 0;
if (needsBackdrop) if (needsBackdrop)
{ {
if (transparencyGroupStack.isEmpty()) if (transparencyGroupStack.isEmpty())
{ {
// Use the current page as the parent group. // Use the current page as the parent group.
backdropImage = renderer.getPageImage(); backdropImage = renderer.getPageImage();
needsBackdrop = backdropImage != null; if (backdropImage == null)
backdropX = minX; {
backdropY = (backdropImage != null) ? (backdropImage.getHeig needsBackdrop = false;
ht() - maxY) : 0; }
else
{
backdropX = minX;
backdropY = backdropImage.getHeight() - maxY;
}
} }
else else
{ {
TransparencyGroup parentGroup = transparencyGroupStack.peek( ); TransparencyGroup parentGroup = transparencyGroupStack.peek( );
backdropImage = parentGroup.image; backdropImage = parentGroup.image;
backdropX = minX - parentGroup.minX; backdropX = minX - parentGroup.minX;
backdropY = parentGroup.maxY - maxY; backdropY = parentGroup.maxY - maxY;
} }
} }
skipping to change at line 1773 skipping to change at line 1839
if (needsBackdrop) if (needsBackdrop)
{ {
((GroupGraphics) g).removeBackdrop(backdropImage, backdropX, backdropY); ((GroupGraphics) g).removeBackdrop(backdropImage, backdropX, backdropY);
} }
} }
} }
// http://stackoverflow.com/a/21181943/535646 // http://stackoverflow.com/a/21181943/535646
private BufferedImage create2ByteGrayAlphaImage(int width, int height) private BufferedImage create2ByteGrayAlphaImage(int width, int height)
{ {
/** // gray + alpha
* gray + alpha
*/
int[] bandOffsets = new int[] {1, 0}; int[] bandOffsets = new int[] {1, 0};
int bands = bandOffsets.length; int bands = bandOffsets.length;
/** // Color Model used for raw GRAY + ALPHA
* Color Model used for raw GRAY + ALPHA
*/
final ColorModel CM_GRAY_ALPHA final ColorModel CM_GRAY_ALPHA
= new ComponentColorModel( = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_GRAY), ColorSpace.getInstance(ColorSpace.CS_GRAY),
true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_B YTE); true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_B YTE);
// Init data buffer of type byte // Init data buffer of type byte
DataBuffer buffer = new DataBufferByte(width * height * bands); DataBuffer buffer = new DataBufferByte(width * height * bands);
// Wrap the data buffer in a raster // Wrap the data buffer in a raster
WritableRaster raster = WritableRaster raster =
 End of changes. 22 change blocks. 
46 lines changed or deleted 113 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)