使用PDFBox 2.0.24合并PDF时,如何移除重复嵌入的字体子集?
解决PDFBox合并PDF时重复嵌入字体子集的问题
一、手动控制PDFBox的字体资源复用
PDFBox默认合并逻辑不会严格复用相同字体子集,你可以自己写逻辑来复用:
- 遍历所有待合并PDF的页面,提取每个页面的字体,用字体名+字符集哈希作为唯一标识,把相同的字体实例存起来,后续页面遇到重复字体时直接复用,不再重复嵌入。
- 参考代码片段:
注意:要确保复用的字体包含所有需要的字符,不然可能出现乱码,测试时要重点检查特殊字符。PDDocument targetDoc = new PDDocument(); Map<String, PDFont> reusedFontMap = new HashMap<>(); for (String pdfPath : 你的PDF路径列表) { try (PDDocument sourceDoc = PDDocument.load(new File(pdfPath))) { for (PDPage page : sourceDoc.getPages()) { PDPage importedPage = targetDoc.importPage(page); PDResources pageResources = importedPage.getResources(); // 遍历页面字体资源 for (COSName fontName : pageResources.getFontNames()) { PDFont currentFont = pageResources.getFont(fontName); // 生成字体唯一标识,确保相同子集的字体能匹配 String fontKey = currentFont.getName() + "_" + currentFont.getFontDescriptor().getFontFile2().getCOSObject().getKey(); if (reusedFontMap.containsKey(fontKey)) { // 替换成已复用的字体 pageResources.put(fontName, reusedFontMap.get(fontKey)); } else { reusedFontMap.put(fontKey, currentFont); } } } } } targetDoc.save("合并后优化版.pdf"); targetDoc.close();
二、用PDFBox自带的优化器后处理
PDFBox有个PDFOptimizer工具,专门用来优化PDF体积,开启字体优化选项试试:
PDDocument mergedDoc = PDDocument.load(new File("合并后的大文件.pdf")); PDFOptimizer optimizer = new PDFOptimizer(); optimizer.setOptimizeFonts(true); // 打开字体优化开关 optimizer.optimize(mergedDoc); mergedDoc.save("优化后的文件.pdf"); mergedDoc.close();
这个工具会自动检测重复字体并合并,但如果你的文件是PDF/A格式,可能需要额外调整参数保证兼容性。
三、先预处理单个PDF
如果待合并的单个PDF本身就有冗余字体子集,可以先单独优化每个文件:
- 用PDFBox移除每个PDF里未被使用的字体子集,减少源文件的字体冗余:
其中try (PDDocument singleDoc = PDDocument.load(new File("单个PDF文件.pdf"))) { PDResources resources = singleDoc.getDocumentCatalog().getPages().get(0).getResources(); // 遍历字体,移除未被使用的 for (COSName fontName : new HashSet<>(resources.getFontNames())) { PDFont font = resources.getFont(fontName); if (!checkFontIsUsed(singleDoc, font)) { // 自己写方法判断字体是否被页面使用 resources.remove(fontName); } } singleDoc.save("预处理后的单个文件.pdf"); }checkFontIsUsed需要解析页面内容流,判断字体名称是否被引用,避免误删必要字体。
四、换用iText合并试试
如果PDFBox的方案都不管用,可以换iText 7.x版本来合并,它默认会自动复用相同字体子集,对重复字体的处理更成熟:
PdfWriter writer = new PdfWriter("合并后优化版.pdf"); PdfDocument mergedDoc = new PdfDocument(writer); PdfMerger merger = new PdfMerger(mergedDoc); for (String pdfPath : 你的PDF路径列表) { PdfDocument sourceDoc = new PdfDocument(new PdfReader(pdfPath)); merger.merge(sourceDoc, 1, sourceDoc.getNumberOfPages()); sourceDoc.close(); } mergedDoc.close();
内容的提问来源于stack exchange,提问作者ma hei pang
相关产品推荐
相关产品推荐

