PDFBox填充PDF表单字段时文本挤压变形问题求助
解决PDF表单字段填充后文本挤压变形问题
依赖版本
[INFO] +- com.openhtmltopdf:openhtmltopdf-core:jar:1.0.10:compile [INFO] +- com.openhtmltopdf:openhtmltopdf-pdfbox:jar:1.0.10:compile [INFO] | +- org.apache.pdfbox:pdfbox:jar:2.0.24:compile [INFO] | | +- org.apache.pdfbox:fontbox:jar:2.0.24:compile [INFO] | +- org.apache.pdfbox:xmpbox:jar:2.0.24:compile
问题现象
使用上述依赖填充PDF表单字段后,生成的PDF中字段文本出现横向挤压变形:
- 移除
acroForm.flatten()后,点击字段时文本显示正常,但点击PDF其他区域后又变回挤压状态 - 尝试添加
acroForm.setNeedAppearances(true)和acroForm.refreshAppearances()(单独或组合)均未解决问题
手动在Acrobat Reader中输入相同文本时,字体宽度正常,无挤压变形。
现有填充代码
private void populateFieldsWithData(Map<String, String> data, PDAcroForm acroForm, List<PDField> fields) throws IOException { data.forEach((key, value) -> { PDField field = acroForm.getField(key); acroForm.getFieldTree().iterator().forEachRemaining(pdField -> { if (pdField.getFullyQualifiedName().equals(key)) { try { field.setValue(value); field.setReadOnly(true); fields.add(pdField); } catch (IOException e) { throw new RuntimeException(e); } } }); }); acroForm.flatten(); }
解决方案
代码优化方案
核心问题在于原代码的字段引用不一致,且未手动生成可靠的字段外观。修改后的代码如下:
private void populateFieldsWithData(Map<String, String> data, PDAcroForm acroForm, List<PDField> fields) throws IOException { // 禁用阅读器动态生成外观,使用我们手动生成的外观 acroForm.setNeedAppearances(false); for (Map.Entry<String, String> entry : data.entrySet()) { String fieldName = entry.getKey(); String fieldValue = entry.getValue(); // 遍历字段树找到目标字段,避免重复查找 for (PDField pdField : acroForm.getFieldTree()) { if (pdField.getFullyQualifiedName().equals(fieldName)) { pdField.setValue(fieldValue); pdField.setReadOnly(true); // 手动生成字段外观,确保文本显示正常 pdField.generateAppearances(); fields.add(pdField); break; // 找到目标字段后跳出循环,提升效率 } } } // 全局刷新所有字段外观后再执行扁平化 acroForm.refreshAppearances(); acroForm.flatten(); }
关键优化点说明
- 统一字段引用:直接使用遍历字段树得到的
pdField进行操作,避免原代码中acroForm.getField(key)和遍历结果的引用不一致问题 - 禁用动态外观生成:设置
acroForm.setNeedAppearances(false),强制PDF使用我们生成的静态外观,避免阅读器动态渲染导致的变形 - 手动生成字段外观:调用
pdField.generateAppearances()为每个字段生成独立的正确外观,解决文本挤压问题 - 调整扁平化时机:确保所有字段外观都生成并全局刷新后,再执行
flatten()操作
额外排查方向
如果上述方案仍未解决问题,可进一步检查:
- 表单字段的原始字体设置:确保填充时使用的字体与表单字段默认字体一致,可通过
pdField.getDefaultAppearance()获取并确认字体参数 - 字段的宽度设置:检查表单字段的宽度是否足够容纳输入文本,避免因字段宽度不足导致的自动挤压
内容的提问来源于stack exchange,提问作者user1766169
相关产品推荐
相关产品推荐

