Reputation: 747
I am trying, from a TextPosition, to draw the corresponding glyph bounding box as shown in the PDF 32000 documentation.
Here is my function that does the computation from glyph space to user space
@Override
protected void processTextPosition(TextPosition text) {
PDFont font = pos.getFont();
BoundingBox bbox = font.getBoundingBox();
Rectangle2D.Float rect = new Rectangle2D.Float(bbox.getLowerLeftX(), bbox.getUpperRightY(),
bbox.getWidth(), bbox.getHeight());
AffineTransform at = pos.getTextMatrix().createAffineTransform();
if (font instanceof PDType3Font) {
at.concatenate(font.getFontMatrix().createAffineTransform());
} else {
at.scale(1 / 1000f, 1 / 1000f);
}
Shape shape = at.createTransformedShape(rect);
rectangles.add(fillBBox(text));
super.processTextPosition(text);
}
And Here is the function that draws the extracted rectangles:
private void drawBoundingBoxes() throws IOException {
String fileNameOut = path.substring(0, path.lastIndexOf(".")) + "_OUT.pdf";
log.info("Drawing Bounding Boxes for TextPositions");
PDPageContentStream contentStream = new PDPageContentStream(document,
document.getPage(document.getNumberOfPages()-1),
PDPageContentStream.AppendMode.APPEND, false , true );
contentStream.setLineWidth(1f);
contentStream.setStrokingColor(Color.RED);
try{
for (Shape p : rectangles) {
p = all.get(0);
double[] coords = new double[6];
GeneralPath g = new GeneralPath(p.getBounds2D());
for (PathIterator pi = g.getPathIterator(null);
!pi.isDone();
pi.next()) {
System.out.println(Arrays.toString(coords));
switch (pi.currentSegment(coords)) {
case PathIterator.SEG_MOVETO:
System.out.println("move to");
contentStream.moveTo ((float)coords[0], (float) coords[1]);
break;
case PathIterator.SEG_LINETO:
System.out.println("line to");
contentStream.lineTo ((float)coords[0], (float) coords[1]);
break;
case PathIterator.SEG_CUBICTO:
System.out.println("cubc to");
contentStream.curveTo((float)coords[0], (float) coords[1],
(float)coords[2], (float) coords[3],
(float)coords[4],(float) coords[5]);
break;
case PathIterator.SEG_CLOSE:
System.out.println("close");
contentStream.closeAndStroke();
break;
default:
System.out.println("no shatt");
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
contentStream.close();
document.save(new File(fileNameOut));
}
}
Then when I try to draw on the pdf I get the following result for the first letter (the capital V)
I can't figure out what I am doing wrong. Any ideas?
Upvotes: 3
Views: 2917
Reputation: 216
Mr. D,
I tested your code and the only change I needed to make it work was to invert the Y axis. The reason this is needed is because the origin in the PDF User Space is located at the bottom-left corner, unlike the origin of the Java 2D User Space which is located on the top-left corner[1].
8.3.2.3 User Space
The user space coordinate system shall be initialized to a default state for each page of a document. The CropBox entry in the page dictionary shall specify the rectangle of user space corresponding to the visible area of the intended output medium (display window or printed page). The positive x axis extends horizontally to the right and the positive y axis vertically upward, as in standard mathematical practice (subject to alteration by the Rotate entry in the page dictionary). The length of a unit along both the x and y axes is set by the UserUnit entry (PDF 1.6) in the page dictionary (see Table 30). If that entry is not present or supported, the default value of 1⁄72 inch is used. This coordinate system is called default user space.[2]
@Override
protected void processTextPosition(TextPosition text) {
try {
PDFont font = pos.getFont();
BoundingBox bbox = font.getBoundingBox();
Rectangle2D.Float rect = new Rectangle2D.Float(bbox.getLowerLeftX(), bbox.getUpperRightY(),
bbox.getWidth(), bbox.getHeight());
AffineTransform at = pos.getTextMatrix().createAffineTransform();
if (font instanceof PDType3Font) {
at.concatenate(font.getFontMatrix().createAffineTransform());
} else {
at.scale(1 / 1000f, 1 / 1000f);
}
Shape shape = at.createTransformedShape(rect);
// Invert Y axis
Rectangle2D bounds = shape.getBounds2D();
bounds.setRect(bounds.getX(), bounds.getY() - bounds.getHeight(), bounds.getWidth(), bounds.getHeight());
rectangles.add(bounds);
super.processTextPosition(text);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Document management - Portable document format - Part 1: PDF 1.7, PDF 32000-1:2008, Section 8.3: Coordinate Systems, page 115
Upvotes: 3