问题
I need to get access to the font style and size of an acroform text field. I have access to the Field
object via pdfclown but can't work out how to access the font. Anyone know how to do this?
回答1:
I'm glad to announce you that today I committed to the 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): I suggest you to download directly from that SVN repo to get the latest features & fixes.
Otherwise, in case you stick with the published release (0.1.2.0), here it is the relevant code (again, I recommend the committed version as it's more refined). First of all, we need some adjustment:
1) in XObject.java replace the wrap
method:
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) in FormXObject.java replace the wrap
method:
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);
}
Then we can define the actual form flattener:
3) add FormFlattener.java to org.pdfclown.tools package:
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;
}
}
And this is an example using it:
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 */}
}
}
To keep yourself up-to-date with the activity about the project, you can follow PDF Clown on its site (pdfclown.org) and through its twitter stream (https://twitter.com/pdfclown).
回答2:
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();
}
}
来源:https://stackoverflow.com/questions/28109932/get-font-and-size-of-an-acroform-field