Java PDFBox为PDF表单中的几个字段设置自定义字体 [英] Java PDFBox setting custom font for a few fields in PDF Form

查看:4891
本文介绍了Java PDFBox为PDF表单中的几个字段设置自定义字体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Apache PDFBox来读取可填写的PDF表单,并根据一些数据填充字段。我正在使用下面的代码(根据来自其他SO答案的建议)来获取默认外观字符串,并更改它(如下所示,如果字段名称是Field1,我将字体大小从10更改为12。


  1. 我该如何加粗字段?有关安排/ Helv 10 Tf 0 g的顺序的任何文档?我需要设置大胆的领域?

  2. 如果我理解正确,有14个基本的字体,我可以使用PDFBox开箱(双语意外)我想使用一个或多个字体看起来像签名(草书)。任何开箱即可的字体,如果没有,如果我有我自己的字体,我该如何设置方法写入PDF?

请注意,下面的代码可以通过在方法参数的特定名称字段中填写方法参数中传递的特定值

谢谢!

  public static void setField(String name,String value )抛出IOException {
PDDocumentCatalog docCatalog = _pdfDocument.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();
PDField field = acroForm.getField(name);

COSDictionary dict =((PDField)field).getDictionary();
COSString defaultAppearance =(COSString)dict.getDictionaryObject(COSName.DA);
if(defaultAppearance!= null)
{
dict.setString(COSName.DA,/ Helv 10 Tf 0 g);
if(name.equalsIgnoreCase(Field1))
{
dict.setString(COSName.DA,/ Helv 12 Tf 0 g);


if(field instanceof PDTextbox)
{
field = new PDTextbox(acroForm,dict);
((PDField)field).setValue(value);





$ b根据mkl的回答,为了在同一PDF中使用两种字体,下面的方法:我无法获得默认字体和自定义字体一起工作,所以我添加了两种字体的资源,并使用它们。

  public List< String> prepareFont(PDDocument _pdfDocument)抛出IOException 
{
PDDocumentCatalog docCatalog = _pdfDocument.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();

PDResources res = acroForm.getDefaultResources();
if(res == null)
res = new PDResources();

InputStream fontStream = getClass()。getResourceAsStream(LiberationSans-Regular.ttf);
InputStream fontStream2 = getClass()。getResourceAsStream(Font2.ttf);
PDTrueTypeFont font = PDTrueTypeFont.loadTTF(_pdfDocument,fontStream);
PDTrueTypeFont font2 = PDTrueTypeFont.loadTTF(_pdfDocument,fontStream2);
String fontName = res.addFont(font);
String fontName2 = res.addFont(font2);
acroForm.setDefaultResources(res);
列表< String> fontList = new ArrayList< String>(); fontList.add(font1); fontList.add(font2);
返回fontList;


解决方案

在这里找到一个可运行的示例:,似乎可以在任何资源字典中定义它们。



这些名称不是PDF功能,即PDF规范不知道他们,相反︰


默认外观字符串( DA )包含任何图形状态或文本状态操作符,用于建立图形状态参数(如文本大小和颜色),以显示字段的可变文本。只有文本对象中允许的运算符才会出现在这个字符串中(见图9)。该字符串至少应包含 Tf (文本字体)运算符及其两个操作数,字体和大小。 指定的字体值应与默认资源字典的字体条目中的资源名称匹配(从交互式表单字典的 DR 条目引用;参见表218 )。/ b>

(第12.7.3.3节:字段/ ISO 32000-1中的变量文本)


因此,规范并不知道这些默认的字体名称。



尽管如此,Adobe Reader / Acrobat似乎支持他们,很可能是因为在遥远的过去某些形式生成工具假定他们在那里,并支持这些形式是由于兼容性的原因保存。

使用此功能,因此,可能不是最好的选择,但你的里程可能会有所不同。

使用自定义和标准字体



在他的评论中,OP表示他希望在表单中使用自定义字体和标准字体。
$ b $ p要做到这一点,我推广了方法 prepareFont 一点点,并重构TTF导入到一个单独的方法:

  public List<串GT; prepareFont(PDDocument _pdfDocument,List< PDFont>字体)抛出IOException 
{
PDDocumentCatalog docCatalog = _pdfDocument.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();

PDResources res = acroForm.getDefaultResources();
if(res == null)
res = new PDResources();

列表< String> fontNames = new ArrayList< String>(); (PDFont字体:字体)

{
fontNames.add(res.addFont(font));
}

acroForm.setDefaultResources(res);

返回fontNames;

$ b public PDFont loadTrueTypeFont(PDDocument _pdfDocument,String resourceName)throws IOException
{
try(InputStream fontStream = getClass()。getResourceAsStream(resourceName);)
{
return PDTrueTypeFont.loadTTF(_pdfDocument,fontStream);






使用这些方法可以混合自定义字体和标准字体这:

  PDDocument doc = PDDocument.load(originalStream); 
列表< String> fontNames = prepareFont(doc,Arrays.asList(loadTrueTypeFont(doc,LiberationSans-Regular.ttf),PDType1Font.HELVETICA_BOLD));
$ b $ setField(doc,FirstName,My first name,fontNames.get(0));
setField(doc,LastName,My last name,fontNames.get(1));

doc.save(新文件(RESULT_FOLDER,acroform-setFieldCustomStandard.pdf));
doc.close();




(。

I am using Apache PDFBox to read a fillable PDF form and fill the fields based on some data. I am using the below code (as per suggestions from other SO answers) to get the default Appearance String and changing it (as you can see below, I am changing the font size from 10 to 12 if the field name is "Field1".

  1. How do I bold the field? Any documentation on what order the /Helv 10 Tf 0 g are arranged? What I need to set to bold the field?
  2. If I understand right, there are 14 basic fonts that I can use in PDFBox out of the box (pun unintended). I would like to use one or more fonts that look like Signatures (cursive). Any out of the box fonts that do that? If not, if I have my own font, how do I set in the method to be written to the PDF?

Please note, the below code works fine by filling the specific 'value' passed in the method parameter in the specific 'name' field of the method parameter.

Thank you !

public static void setField(String name, String value ) throws     IOException {
    PDDocumentCatalog docCatalog = _pdfDocument.getDocumentCatalog();
    PDAcroForm acroForm = docCatalog.getAcroForm();
    PDField field = acroForm.getField( name );

    COSDictionary dict = ((PDField)field).getDictionary();
    COSString defaultAppearance = (COSString) dict.getDictionaryObject(COSName.DA);
    if (defaultAppearance != null)
    {
        dict.setString(COSName.DA, "/Helv 10 Tf 0 g");
        if(name.equalsIgnoreCase("Field1"))
        {
            dict.setString(COSName.DA, "/Helv 12 Tf 0 g");
        }
    }
    if(field instanceof PDTextbox)
    {
        field= new PDTextbox(acroForm, dict);
        ((PDField)field).setValue(value);
    }

As per mkl's answer, to use two fonts in the same PDF, I used the following method: I could not get the default font and a custom font working together, so I added two fonts to the resources and used them.

public List<String> prepareFont(PDDocument _pdfDocument) throws IOException
{
    PDDocumentCatalog docCatalog = _pdfDocument.getDocumentCatalog();
    PDAcroForm acroForm = docCatalog.getAcroForm();

    PDResources res = acroForm.getDefaultResources();
    if (res == null)
        res = new PDResources();

    InputStream fontStream = getClass().getResourceAsStream("LiberationSans-Regular.ttf");
InputStream fontStream2 = getClass().getResourceAsStream("Font2.ttf");
    PDTrueTypeFont font = PDTrueTypeFont.loadTTF(_pdfDocument, fontStream);
PDTrueTypeFont font2 = PDTrueTypeFont.loadTTF(_pdfDocument, fontStream2);
    String fontName = res.addFont(font); 
String fontName2 = res.addFont(font2);
    acroForm.setDefaultResources(res);
    List<String> fontList = new ArrayList<String>();    fontList.add(font1);fontList.add(font2);
    return fontList;
}

解决方案

(You can find a runnable example here: FillFormCustomFont.java)

Using poor-man's-bold

  1. How do I bold the field? ... What I need to set to bold the field?

In PDF you usually make text bold by using a font with bold glyphs, also see your second question. If you don't have such a bold font at hands, you may instead use some poor-man's-bold technique, e.g. not only filling the letter but also stroking a line along its borders:

public static void setFieldBold(String name, String value) throws IOException
{
    PDDocumentCatalog docCatalog = _pdfDocument.getDocumentCatalog();
    PDAcroForm acroForm = docCatalog.getAcroForm();
    PDField field = acroForm.getField(name);

    COSDictionary dict = ((PDField) field).getDictionary();
    COSString defaultAppearance = (COSString) dict
            .getDictionaryObject(COSName.DA);
    if (defaultAppearance != null)
    {
        dict.setString(COSName.DA, "/Helv 10 Tf 2 Tr .5 w 0 g");
        if (name.equalsIgnoreCase("Field1")) {
            dict.setString(COSName.DA, "/Helv 12 Tf 0 g");
        }
    }
    if (field instanceof PDTextbox)
    {
        field = new PDTextbox(acroForm, dict);
        ((PDField) field).setValue(value);
    }
}

(2 Tr .5 w = use rendering mode 2, i.e. fill and stroke, and use a line width of .5)

Instead of

you now get

Using custom fonts

  1. If I understand right, there are 14 basic fonts that I can use in PDFBox out of the box (pun unintended). I would like to use one or more fonts that look like Signatures (cursive). Any out of the box fonts that do that? If not, if I have my own font, how do I set in the method to be written to the PDF?

If you want to use an own font, you first need to register it in the AcroForm default resources like this:

public String prepareFont(PDDocument _pdfDocument) throws IOException
{
    PDDocumentCatalog docCatalog = _pdfDocument.getDocumentCatalog();
    PDAcroForm acroForm = docCatalog.getAcroForm();

    PDResources res = acroForm.getDefaultResources();
    if (res == null)
        res = new PDResources();

    InputStream fontStream = getClass().getResourceAsStream("LiberationSans-Regular.ttf");
    PDTrueTypeFont font = PDTrueTypeFont.loadTTF(_pdfDocument, fontStream);
    String fontName = res.addFont(font);
    acroForm.setDefaultResources(res);

    return fontName;
}

This method returns the font name to use in

public static void setField(String name, String value, String fontName) throws IOException
{
    PDDocumentCatalog docCatalog = _pdfDocument.getDocumentCatalog();
    PDAcroForm acroForm = docCatalog.getAcroForm();
    PDField field = acroForm.getField(name);

    COSDictionary dict = ((PDField) field).getDictionary();
    COSString defaultAppearance = (COSString) dict
            .getDictionaryObject(COSName.DA);
    if (defaultAppearance != null)
    {
        dict.setString(COSName.DA, "/" + fontName + " 10 Tf 0 g");
        if (name.equalsIgnoreCase("Field1")) {
            dict.setString(COSName.DA, "/" + fontName + " 12 Tf 0 g");
        }
    }
    if (field instanceof PDTextbox)
    {
        field = new PDTextbox(acroForm, dict);
        ((PDField) field).setValue(value);
    }
}

You now get

The difference is not too big because the fonts are quite similar. Use the font of your choice for more effect.

Using /Helv, /HeBo, ...

The OP found a list of font names /Helv, /HeBo, ..., probably in the PDFBox issue PDFBOX-1234, which appear to be usable without defining them in any resource dictionary.

These names are not a PDF feature, i.e. the PDF specification does not know about them, on the contrary:

The default appearance string (DA) contains any graphics state or text state operators needed to establish the graphics state parameters, such as text size and colour, for displaying the field’s variable text. Only operators that are allowed within text objects shall occur in this string (see Figure 9). At a minimum, the string shall include a Tf (text font) operator along with its two operands, font and size. The specified font value shall match a resource name in the Font entry of the default resource dictionary (referenced from the DR entry of the interactive form dictionary; see Table 218).

(section 12.7.3.3 Field Dictionaries / Variable Text in ISO 32000-1)

Thus, the specification does not know those default font names.

Nonetheless, Adobe Reader/Acrobat seem to support them, most likely because at some time in the distant past some form generating tool assumed them to be there and support for those forms was kept due to compatibility reasons.

Using this feature, therefore, might not be the best choice but your mileage may vary.

Using custom and standard fonts

In his comments the OP indicated he wanted to use both custom and standard fonts in forms.

To do this I generalized the method prepareFont a bit and refactored the TTF import into a separate method:

public List<String> prepareFont(PDDocument _pdfDocument, List<PDFont> fonts) throws IOException
{
    PDDocumentCatalog docCatalog = _pdfDocument.getDocumentCatalog();
    PDAcroForm acroForm = docCatalog.getAcroForm();

    PDResources res = acroForm.getDefaultResources();
    if (res == null)
        res = new PDResources();

    List<String> fontNames = new ArrayList<String>();
    for (PDFont font: fonts)
    {
        fontNames.add(res.addFont(font));
    }

    acroForm.setDefaultResources(res);

    return fontNames;
}

public PDFont loadTrueTypeFont(PDDocument _pdfDocument, String resourceName) throws IOException
{
    try ( InputStream fontStream = getClass().getResourceAsStream(resourceName); )
    {
        return PDTrueTypeFont.loadTTF(_pdfDocument, fontStream);
    }
}

Using these methods you can mix custom and standard fonts like this:

PDDocument doc = PDDocument.load(originalStream);
List<String> fontNames = prepareFont(doc, Arrays.asList(loadTrueTypeFont(doc, "LiberationSans-Regular.ttf"), PDType1Font.HELVETICA_BOLD));

setField(doc, "FirstName", "My first name", fontNames.get(0));
setField(doc, "LastName", "My last name", fontNames.get(1));

doc.save(new File(RESULT_FOLDER, "acroform-setFieldCustomStandard.pdf"));
doc.close();

(FillFormCustomFont.testSetFieldCustomStandard_acroform)

Resulting in

PDType1Font has constants for all 14 standard fonts. Thus, like this you can use standard fonts (mixed with custom fonts if desired) in form fields in a way that generates the proper Font entries in the default resources, i.e. without relying on proprietary default font names like HeBo.

PS

Any documentation on what order the /Helv 10 Tf 0 g are arranged?

Yes, there is, cf. the specification ISO 32000-1.

这篇关于Java PDFBox为PDF表单中的几个字段设置自定义字体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