gpt4 book ai didi

java - 使用 PDFBox 嵌入字体以扁平化 PDF 表单

转载 作者:行者123 更新时间:2023-12-02 01:44:02 28 4
gpt4 key购买 nike

我使用 PDFBox 填写 PDF 表单,在保存之前将其压平。该表单具有用于文本和表单字段的自定义字体。当我在未安装此自定义字体的设备上打开输出文档(带有扁平化字段)时,普通文本的字体仍然正确,但扁平化字段的字体以后备(?)字体显示。在安装了此自定义字体的设备上,一切看起来都符合预期。

有没有办法在展平表单后强制对所有文本使用相同的自定义字体?

用于使用 PDFBox 填写 PDF 表单的代码(简化):

public class App
{
public static void main(String[] args) throws IOException {
String formTemplate = "src/main/resources/fonts.pdf";
String filledForm = "src/main/resources/fonts_out.pdf";
PDDocument pdfDocument = PDDocument.load(new File(formTemplate));
PDAcroForm acroForm = pdfDocument.getDocumentCatalog().getAcroForm();
acroForm.getField("text").setValue("Same font in form text field (updated with PDFBox)");
acroForm.setNeedAppearances(true);
acroForm.refreshAppearances();
acroForm.flatten();
pdfDocument.save(filledForm);
pdfDocument.close();
}
}

PDF: Input Output

预期:

Expected

系统未安装字体时的结果:

Result when font is not installed on system

最佳答案

对 PDF 的一些观察(上述编码问题都不是 - 只是我的无知):

  1. SansDroid 字体未嵌入到 PDF 中。通过将 F2 字体替换为新嵌入的 F5 字体即可解决此问题。

  2. NeedAppearances 标志已设置,表示表单字段没有外观。任何读者都必须(重新)创建它们。在展平之前,PDFBox 不会自动完成此操作,因此我添加了这部分

  3. 为了不再发出有关丢失字体的警告,我完全删除了 F2 字体。

  4. 我通过预检运行原始 PDF,它给了我以下警告:“缺少所需的键/Subtype。路径:->Pages->Kids->[0]->Annots->[0]->AP->N "该键确实存在,但似乎表明表单字段的外观存在错误。如果我删除/N 字典,错误就会消失。流是“/Tx BMC EMC” - 也许缺少一些 EOL?但由于无论如何都会重新生成外观,因此错误随后就消失了。

使用以下代码将 DroidSans 字体嵌入到 PDF 中:

File pdf = new File("Fonts.pdf");
final PDDocument document = PDDocument.load(pdf);

FileInputStream fontFile = new FileInputStream(new File("DroidSans.ttf"));
PDFont font = PDType0Font.load(document, fontFile, false);

//1. embedd and register the font (Catalog dict)
PDAcroForm pDAcroForm = document.getDocumentCatalog().getAcroForm();
//create a new font resource
PDResources res = pDAcroForm.getDefaultResources();
if (res == null) res = new PDResources();
COSName fontName = res.add(font);
pDAcroForm.setDefaultResources(res);

//2. Now change the font of form field to the newly added font
PDField field = pDAcroForm.getField("text");
//field.setValue("Same font in form text field (updated with PDFBox)");

COSDictionary dict = field.getCOSObject();
COSString defaultAppearance = (COSString) dict.getDictionaryObject(COSName.DA);

if (defaultAppearance != null){
String currentValue = dict.getString(COSName.DA);
//replace the font - this should be improved with a more general version
dict.setString(COSName.DA,currentValue.replace("F2", fontName.getName()));

//remove F2 completely
COSDictionary resources = res.getCOSObject();
for(Entry<COSName, COSBase> resource : resources.entrySet()) {
if(resource.getKey().equals(COSName.FONT)) {
COSObject fonts = (COSObject)resource.getValue();
COSDictionary fontDict = (COSDictionary)fonts.getObject();

COSName toBeRemoved=null;
for(Entry<COSName, COSBase> item : fontDict.entrySet()) {
if(item.getKey().getName().equals("F2")) {
toBeRemoved = item.getKey();
}
}
if(toBeRemoved!=null) {
fontDict.removeItem(toBeRemoved);
}
}
}

if(pDAcroForm.getNeedAppearances()) {
pDAcroForm.refreshAppearances();
pDAcroForm.setNeedAppearances(false);
}

//Flatten the document
pDAcroForm.flatten();

//Save the document
document.save("Form-Test-Result.pdf");
document.close();

请注意,上面的代码是相当静态的 - 搜索和替换名为 F2 的字体仅适用于提供的 PDF,在其他情况下则无效。您必须为此实现一个更通用的解决方案......

关于java - 使用 PDFBox 嵌入字体以扁平化 PDF 表单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53968324/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com