You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ja...@apache.org on 2015/05/19 19:19:42 UTC

svn commit: r1680350 - in /pdfbox/trunk: examples/src/main/java/org/apache/pdfbox/examples/acroforms/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/

Author: jahewson
Date: Tue May 19 17:19:42 2015
New Revision: 1680350

URL: http://svn.apache.org/r1680350
Log:
PDFBOX-2805: Correct CapHeight calculation, use bbox for form field text

Modified:
    pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/acroforms/CreateFormField.java
    pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/acroforms/FillFormField.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java

Modified: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/acroforms/CreateFormField.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/acroforms/CreateFormField.java?rev=1680350&r1=1680349&r2=1680350&view=diff
==============================================================================
--- pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/acroforms/CreateFormField.java (original)
+++ pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/acroforms/CreateFormField.java Tue May 19 17:19:42 2015
@@ -19,7 +19,6 @@ package org.apache.pdfbox.examples.acrof
 
 import java.io.File;
 import java.io.IOException;
-
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDPage;
@@ -65,14 +64,14 @@ public class CreateFormField
         PDAnnotationWidget widget = textBox.getWidgets().get(0);
         PDRectangle rect = new PDRectangle();
         rect.setLowerLeftX((float) 50);
-        rect.setLowerLeftY((float) 750);
+        rect.setLowerLeftY((float) 550);
         rect.setUpperRightX((float) 250);
-        rect.setUpperRightY((float) 800); 
+        rect.setUpperRightY((float) 560); 
         widget.setRectangle(rect);
         page.getAnnotations().add(widget);
         
         // set the field value
-        textBox.setValue("English русский язык Tiếng Việt");
+        textBox.setValue("English form contents");
 
         document.save("exampleForm.pdf");
         document.close();

