当前位置: 首页 > 知识库问答 >
问题:

Java PDFBox为PDF格式的几个字段设置自定义字体

陶锋
2023-03-14

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

  1. 如何加粗字段?是否有关于/HELV 10 Tf 0 g的排列顺序的文件?我需要设置什么来粗体字段?
  2. 如果我理解正确,有14种基本字体,我可以在PDFBox中使用开箱即用(双关语无意)。我想使用一个或多个看起来像签名的字体(草书)。有什么开箱即用的字体吗?如果没有,如果我有自己的字体,如何设置要写入PDF的方法?

请注意,下面的代码通过在方法参数的特定'name'字段中填充方法参数中传递的特定'value'可以很好地工作。

谢谢!

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);
    }

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

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;
}

共有1个答案

蒋飞捷
2023-03-14

(您可以在这里找到一个可运行的示例:FillFormCustomFont.java

  1. 如何加粗字段?...我需要设置什么来加粗该字段?

在PDF中,你通常使用带有粗体字形的字体来使文本粗体,也见你的第二个问题。如果你手边没有这样的粗体字体,你可以使用一些穷人的粗体技巧,例如,不仅填充字母,而且沿着字母的边框画一条线:

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);
    }
}

如果要使用自己的字体,首先需要将其注册到AcroForm默认资源中,如下所示:

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;
}

此方法返回要在

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);
    }
}

你现在得到

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

(ISO 32000-1中的字段词典/可变文本第12.7.3.3节)

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

为此,我对preparefont方法进行了一点泛化,并将TTF导入重构为一个单独的方法

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);
    }
}

使用这些方法,您可以像下面这样混合自定义字体和标准字体:

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)

 类似资料:
  • 如何为PDF表单中的每个字段设置定义值,假设我的PDF表单中有5个字段,例如2个文本框(名字和姓氏)和2个复选框(Check_1,Check_2),2个单选按钮(男,女),然后最后我有另一个文本框(地址),现在我必须定义或设置每个字段的值,比如1代表名字,2代表姓氏,3代表Check_1并继续到7代表地址。下面是一段代码来定义每个字段的值,但我面临一些问题,当设置单选按钮字段的值时,当涉及男和女字

  • 介绍 model 参考文档已经介绍了如何使用 Django 的标准字段类;例如 CharField, DateField,等等。对于很多应用来说,这些类足够用了。 但是在某些情况下, 你所用的Django 不具备你需要的某些精巧功能,或是你想使用的字段与 Django 自带字段完全不同。 Django 内置的字段类型并不能覆盖所有可能遇到的数据库的列类型,仅仅是些普通的字段类型,例如VARCHAR

  • 我在修改我安装的WordPress流行帖子插件时遇到了一些问题。 它可以选择从自定义字段获取缩略图,我已将其输入为“image_facebook”。但是缩略图没有显示。 在检查代码时,我发现imgsrc有post id而不是返回图像URL。 我已经把问题缩小到我安装的另一个插件http://wordpress.org/plugins/advanced-custom-fields/ 当它处于活动状态

  • WooCommerce的设置指仪表盘 - WooCommerce - 设置下的选项卡,有常规、产品、配送等等。很多WooCommerce插件会在这里增加自己的设置选项,它们是怎么做的呢?本文将介绍向WooCommerce设置里添加自定义选项卡和字段的方法。 WooCommerce设置 – 向产品设置里添加自定义选项卡和字段 目标:如上图所示,在产品选项卡下添加Example Section,里面就

  • 我知道我可以像这样轻松地在JSP中格式化日期: 我做错了什么?

  • 问题内容: 目前,我仅显示键,每个键都在新行中显示: 如何在新行中将它们显示为 key :: value ? 问题答案: 通过迭代器,将生成一个键,值元组: 更新为现代符号: