我正在使用 Apache PDFBox 读取可填写的 PDF 表单并根据一些数据填充字段。我正在使用下面的代码(根据其他 SO 答案的建议)来获取默认的外观字符串并更改它(如下所示,如果字段名称为“Field1”,我会将字体大小从 10 更改为 12。
请注意,通过将方法参数中传递的特定“值”填充到方法参数的特定“名称”字段中,以下代码可以正常工作。
谢谢你!
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;
}
(您可以在这里找到可运行的示例:FillFormCustomFont.java)
- 如何加粗该字段? ...我需要设置什么才能使字段加粗?
在 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,即填充和描边,并使用 0.5 的线宽)
而不是
你现在得到了
- 如果我没理解错的话,我可以在 PDFBox 中开箱即用地使用 14 种基本字体(双关语无意)。我想使用一种或多种看起来像签名(草书)的字体。有任何开箱即用的字体可以做到这一点吗?如果没有,如果我有自己的字体,如何在方法中设置写入PDF?
如果你想使用自己的字体,你首先需要在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);
}
}
你现在得到了
差异不是太大,因为字体非常相似。使用您选择的字体以获得更多效果。
OP 发现了字体名称列表 /Helv、/HeBo,...,可能在 PDFBox 问题 PDFBOX-1234 中,这些字体名称似乎无需在任何资源字典中定义即可使用。
这些名称不是 PDF 功能,即 PDF 规范不知道它们,相反:
默认外观字符串 (DA) 包含建立图形状态参数所需的任何图形状态或文本状态运算符,例如文本大小和颜色,以显示字段的可变文本。只有文本对象中允许的运算符才应出现在该字符串中(参见图 9)。字符串至少应包含一个 Tf(文本字体)运算符及其两个操作数:字体和大小。 指定的字体值应与默认资源字典的Font条目中的资源名称匹配(从交互式表单字典的DR条目引用;参见表218)。
(ISO 32000-1 中的第 12.7.3.3 节字段字典/变量文本)
因此,规范不知道那些默认字体名称。
尽管如此,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)
导致
PDType1Font
具有所有 14 种标准字体的常量。因此,像这样,您可以在表单字段中使用标准字体(如果需要,可以与自定义字体混合),从而在默认资源中生成正确的 Font 条目,即不依赖于像 HeBo 这样的专有默认字体名称。
有关于 /Helv 10 Tf 0 g 排列顺序的任何文档吗?
是的,有,参见。规范 ISO 32000-1。