You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2013/10/26 13:26:35 UTC
svn commit: r1535966 - in
/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox:
pdfviewer/PageDrawer.java pdfviewer/font/CFFGlyph2D.java
pdfviewer/font/TTFGlyph2D.java util/operator/pagedrawer/Invoke.java
Author: lehmi
Date: Sat Oct 26 11:26:34 2013
New Revision: 1535966
URL: http://svn.apache.org/r1535966
Log:
PDFBOX-1741: take the whole font matrix into account when rendering a font, simplify the calculation of transformed coordinates as proposed by Vincent Hennebert
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/PageDrawer.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/CFFGlyph2D.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/TTFGlyph2D.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/PageDrawer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/PageDrawer.java?rev=1535966&r1=1535965&r2=1535966&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/PageDrawer.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/PageDrawer.java Sat Oct 26 11:26:34 2013
@@ -142,6 +142,8 @@ public class PageDrawer extends PDFStrea
pageSize = pageDimension;
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ graphics.translate(0, pageSize.height);
+ graphics.scale(1, -1);
// Only if there is some content, we have to process it.
// Otherwise we are done here and we will produce an empty page
if (page.getContents() != null)
@@ -259,37 +261,16 @@ public class PageDrawer extends PDFStrea
graphics.setPaint(paint);
PDFont font = text.getFont();
- Matrix textPos = text.getTextPos().copy();
- float x = textPos.getXPosition();
- // the 0,0-reference has to be moved from the lower left (PDF) to the upper left (AWT-graphics)
- float y = pageSize.height - textPos.getYPosition();
-
- // Set translation to 0,0. We only need the scaling and shearing except for type 3 fonts
- if (!font.isType3Font())
- {
- textPos.setValue(2, 0, 0);
- textPos.setValue(2, 1, 0);
- }
- // because of the moved 0,0-reference, we have to shear in the opposite direction
- textPos.setValue(0, 1, (-1) * textPos.getValue(0, 1));
- textPos.setValue(1, 0, (-1) * textPos.getValue(1, 0));
- AffineTransform at = textPos.createAffineTransform();
+ AffineTransform at = text.getTextPos().createAffineTransform();
PDMatrix fontMatrix = font.getFontMatrix();
- // Type3 fonts don't use the same units within the font matrix as all the other fonts
- if (font.isType3Font())
- {
- at.scale(fontMatrix.getValue(0, 0), fontMatrix.getValue(1, 1));
- }
- else
- {
- at.scale(fontMatrix.getValue(0, 0) * 1000f, fontMatrix.getValue(1, 1) * 1000f);
- }
// TODO setClip() is a massive performance hot spot. Investigate optimization possibilities
graphics.setClip(graphicsState.getCurrentClippingPath());
// use different methods to draw the string
if (font.isType3Font())
{
+ // Type3 fonts don't use the same units within the font matrix as all the other fonts
+ at.scale(fontMatrix.getValue(0, 0), fontMatrix.getValue(1, 1));
// Type3 fonts are using streams for each character
drawType3String((PDType3Font) font, text.getCharacter(), at);
}
@@ -298,14 +279,18 @@ public class PageDrawer extends PDFStrea
Glyph2D glyph2D = createGlyph2D(font);
if (glyph2D != null)
{
+ AffineTransform fontMatrixAT = new AffineTransform(fontMatrix.getValue(0, 0), fontMatrix.getValue(
+ 0, 1), fontMatrix.getValue(1, 0), fontMatrix.getValue(1, 1), fontMatrix.getValue(2, 0),
+ fontMatrix.getValue(2, 1));
+ at.concatenate(fontMatrixAT);
// Let PDFBox render the font if supported
- drawGlyph2D(glyph2D, text.getCodePoints(), at, x, y);
+ drawGlyph2D(glyph2D, text.getCodePoints(), at);
}
else
{
// Use AWT to render the font (Type1 fonts, standard14 fonts, if the embedded font is substituted)
// TODO to be removed in the long run?
- drawString((PDSimpleFont) font, text.getCharacter(), at, x, y);
+ drawString((PDSimpleFont) font, text.getCharacter(), at);
}
}
}
@@ -321,52 +306,36 @@ public class PageDrawer extends PDFStrea
* @param glyph2D the Glyph2D implementation provided a GeneralPath for each glyph
* @param codePoints the string to be rendered
* @param at the transformation
- * @param x the x coordinate of the text
- * @param y the y coordinate of the text
* @throws IOException if something went wrong
*/
- private void drawGlyph2D(Glyph2D glyph2D, int[] codePoints, AffineTransform at, float x, float y)
- throws IOException
+ private void drawGlyph2D(Glyph2D glyph2D, int[] codePoints, AffineTransform at) throws IOException
{
- Graphics2D g2d = (Graphics2D) graphics;
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (int i = 0; i < codePoints.length; i++)
{
- if (!at.isIdentity())
+ GeneralPath path = glyph2D.getPathForCharactercode(codePoints[i]);
+ if (path != null)
{
- try
+ AffineTransform atInverse = null;
+ if (!at.isIdentity())
{
- AffineTransform atInv = at.createInverse();
- // do only apply the size of the transform, rotation will be realized by rotating the graphics,
- // otherwise the hp printers will not render the font
- // apply the transformation to the graphics, which should be the same as applying the
- // transformation itself to the text
- g2d.transform(at);
- // translate the coordinates
- Point2D.Float newXy = new Point2D.Float(x, y);
- atInv.transform(new Point2D.Float(x, y), newXy);
-
- GeneralPath path = glyph2D.getPathForCharactercode(codePoints[i]);
- if (path != null)
+ try
+ {
+ atInverse = at.createInverse();
+ }
+ catch (NoninvertibleTransformException exception)
{
- g2d.translate(newXy.getX(), newXy.getY());
- g2d.fill(path);
- g2d.translate(-newXy.getX(), -newXy.getY());
+ LOG.error("Can't invert the given affine transformation", exception);
}
- // restore the original transformation
- g2d.transform(atInv);
}
- catch (NoninvertibleTransformException e)
+ if (atInverse != null)
{
- LOG.error("Error in " + getClass().getName() + ".drawGlyph2D", e);
+ graphics.transform(at);
}
- }
- else
- {
- GeneralPath path = glyph2D.getPathForCharactercode(codePoints[i]);
- if (path != null)
+ graphics.fill(path);
+ if (atInverse != null)
{
- g2d.draw(path);
+ graphics.transform(atInverse);
}
}
}
@@ -378,6 +347,7 @@ public class PageDrawer extends PDFStrea
* @param font the type3 font
* @param string the string to be rendered
* @param at the transformation
+ *
* @throws IOException if something went wrong
*/
private void drawType3String(PDType3Font font, String string, AffineTransform at) throws IOException
@@ -413,51 +383,33 @@ public class PageDrawer extends PDFStrea
* @param string The string to draw.
* @param g The graphics to draw onto.
* @param at The transformation matrix with all information for scaling and shearing of the font.
- * @param x The x coordinate to draw at.
- * @param y The y coordinate to draw at.
*
* @throws IOException If there is an error drawing the specific string.
*/
- private void drawString(PDSimpleFont font, String string, AffineTransform at, float x, float y) throws IOException
+ private void drawString(PDSimpleFont font, String string, AffineTransform at) throws IOException
{
Font awtFont = createAWTFont(font);
FontRenderContext frc = new FontRenderContext(new AffineTransform(), true, true);
GlyphVector glyphs = awtFont.createGlyphVector(frc, string);
+ graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ writeFont(at, glyphs);
+ }
- Graphics2D g2d = (Graphics2D) graphics;
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- writeFont(g2d, at, x, y, glyphs);
- }
-
- private void writeFont(final Graphics2D g2d, final AffineTransform at, final float x, final float y,
- final GlyphVector glyphs)
- {
- // check if we have a rotation
- if (!at.isIdentity())
- {
- try
- {
- AffineTransform atInv = at.createInverse();
- // do only apply the size of the transform, rotation will be realized by rotating the graphics,
- // otherwise the hp printers will not render the font
- // apply the transformation to the graphics, which should be the same as applying the
- // transformation itself to the text
- g2d.transform(at);
- // translate the coordinates
- Point2D.Float newXy = new Point2D.Float(x, y);
- atInv.transform(new Point2D.Float(x, y), newXy);
- g2d.drawGlyphVector(glyphs, (float) newXy.getX(), (float) newXy.getY());
- // restore the original transformation
- g2d.transform(atInv);
- }
- catch (NoninvertibleTransformException e)
- {
- LOG.error("Error in " + getClass().getName() + ".writeFont", e);
- }
+ private void writeFont(final AffineTransform at, final GlyphVector glyphs)
+ {
+ try
+ {
+ // Convert from PDF, where glyphs are upright when direction is from
+ // bottom to top, to AWT, where this is the other way around
+ at.scale(1, -1);
+ AffineTransform atInverse = at.createInverse();
+ graphics.transform(at);
+ graphics.drawGlyphVector(glyphs, 0, 0);
+ graphics.transform(atInverse);
}
- else
+ catch (NoninvertibleTransformException exception)
{
- g2d.drawGlyphVector(glyphs, x, y);
+ LOG.error("Can't invert the given affine transformation", exception);
}
}
@@ -654,17 +606,6 @@ public class PageDrawer extends PDFStrea
}
/**
- * Fix the y coordinate.
- *
- * @param y The y coordinate.
- * @return The updated y coordinate.
- */
- public double fixY(double y)
- {
- return pageSize.getHeight() - y;
- }
-
- /**
* Get the current line path to be drawn.
*
* @return The current line path to be drawn.
@@ -794,7 +735,6 @@ public class PageDrawer extends PDFStrea
double[] position = { x, y };
getGraphicsState().getCurrentTransformationMatrix().createAffineTransform()
.transform(position, 0, position, 0, 1);
- position[1] = fixY(position[1]);
return new Point2D.Double(position[0], position[1]);
}
@@ -862,7 +802,12 @@ public class PageDrawer extends PDFStrea
{
graphics.setComposite(getGraphicsState().getStrokeJavaComposite());
graphics.setClip(getGraphicsState().getCurrentClippingPath());
- graphics.drawImage(awtImage, at, null);
+ int width = awtImage.getWidth(null);
+ int height = awtImage.getHeight(null);
+ AffineTransform imageTransform = new AffineTransform(at);
+ imageTransform.scale(1.0 / width, -1.0 / height);
+ imageTransform.translate(0, -height);
+ graphics.drawImage(awtImage, imageTransform, null);
}
/**
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/CFFGlyph2D.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/CFFGlyph2D.java?rev=1535966&r1=1535965&r2=1535966&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/CFFGlyph2D.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/CFFGlyph2D.java Sat Oct 26 11:26:34 2013
@@ -18,10 +18,7 @@
*/
package org.apache.pdfbox.pdfviewer.font;
-import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
-import java.awt.geom.Path2D;
-import java.awt.geom.PathIterator;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
@@ -46,7 +43,6 @@ public class CFFGlyph2D implements Glyph
*/
private static final Log LOG = LogFactory.getLog(CFFGlyph2D.class);
- private float scale = 0.001f;
private HashMap<Integer, GeneralPath> glyphs = new HashMap<Integer, GeneralPath>();
private HashMap<Integer, Integer> codeToGlyph = new HashMap<Integer, Integer>();
private String fontname = null;
@@ -81,9 +77,7 @@ public class CFFGlyph2D implements Glyph
}
if (glyph != null)
{
- AffineTransform atPath = AffineTransform.getScaleInstance(scale, scale);
- glyph.transform(atPath);
- glyphs.put(glyphId, transformGlyph(glyph));
+ glyphs.put(glyphId, glyph);
int code = mapping.getSID();
String name = mapping.getName();
if (nameToCode != null && nameToCode.containsKey(name))
@@ -96,48 +90,6 @@ public class CFFGlyph2D implements Glyph
}
}
- private GeneralPath transformGlyph(GeneralPath glyph)
- {
- // we have to invert all y-coordinates due to the moved 0,0-reference
- PathIterator iter = glyph.getPathIterator(null);
- float[] currentSegment = new float[6];
- Path2D.Float path = new Path2D.Float(iter.getWindingRule());
- boolean glyphTransformed = false;
- while (!iter.isDone())
- {
- glyphTransformed = true;
- int type = iter.currentSegment(currentSegment);
- switch (type)
- {
- case PathIterator.SEG_MOVETO:
- path.moveTo(currentSegment[0], -currentSegment[1]);
- break;
- case PathIterator.SEG_LINETO:
- path.lineTo(currentSegment[0], -currentSegment[1]);
- break;
- case PathIterator.SEG_QUADTO:
- path.quadTo(currentSegment[0], -currentSegment[1], currentSegment[2], -currentSegment[3]);
- break;
- case PathIterator.SEG_CUBICTO:
- path.curveTo(currentSegment[0], -currentSegment[1], currentSegment[2], -currentSegment[3],
- currentSegment[4], -currentSegment[5]);
- break;
- case PathIterator.SEG_CLOSE:
- path.closePath();
- break;
- }
- iter.next();
- }
- if (glyphTransformed)
- {
- return new GeneralPath(path);
- }
- else
- {
- return glyph;
- }
- }
-
/**
* {@inheritDoc}
*/
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/TTFGlyph2D.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/TTFGlyph2D.java?rev=1535966&r1=1535965&r2=1535966&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/TTFGlyph2D.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/font/TTFGlyph2D.java Sat Oct 26 11:26:34 2013
@@ -55,11 +55,6 @@ public class TTFGlyph2D implements Glyph
private static final Log LOG = LogFactory.getLog(TTFGlyph2D.class);
/**
- * Default scaling value.
- */
- private static final float DEFAULT_SCALING = 0.001f;
-
- /**
* Start of coderanges.
*/
private static final int START_RANGE_F000 = 0xF000;
@@ -69,7 +64,8 @@ public class TTFGlyph2D implements Glyph
private TrueTypeFont font;
private PDCIDFontType2Font descendantFont;
private String name;
- private float scale;
+ private float scale = 1.0f;
+ private boolean hasScaling = false;
private CMAPEncodingEntry cmapWinUnicode = null;
private CMAPEncodingEntry cmapWinSymbol = null;
private CMAPEncodingEntry cmapMacintoshSymbol = null;
@@ -105,13 +101,12 @@ public class TTFGlyph2D implements Glyph
font = trueTypeFont;
// get units per em, which is used as scaling factor
HeaderTable header = font.getHeader();
- if (header != null)
- {
- scale = 1f / header.getUnitsPerEm();
- }
- else
+ if (header != null && header.getUnitsPerEm() != 1000)
{
- scale = DEFAULT_SCALING;
+ // in most case the scaling factor is set to 1.0f
+ // due to the fact that units per em is set to 1000
+ scale = 1000f / header.getUnitsPerEm();
+ hasScaling = true;
}
extractCMaps();
extractFontSpecifics(pdFont, descFont);
@@ -191,7 +186,7 @@ public class TTFGlyph2D implements Glyph
{
endPtIndex++;
}
- points[i] = new Point(gd.getXCoordinate(i), -gd.getYCoordinate(i),
+ points[i] = new Point(gd.getXCoordinate(i), gd.getYCoordinate(i),
(gd.getFlags(i) & GlyfDescript.ON_CURVE) != 0, endPt);
}
return points;
@@ -217,8 +212,11 @@ public class TTFGlyph2D implements Glyph
GlyphDescription gd = glyph.getDescription();
Point[] points = describe(gd);
glyphPath = calculatePath(points);
- AffineTransform atScale = AffineTransform.getScaleInstance(scale, scale);
- glyphPath.transform(atScale);
+ if (hasScaling)
+ {
+ AffineTransform atScale = AffineTransform.getScaleInstance(scale, scale);
+ glyphPath.transform(atScale);
+ }
glyphs.put(glyphId, glyphPath);
}
else
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java?rev=1535966&r1=1535965&r2=1535966&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java Sat Oct 26 11:26:34 2013
@@ -40,9 +40,9 @@ import org.apache.pdfbox.util.operator.O
/**
* Implementation of content stream operator for page drawer.
- *
+ *
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.4 $
+ *
*/
public class Invoke extends OperatorProcessor
{
@@ -54,24 +54,25 @@ public class Invoke extends OperatorProc
/**
* process : Do : Paint the specified XObject (section 4.7).
+ *
* @param operator The operator that is being executed.
* @param arguments List
* @throws IOException If there is an error invoking the sub object.
*/
public void process(PDFOperator operator, List<COSBase> arguments) throws IOException
{
- PageDrawer drawer = (PageDrawer)context;
+ PageDrawer drawer = (PageDrawer) context;
PDPage page = drawer.getPage();
- COSName objectName = (COSName)arguments.get( 0 );
+ COSName objectName = (COSName) arguments.get(0);
Map<String, PDXObject> xobjects = drawer.getResources().getXObjects();
- PDXObject xobject = (PDXObject)xobjects.get( objectName.getName() );
- if ( xobject == null )
+ PDXObject xobject = (PDXObject) xobjects.get(objectName.getName());
+ if (xobject == null)
{
- LOG.warn("Can't find the XObject for '"+objectName.getName()+"'");
+ LOG.warn("Can't find the XObject for '" + objectName.getName() + "'");
}
- else if( xobject instanceof PDXObjectImage )
+ else if (xobject instanceof PDXObjectImage)
{
- PDXObjectImage image = (PDXObjectImage)xobject;
+ PDXObjectImage image = (PDXObjectImage) xobject;
try
{
if (image.getImageMask())
@@ -81,59 +82,46 @@ public class Invoke extends OperatorProc
image.setStencilColor(drawer.getGraphicsState().getNonStrokingColor());
}
BufferedImage awtImage = image.getRGBImage();
- if (awtImage == null)
+ if (awtImage == null)
{
LOG.warn("getRGBImage returned NULL");
- return;//TODO PKOCH
+ return;// TODO PKOCH
}
int imageWidth = awtImage.getWidth();
int imageHeight = awtImage.getHeight();
- double pageHeight = drawer.getPageSize().getHeight();
LOG.debug("imageWidth: " + imageWidth + "\t\timageHeight: " + imageHeight);
-
+
Matrix ctm = drawer.getGraphicsState().getCurrentTransformationMatrix();
- float yScaling = ctm.getYScale();
- float angle = (float)Math.acos(ctm.getValue(0, 0)/ctm.getXScale());
- if (ctm.getValue(0, 1) < 0 && ctm.getValue(1, 0) > 0)
- {
- angle = (-1)*angle;
- }
- ctm.setValue(2, 1, (float)(pageHeight - ctm.getYPosition() - Math.cos(angle)*yScaling));
- ctm.setValue(2, 0, (float)(ctm.getXPosition() - Math.sin(angle)*yScaling));
- // because of the moved 0,0-reference, we have to shear in the opposite direction
- ctm.setValue(0, 1, (-1)*ctm.getValue(0, 1));
- ctm.setValue(1, 0, (-1)*ctm.getValue(1, 0));
- AffineTransform ctmAT = ctm.createAffineTransform();
- ctmAT.scale(1f/imageWidth, 1f/imageHeight);
- drawer.drawImage( awtImage, ctmAT );
+ AffineTransform imageTransform = ctm.createAffineTransform();
+ drawer.drawImage(awtImage, imageTransform);
}
- catch( Exception e )
+ catch (Exception e)
{
e.printStackTrace();
LOG.error(e, e);
}
}
- else if(xobject instanceof PDXObjectForm)
+ else if (xobject instanceof PDXObjectForm)
{
// save the graphics state
- context.getGraphicsStack().push( (PDGraphicsState)context.getGraphicsState().clone() );
-
- PDXObjectForm form = (PDXObjectForm)xobject;
+ context.getGraphicsStack().push((PDGraphicsState) context.getGraphicsState().clone());
+
+ PDXObjectForm form = (PDXObjectForm) xobject;
COSStream formContentstream = form.getCOSStream();
// find some optional resources, instead of using the current resources
PDResources pdResources = form.getResources();
// if there is an optional form matrix, we have to map the form space to the user space
Matrix matrix = form.getMatrix();
- if (matrix != null)
+ if (matrix != null)
{
- Matrix xobjectCTM = matrix.multiply( context.getGraphicsState().getCurrentTransformationMatrix());
+ Matrix xobjectCTM = matrix.multiply(context.getGraphicsState().getCurrentTransformationMatrix());
context.getGraphicsState().setCurrentTransformationMatrix(xobjectCTM);
}
- getContext().processSubStream( page, pdResources, formContentstream );
-
+ getContext().processSubStream(page, pdResources, formContentstream);
+
// restore the graphics state
- context.setGraphicsState( (PDGraphicsState)context.getGraphicsStack().pop() );
+ context.setGraphicsState((PDGraphicsState) context.getGraphicsStack().pop());
}
}
}