You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PDFBox生成PDF在pdf.js中部分符号渲染异常问题排查

PDFBox生成的PDF在pdf.js中无法正确渲染反引号、单引号等符号

我使用PDFBox生成PDF文件后,在Firefox浏览器的pdf.js中查看时,文本字段内的反引号(`)和单引号(')等符号无法正确渲染,但在Acrobat和Chrome浏览器中显示完全正常。我分别测试了嵌入Poppins字体和Arial字体的PDF文件,二者均出现相同的异常表现。

显示效果对比

  • Acrobat中的正常显示:
    Acrobat显示
  • pdf.js中的异常显示:
    pdf.js显示

我不确定这是pdf.js的固有限制,还是我生成PDF的代码存在问题,希望能确认问题根源。

相关代码

创建文本框的代码

public static void createTextbox(PDDocument doc, int pageIndex, PDRectangle rect, String fieldName, String fontPath) throws Exception {
    PDPage page = doc.getPage(pageIndex);

    // Add a new AcroForm and add that to the document
    PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
    if (acroForm == null) {
        acroForm = new PDAcroForm(doc);
        doc.getDocumentCatalog().setAcroForm(acroForm);
    }
    
    if(acroForm.getFields() instanceof AbstractList){
        acroForm.setFields(new ArrayList<>());
    }
    
    PDResources resources = new PDResources();
    acroForm.setDefaultResources(resources);

    // set custom font here, else the non embeded HELV will be used when u call to setNeedAppearances(true)
    PDType0Font f = PDType0Font.load(doc, new File(fontPath));
    String customFontNameToMatch = f.getFontDescriptor().getFontName();

    String fontName = null;
    PDFont customFont = null;

    Iterator<COSName> fontIte = acroForm.getDefaultResources().getFontNames().iterator();
    while(fontIte.hasNext()){
        COSName fcn = fontIte.next();
        if(acroForm.getDefaultResources().getFont(fcn).getName().equals(customFontNameToMatch)){
            fontName = fcn.getName();
            customFont = acroForm.getDefaultResources().getFont(fcn);
            break;
        }
    }

    // font not embedded, embed it
    if (fontName == null){
        customFont = PDTrueTypeFont.load(doc, new File(fontPath), StandardEncoding.INSTANCE);
        fontName = acroForm.getDefaultResources().add(customFont).getName();
    }

    String defApp = String.format("/%s 0 Tf 0 0 0 rg", fontName);
    
    // Add a form field to the form.
    PDTextField textBox = new PDTextField(acroForm);
    textBox.setPartialName(fieldName);
    textBox.setReadOnly(true);
    textBox.setDefaultAppearance(defApp);
    textBox.setMultiline(true);

    // Specify the widget annotation associated with the field
    PDAnnotationWidget widget = textBox.getWidgets().get(0);
    widget.setRectangle(rect);
    widget.setPage(page);
    widget.getCOSObject().setNeedToBeUpdated(true);
    
    acroForm.setNeedAppearances(true);

    // make sure the widget annotation is visible on screen and paper
    widget.setPrinted(true);

    // Add the widget annotation to the page
    page.getAnnotations().add(widget);
    // set the alignment ("quadding")
    textBox.setQ(PDVariableText.QUADDING_LEFT);
    
    textBox.setDoNotScroll(true);
    
    textBox.getCOSObject().setNeedToBeUpdated(true);

    acroForm.getFields().add(textBox);
    acroForm.getCOSObject().setNeedToBeUpdated(true);
    
    page.getCOSObject().setNeedToBeUpdated(true);
}

调用createTextbox()后执行doc.saveIncremental(baos);

填充文本框的代码

public static void fillTextBox(PDDocument doc, String fieldName, String fontPath, String text) throws Exception {
    // get the document catalog
    PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
    
    // as there might not be an AcroForm entry a null check is necessary
    if (acroForm != null) {
        // Retrieve an individual field and set its value.
        PDTextField field = (PDTextField) acroForm.getField(fieldName);
        
        // set custom font
        PDType0Font f = PDType0Font.load(doc, new File(fontPath));
        String customFontNameToMatch = f.getFontDescriptor().getFontName();

        String fontName = null;
        PDFont customFont = null;

        Iterator<COSName> fontIte = acroForm.getDefaultResources().getFontNames().iterator();
        while(fontIte.hasNext()){
            COSName fcn = fontIte.next();
            if(acroForm.getDefaultResources().getFont(fcn).getName().equals(customFontNameToMatch)){
                fontName = fcn.getName();
                customFont = acroForm.getDefaultResources().getFont(fcn);
                break;
            }
        }

        // font not embedded, embed it
        if (fontName == null){
            customFont = PDTrueTypeFont.load(doc, new File(fontPath), StandardEncoding.INSTANCE);
            fontName = acroForm.getDefaultResources().add(customFont).getName();
        }

        String defApp = String.format("/%s 0 Tf 0 0 0 rg", fontName);

        field.setDefaultAppearance(defApp);
        field.setMultiline(true);
        field.setReadOnly(true);
        field.setValue(text);
        
        PDAnnotationWidget widget = field.getWidgets().get(0);
        widget.setReadOnly(true);
        widget.setLocked(true);
        widget.getCOSObject().setNeedToBeUpdated(true);
    }
}

调用fillTextBox()后执行doc.saveIncremental(baos);

使用的依赖版本

  • pdfbox(Maven):3.0.4
  • Java版本:21

内容的提问来源于stack exchange,提问作者rec7y33

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 21:19:51