Java PDFBox设置PDF表单中几个字段的自定义字体

时间:2015-05-12 03:27:06

标签: java pdf fonts pdfbox pdf-form

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

  1. 我如何大胆领域?有关/ Helv 10 Tf 0 g排列顺序的任何文件?我需要设置哪些大胆的字段?
  2. 如果我理解正确的话,我可以在开箱即用的PDFBox中使用14种基本字体(双关语意外)。我想使用一个或多个看起来像Signatures(草书)的字体。任何开箱即用的字体都可以吗?如果没有,如果我有自己的字体,如何设置要写入PDF的方法?
  3. 请注意,以下代码可以通过填充方法参数的特定“名称”字段中方法参数中传递的特定“值”来正常工作。

    谢谢!

    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中使用两种字体,我使用了以下方法:我无法获得默认字体和自定义字体一起工作,因此我在资源中添加了两种字体并使用它们。 / p>

    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 个答案:

答案 0 :(得分:14)

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

使用穷人的大胆

  
      
  1. 我如何大胆领域? ......我需要设置哪些大胆的字段?
  2.   

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

2 Tr .5 w =使用渲染模式2,即填充和描边,并使用.5的线宽

而不是

Using the OP's method

你现在得到了

Using the setFieldBold method

使用自定义字体

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

如果您想使用自己的字体,首先需要在 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);
    }
}

你现在得到了

Using the setFieldBold method with font parameter

差异不是太大,因为字体非常相似。使用您选择的字体可以获得更好的效果。

使用 / Helv / HeBo ,......

OP发现了一个字体名称列表 / Helv / HeBo ,...,可能在PDFBox问题PDFBOX-1234中,似乎是可用,无需在任何资源字典中定义它们。

这些名称不是PDF功能,相反,PDF规范不了解它们,相反:

  

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

     

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

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

尽管如此,Adobe Reader / Acrobat似乎支持它们,很可能是因为在遥远的过去的某个时间,某些表单生成工具假定它们存在并且由于兼容性原因而保留了对这些表单的支持。

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

使用自定义和标准字体

在他的评论中,OP表示他想在表格中使用自定义和标准字体。

为此,我稍微概括了方法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)

导致

Using mixed custom and standard fonts

PDType1Font具有所有14种标准字体的常量。因此,像这样你可以在表单字段中使用标准字体(如果需要,与自定义字体混合),在默认资源中生成正确的字体条目,即不依赖于专有的默认字体名称,如的荷波

PS

  

有关/ Helv 10 Tf 0 g排列顺序的任何文件吗?

是的,有,参见规范ISO 32000-1