获取 acroform 字段的字体和大小

Get font and size of an acroform field

我需要访问 acroform 文本字段的字体样式和大小。我可以通过 pdfclown 访问 Field 对象,但不知道如何访问字体。有人知道怎么做吗?

我很高兴地向您宣布,今天我承诺 PDF Clown's repository the fully-functional implementation of the FormFlattener, both on the current branch (0.1.2-Fix, rev 129, 131, 133) and on trunk (rev 130, 132, 134):我建议您直接从该 SVN 存储库下载以获得最新的功能和修复。

否则,如果您坚持使用已发布的版本 (0.1.2.0),这里是相关代码(同样,我推荐提交的版本,因为它更精致)。首先,我们需要做一些调整:

1) 在XObject.java中替换wrap方法:

public static XObject wrap(
  PdfDirectObject baseObject
  )
{
  if(baseObject == null)
    return null;

  PdfName subtype = (PdfName)((PdfStream)baseObject.resolve()).getHeader().get(PdfName.Subtype);
  if(PdfName.Form.equals(subtype))
    return FormXObject.wrap(baseObject);
  else if(PdfName.Image.equals(subtype))
    return ImageXObject.wrap(baseObject);
  else
    return null;
}

2) 在FormXObject.java中替换wrap方法:

public static FormXObject wrap(
  PdfDirectObject baseObject
  )
{
  if(baseObject == null)
    return null;

  PdfDictionary header = ((PdfStream)PdfObject.resolve(baseObject)).getHeader();
  PdfName subtype = (PdfName)header.get(PdfName.Subtype);
  /*
    NOTE: Sometimes the form stream's header misses the mandatory Subtype entry; therefore, here
    we force integrity for convenience (otherwise, content resource allocation may fail, for 
    example in case of Acroform flattening).
  */
  if(subtype == null && header.containsKey(PdfName.BBox))
  {header.put(PdfName.Subtype, PdfName.Form);}
  else if(!subtype.equals(PdfName.Form))
    return null;

  return new FormXObject(baseObject);
}

然后我们就可以定义实际的form flattener了:

3) 添加 FormFlattener.java 到 org.pdfclown.tools 包:

package org.pdfclown.tools;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;

import org.pdfclown.documents.Document;
import org.pdfclown.documents.Page;
import org.pdfclown.documents.PageAnnotations;
import org.pdfclown.documents.contents.xObjects.FormXObject;
import org.pdfclown.documents.interaction.annotations.Annotation.FlagsEnum;
import org.pdfclown.documents.interaction.annotations.Widget;
import org.pdfclown.documents.interaction.forms.Field;
import org.pdfclown.documents.interaction.forms.Fields;
import org.pdfclown.documents.interaction.forms.Form;
import org.pdfclown.objects.PdfArray;
import org.pdfclown.objects.PdfDictionary;
import org.pdfclown.objects.PdfDirectObject;
import org.pdfclown.objects.PdfName;
import org.pdfclown.objects.PdfObjectWrapper;
import org.pdfclown.objects.PdfReference;
import org.pdfclown.tools.PageStamper;
import org.pdfclown.util.math.geom.Dimension;

public class FormFlattener
{
  private boolean hiddenRendered;
  private boolean nonPrintableRendered;

