Java PDFBox 为 PDF 表单中的一些字段设置自定义字体
Java PDFBox setting custom font for a few fields in PDF Form
我正在使用 Apache PDFBox 读取可填写的 PDF 表单并根据一些数据填写字段。我正在使用下面的代码(根据其他 SO 答案的建议)获取默认外观字符串并更改它(如下所示,如果字段名称为 [=27=,我将字体大小从 10 更改为 12 ].
- 如何加粗字段?关于 /Helv 10 Tf 0 g 排列顺序的任何文档?我需要设置什么来加粗字段?
- 如果我没理解错的话,我可以在 PDFBox 中使用 14 种开箱即用的基本字体(双关语意想不到的)。我想使用一种或多种看起来像签名(草书)的字体。任何开箱即用的字体吗?如果没有,如果我有自己的字体,在写入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;
}
(您可以在此处找到可运行的示例:FillFormCustomFont.java)
使用穷人的粗体
- How do I bold the field? ... What I need to set to bold the field?
在 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 的线宽)
而不是
你现在得到
使用自定义字体
- 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?
如果您想使用自己的字体,首先需要在 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;
}
此方法returns要在
中使用的字体名称
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);
}
}
你现在得到
区别不是很大,因为字体很相似。使用您选择的字体以获得更多效果。
使用/Helv, /HeBo, ...
OP 找到了字体名称列表 /Helv, /HeBo, ..., 可能在 PDFBox 问题中 PDFBOX-1234,似乎无需在任何资源字典中定义它们就可以使用。
这些名称不是 PDF 功能,即 PDF 规范不知道它们,相反:
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)
因此,规范不知道那些默认字体名称。
尽管如此,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.
PS
Any documentation on what order the /Helv 10 Tf 0 g are arranged?
是的,有,比照。规格 ISO 32000-1.
我正在使用 Apache PDFBox 读取可填写的 PDF 表单并根据一些数据填写字段。我正在使用下面的代码(根据其他 SO 答案的建议)获取默认外观字符串并更改它(如下所示,如果字段名称为 [=27=,我将字体大小从 10 更改为 12 ].
- 如何加粗字段?关于 /Helv 10 Tf 0 g 排列顺序的任何文档?我需要设置什么来加粗字段?
- 如果我没理解错的话,我可以在 PDFBox 中使用 14 种开箱即用的基本字体(双关语意想不到的)。我想使用一种或多种看起来像签名(草书)的字体。任何开箱即用的字体吗?如果没有,如果我有自己的字体,在写入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;
}
(您可以在此处找到可运行的示例:FillFormCustomFont.java)
使用穷人的粗体
- How do I bold the field? ... What I need to set to bold the field?
在 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 的线宽)
而不是
你现在得到
使用自定义字体
- 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?
如果您想使用自己的字体,首先需要在 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;
}
此方法returns要在
中使用的字体名称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);
}
}
你现在得到
区别不是很大,因为字体很相似。使用您选择的字体以获得更多效果。
使用/Helv, /HeBo, ...
OP 找到了字体名称列表 /Helv, /HeBo, ..., 可能在 PDFBox 问题中 PDFBOX-1234,似乎无需在任何资源字典中定义它们就可以使用。
这些名称不是 PDF 功能,即 PDF 规范不知道它们,相反:
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)
因此,规范不知道那些默认字体名称。
尽管如此,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.
PS
Any documentation on what order the /Helv 10 Tf 0 g are arranged?
是的,有,比照。规格 ISO 32000-1.