You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在PDFBox操作AcroForm表单时正确使用TTF字体并完成文档展平?

Fix Font Loss When Flattening PDF Form Fields with PDFBox

Hey there, let's tackle this font issue you're facing. The core problem here is that when you update form fields and flatten the PDF with PDFBox, the tool isn't properly picking up the embedded fonts from your original LibreOffice-generated PDF. Your initial attempt added a default font resource, but missed loading both required fonts and refreshing individual field appearances—two critical steps.

Step-by-Step Solution

Here's a revised code implementation that addresses these gaps, ensuring your custom fonts stay embedded after flattening:

Corrected Code

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.cos.COSName;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

public class PdfFormModifier {
    public static void main(String[] args) {
        try (PDDocument doc = PDDocument.load(new File("/media/stoyank/Elements/Java/tmp/Receipt.pdf"))) {
            PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
            if (acroForm == null) {
                System.err.println("No AcroForm found in the document");
                return;
            }

            // Set up form resources and load both required fonts
            PDResources resources = acroForm.getDefaultResources();
            if (resources == null) {
                resources = new PDResources();
            }

            // Load SF Pro Text Light (for all fields except tbxTotal)
            try (InputStream sfProStream = ClassLoader.getSystemResourceAsStream("SF-Pro-Text-Light.ttf")) {
                if (sfProStream == null) {
                    System.err.println("Couldn't locate SF-Pro-Text-Light.ttf");
                    return;
                }
                PDType0Font sfProFont = PDType0Font.load(doc, sfProStream, false);
                resources.put(COSName.getPDFName("SFProTextLight"), sfProFont);
            }

            // Load Oswald Regular (for tbxTotal)
            try (InputStream oswaldStream = ClassLoader.getSystemResourceAsStream("Oswald-Regular.ttf")) {
                if (oswaldStream == null) {
                    System.err.println("Couldn't locate Oswald-Regular.ttf");
                    return;
                }
                PDType0Font oswaldFont = PDType0Font.load(doc, oswaldStream, false);
                resources.put(COSName.getPDFName("Oswald-Regular"), oswaldFont);
            }

            acroForm.setDefaultResources(resources);

            // Update fields and refresh individual appearances
            PDField orderIdField = acroForm.getField("tbxOrderId");
            if (orderIdField != null) {
                orderIdField.setValue("192753");
                orderIdField.refreshAppearance(); // Critical: Refresh this field's look
            }

            PDField totalField = acroForm.getField("tbxTotal");
            if (totalField != null) {
                totalField.setValue("Total: €192.00");
                totalField.refreshAppearance(); // Critical for Oswald font to apply
            }

            // Flatten and save
            acroForm.flatten();
            doc.save("/media/stoyank/Elements/Java/tmp/output.pdf");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Key Fixes & Notes

  1. Load Both Fonts: Your original code only added Oswald, but you need to load both SF Pro Text Light and Oswald Regular since different fields use different fonts.
  2. Refresh Individual Field Appearances: Calling refreshAppearance() on each modified field ensures PDFBox regenerates the field's visual using the correct font from your resources. The AcroForm-level refreshAppearances() doesn't always handle this reliably for individual fields.
  3. Font Path Validation: Double-check your font file paths. If classloader resources aren't working, use absolute file paths (e.g., new FileInputStream("/home/youruser/fonts/SF-Pro-Text-Light.ttf")) to test.
  4. Font Name Matching: Make sure the names you use in COSName.getPDFName() match the font references in your original PDF. You can inspect the original PDF's field dictionaries with a tool like PDFBox Debugger to confirm the exact font names used.
  5. Euro Symbol Support: Using PDType0Font ensures proper handling of extended characters like the euro (€), which might fail with older font loading methods.

Verify the Fix

After running the code, use pdffonts to check the output PDF:

pdffonts /media/stoyank/Elements/Java/tmp/output.pdf

You should see both SF Pro Text Light and Oswald Regular listed with emb set to yes, confirming they're embedded correctly.

内容的提问来源于stack exchange,提问作者S. Kostadinov

火山引擎 最新活动