  /**
    Replaces the Acroform fields with their corresponding graphics representation.

    @param document Document to flatten.
  */
  public void flatten(
    Document document
    )
  {
    Map<PdfDirectObject,PageStamper> pageStampers = new HashMap<PdfDirectObject,PageStamper>();
    Form form = document.getForm();
    Fields formFields = form.getFields();
    for(Field field : formFields.values())
    {
      for(Widget widget : field.getWidgets())
      {
        Page widgetPage = widget.getPage();
        EnumSet<FlagsEnum> flags = widget.getFlags();
        // Is the widget to be rendered?
        if((!flags.contains(FlagsEnum.Hidden) || hiddenRendered)
          && (flags.contains(FlagsEnum.Print) || nonPrintableRendered))
        {
          // Stamping the current state appearance of the widget...
          PdfName widgetCurrentState = (PdfName)widget.getBaseDataObject().get(PdfName.AS);
          FormXObject widgetCurrentAppearance = widget.getAppearance().getNormal().get(widgetCurrentState);
          if(widgetCurrentAppearance != null)
          {
            PageStamper widgetStamper = pageStampers.get(widgetPage.getBaseObject());
            if(widgetStamper == null)
            {pageStampers.put(widgetPage.getBaseObject(), widgetStamper = new PageStamper(widgetPage));}

            Rectangle2D widgetBox = widget.getBox();
            widgetStamper.getForeground().showXObject(widgetCurrentAppearance, new Point2D.Double(widgetBox.getX(), widgetBox.getY()), new Dimension(widgetBox.getWidth(), widgetBox.getHeight()));
          }
        }

        // Removing the widget from the page annotations...
        PageAnnotations widgetPageAnnotations = widgetPage.getAnnotations();
        widgetPageAnnotations.remove(widget);
        if(widgetPageAnnotations.isEmpty())
        {
          widgetPage.getBaseDataObject().put(PdfName.Annots, null);
          widgetPageAnnotations.delete();
        }

        // Removing the field references relating the widget...
        PdfDictionary fieldPartDictionary = widget.getBaseDataObject();
        while (fieldPartDictionary != null)
        {
          PdfDictionary parentFieldPartDictionary = (PdfDictionary)fieldPartDictionary.resolve(PdfName.Parent);

          PdfArray kidsArray;
          if(parentFieldPartDictionary != null)
          {kidsArray = (PdfArray)parentFieldPartDictionary.resolve(PdfName.Kids);}
          else
          {kidsArray = formFields.getBaseDataObject();}

          kidsArray.remove(fieldPartDictionary.getReference());
          fieldPartDictionary.getReference().delete();

          if(!kidsArray.isEmpty())
            break;

          fieldPartDictionary = parentFieldPartDictionary;
        }
      }
    }
    if(formFields.isEmpty())
    {
      // Removing the Acroform root...
      document.setForm(null);
      form.delete();
    }
    for(PageStamper pageStamper : pageStampers.values())
    {pageStamper.flush();}
  }

  /**
    Gets whether hidden fields have to be rendered.
  */
  public boolean isHiddenRendered(
    )
  {return hiddenRendered;}

  /**
    Gets whether non-printable fields have to be rendered.
  */
  public boolean isNonPrintableRendered(
    )
  {return nonPrintableRendered;}

  /**
    @see #isHiddenRendered()
  */
  public FormFlattener setHiddenRendered(
    boolean value
    )
  {
    hiddenRendered = value;
    return this;
  }

  /**
    @see #isNonPrintableRendered()
  */
  public FormFlattener setNonPrintableRendered(
    boolean value
    )
  {
    nonPrintableRendered = value;
    return this;
  }
}

这是一个使用它的例子:

import java.io.IOException;

import org.pdfclown.documents.Document;
import org.pdfclown.files.File;
import org.pdfclown.tools.FormFlattener;

File file = null;
try
{
  // 1. Opening the PDF file...
  {
    try
    {file = new File(myFilePath);}
    catch(Exception e)
    {throw new RuntimeException(myFilePath + " file access error.",e);}
  }
  Document document = file.getDocument();

  // 2. Flatten the form!
  FormFlattener formFlattener = new FormFlattener();
  formFlattener.flatten(document);

  // 3. Serialize the PDF file!
  try
  {file.save(SerializationModeEnum.Standard);}
  catch(Exception e)
  {
    System.out.println("File writing failed: " + e.getMessage());
    e.printStackTrace();
  }
}
finally
{
  // 4. Closing the PDF file...
  if(file != null)
  {
    try
    {file.close();}
    catch(IOException e)
    {/* NOOP */}
  }
}

要了解有关该项目的 activity 最新信息,您可以在其网站 (pdfclown.org) and through its twitter stream (https://twitter.com/pdfclown) 上关注 PDF Clown。

public void flatten(Document document) {
    Map<Page, PageStamper> pageStampers = new HashMap<Page, PageStamper>();
    Form form = document.getForm();
    Fields formFields = form.getFields();
    for (Field field : formFields.values()) {
        for (Widget widget : field.getWidgets()) {
            Page widgetPage = widget.getPage();             
            PageStamper widgetStamper = pageStampers.get(widgetPage);
            if (widgetStamper == null) {
                pageStampers.put(widgetPage,widgetStamper = new PageStamper(widgetPage));
            }
            PrimitiveComposer composer = widgetStamper.getForeground();
            composer.setFont(new StandardType1Font(document,StandardType1Font.FamilyEnum.Courier, false, false), 7);                                    
            composer.showText(field.getName(), new Point2D.Double(widget.getBox().getX()+3, widget.getBox().getY()+3));

        }
        field.delete();
    }
    if (formFields.isEmpty()) {
        // Removing the form root...
        document.setForm(null);
        form.delete();
    }
    for (PageStamper pageStamper : pageStampers.values()) {
        pageStamper.flush();
    }
}