Modified: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/acroforms/FillFormField.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/acroforms/FillFormField.java?rev=1680350&r1=1680349&r2=1680350&view=diff
==============================================================================
--- pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/acroforms/FillFormField.java (original)
+++ pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/acroforms/FillFormField.java Tue May 19 17:19:42 2015
@@ -33,7 +33,7 @@ public class FillFormField
     public static void main(String[] args) throws IOException
     {
         String formTemplate = "src/main/resources/org/apache/pdfbox/examples/acroforms/FillFormField.pdf";
-        String filledForm = "target/examples-output/FillFormField.pdf";
+        String filledForm = "FillFormField.pdf";
         
         // load the document
         PDDocument pdfDocument = PDDocument

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java?rev=1680350&r1=1680349&r2=1680350&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java Tue May 19 17:19:42 2015
@@ -207,16 +207,16 @@ abstract class TrueTypeEmbedder implemen
         // CapHeight, XHeight
         if (os2.getVersion() >= 1.2)
         {
-            fd.setCapHeight(os2.getCapHeight() / scaling);
-            fd.setXHeight(os2.getHeight() / scaling);
+            fd.setCapHeight(os2.getCapHeight() * scaling);
+            fd.setXHeight(os2.getHeight() * scaling);
         }
         else
         {
             // estimate by summing the typographical +ve ascender and -ve descender
-            fd.setCapHeight((os2.getTypoAscender() + os2.getTypoDescender()) / scaling);
+            fd.setCapHeight((os2.getTypoAscender() + os2.getTypoDescender()) * scaling);
 
             // estimate by halving the typographical ascender
-            fd.setXHeight((os2.getTypoAscender() / 2.0f) / scaling);
+            fd.setXHeight(os2.getTypoAscender() / 2.0f * scaling);
         }
 
         // StemV - there's no true TTF equivalent of this, so we estimate it

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java?rev=1680350&r1=1680349&r2=1680350&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java Tue May 19 17:19:42 2015
@@ -30,7 +30,6 @@ import org.apache.pdfbox.pdfwriter.Conte
 import org.apache.pdfbox.pdmodel.PDPageContentStream;
 import org.apache.pdfbox.pdmodel.common.PDRectangle;
 import org.apache.pdfbox.pdmodel.font.PDFont;
-import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
 import org.apache.pdfbox.pdmodel.interactive.action.PDFormFieldAdditionalActions;
 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
@@ -187,20 +186,23 @@ class AppearanceGeneratorHelper
         // Acrobat calculates the left and right padding dependent on the offset of the border edge
         // This calculation works for forms having been generated by Acrobat.
         // The minimum distance is always 1f even if there is no rectangle being drawn around.
-        float lineWidth = 0;
+        float borderWidth = 0;
         if (widget.getBorderStyle() != null)
         {
-            lineWidth = widget.getBorderStyle().getWidth();
+            borderWidth = widget.getBorderStyle().getWidth();
         }
-        PDRectangle paddingEdge = applyPadding(bbox, Math.max(1f, lineWidth));
-        PDRectangle contentEdge = applyPadding(paddingEdge, Math.max(1f, lineWidth));
+        PDRectangle clipRect = applyPadding(bbox, Math.max(1f, borderWidth));
+        PDRectangle contentRect = applyPadding(clipRect, Math.max(1f, borderWidth));
         
         contents.saveGraphicsState();
         
         // add a clipping path to avoid overlapping with the border
-        contents.addRect(paddingEdge.getLowerLeftX(), paddingEdge.getLowerLeftY(),
-                         paddingEdge.getWidth(), paddingEdge.getHeight());
-        contents.clip();
+        if (borderWidth > 0)
+        {
+            contents.addRect(clipRect.getLowerLeftX(), clipRect.getLowerLeftY(),
+                             clipRect.getWidth(), clipRect.getHeight());
+            contents.clip();
+        }
         
         // start the text output
         contents.beginText();
@@ -212,24 +214,33 @@ class AppearanceGeneratorHelper
         PDFont font = field.getDefaultAppearanceString().getFont();
         
         // calculate the fontSize (because 0 = autosize)
-        float fontSize = calculateFontSize(font, contentEdge);
+        float fontSize = calculateFontSize(font, contentRect);
         
-        // calculation of the vertical offset from where the text will be printed 
-        float verticalOffset = calculateVerticalOffset(paddingEdge, contentEdge, font, fontSize);
-
-        float leftOffset;
+        // calculate the y-position of the baseline
+        float y;
+        if (field instanceof PDTextField && ((PDTextField) field).isMultiline())
+        {
+            float height = font.getBoundingBox().getHeight() / 1000 * fontSize;
+            y = contentRect.getUpperRightY() - height;
+        }
+        else
+        {
+            float minY = font.getBoundingBox().getLowerLeftY() / 1000 * fontSize;
+            y = Math.max(bbox.getHeight() / 2f + minY, 0);
+        }
 
         // show the text
+        float leftOffset;
         if (!isMultiLine())
         {
             // calculation of the horizontal offset from where the text will be printed
-            leftOffset = calculateHorizontalOffset(contentEdge, font, fontSize);
-            contents.newLineAtOffset(leftOffset, verticalOffset);
+            leftOffset = calculateHorizontalOffset(contentRect, font, fontSize);
+            contents.newLineAtOffset(leftOffset, y);
             contents.showText(value);
         }
         else
         {
-            leftOffset = contentEdge.getLowerLeftX();
+            leftOffset = contentRect.getLowerLeftX();
             PlainText textContent = new PlainText(value);
             AppearanceStyle appearanceStyle = new AppearanceStyle();
             appearanceStyle.setFont(font);
@@ -237,15 +248,15 @@ class AppearanceGeneratorHelper
             
             // Adobe Acrobat uses the font's bounding box for the leading between the lines
             appearanceStyle.setLeading(font.getBoundingBox().getHeight() /
-                                       GLYPH_TO_PDF_SCALE * fontSize);
+                    GLYPH_TO_PDF_SCALE * fontSize);
             
             PlainTextFormatter formatter = new PlainTextFormatter
                                                 .Builder(contents)
                                                     .style(appearanceStyle)
                                                     .text(textContent)
-                                                    .width(contentEdge.getWidth())
+                                                    .width(contentRect.getWidth())
                                                     .wrapLines(true)
-                                                    .initialOffset(leftOffset, verticalOffset)
+                                                    .initialOffset(leftOffset, y)
                                                     .textAlign(field.getQ())
                                                     .build();
             formatter.format();
@@ -304,46 +315,6 @@ class AppearanceGeneratorHelper
     }
 
     /**
-     * Calculate the vertical start position for the text.
-     * 
-     * @param paddingEdge the content edge
-     * @param contentEdge the content edge
-     * @param pdFont the font to use for formatting
-     * @param fontSize the font size to use for formating
-     * @return the vertical start position of the text
-     * @throws IOException If there is an error calculating the text position.
-     */
-    private float calculateVerticalOffset(PDRectangle paddingEdge,  PDRectangle contentEdge,
-                                          PDFont pdFont, float fontSize) throws IOException
-    {
-        float verticalOffset;
-        float capHeight = getCapHeight(pdFont, fontSize);
-        float fontHeight = pdFont.getBoundingBox().getHeight()  / GLYPH_TO_PDF_SCALE * fontSize;
-        
-        if (field instanceof PDTextField && ((PDTextField) field).isMultiline())
-        {
-            verticalOffset = contentEdge.getUpperRightY() - fontHeight;
-        }
-        else
-        {
-            // Acrobat shifts the value so it aligns to the bottom if
-            // the font's caps are larger than the height of the paddingEdge
-            if (capHeight > paddingEdge.getHeight())
-            {
-                verticalOffset = paddingEdge.getLowerLeftX() 
-                        - pdFont.getFontDescriptor().getDescent() / GLYPH_TO_PDF_SCALE * fontSize;
-            }
-            else 
-            {
-                verticalOffset = (paddingEdge.getHeight() - capHeight) /
-                                 2f + paddingEdge.getLowerLeftX();
-            }
-        }
-        
-        return verticalOffset;
-    }
-
-    /**
      * Calculate the horizontal start position for the text.
      * 
      * @param contentEdge the content edge
@@ -388,28 +359,6 @@ class AppearanceGeneratorHelper
     }
     
     /**
-     * Get the capHeight for a font.
-     * 
-     * @throws IOException in case the font information can not be retrieved.
-     */
-    private float getCapHeight(PDFont pdFont, float fontSize) throws IOException
-    {
-        final PDFontDescriptor fontDescriptor = pdFont.getFontDescriptor();
-        
-        // as the font descriptor might be null or the cap height might be 0 
-        // alternate calculation for the cap height
-        if (fontDescriptor == null || fontDescriptor.getCapHeight() == 0)
-        {
-            // TODO: refine the calculation if needed
-            return pdFont.getBoundingBox().getHeight() / GLYPH_TO_PDF_SCALE * fontSize * 0.7f;
-        }
-        else
-        {
-            return pdFont.getFontDescriptor().getCapHeight() / GLYPH_TO_PDF_SCALE * fontSize;
-        }
-    }
-    
-    /**
      * Resolve the bounding box.
      * 
      * @param fieldWidget the annotation widget.