如何使用pdfbox 3.0.0减小合并PDF文件的大小

问题描述 投票:0回答:1

我正在使用 PDFBox 3.0.0 和 java 17 来合并许多 PDF 文档。

要合并的文件源预先使用 GhostScript 从一些普通 PDF 转换为每页都有图像的 PDF。每个 PDF 的每一页都是使用 Ghostscript 转换 PDF 后的图像。

有时我会合并相同的文件。 例如,我想再次合并 input-gs.pdf、input2-gs.pdf 和第一个文件 input-gs.pdf。

当我合并这些文件时,输出的大小很大并且没有优化。

我想减小合并后的PDF文件的大小,我正在寻找是否可以在字典中的所有PDF中使用一次相同的图像,并使用其参考而不需要对内存中的所有图像进行充电。

我搜索是否有解决方案为最终合并的 PDF 中的每个图像设置键或唯一名称,并在稍后使用这些图像的名称或引用来再次合并同一文件。

 private static void mergeFiles() throws IOException {
    RandomAccessStreamCache.StreamCacheCreateFunction streamCache =
        IOUtils.createMemoryOnlyStreamCache();
    PDDocument emptyDocument = createBlankValidDocument();
    
    PDFMergerUtility pdfMergerUtility = new PDFMergerUtility();
    pdfMergerUtility.setDocumentMergeMode(
        PDFMergerUtility.DocumentMergeMode.OPTIMIZE_RESOURCES_MODE);
    pdfMergerUtility.setAcroFormMergeMode(PDFMergerUtility.AcroFormMergeMode.JOIN_FORM_FIELDS_MODE);

    appendFile("input-gs.pdf", streamCache, emptyDocument, pdfMergerUtility);
    appendFile("input2-gs.pdf", streamCache, emptyDocument, pdfMergerUtility);
    appendFile("input-gs.pdf", streamCache, emptyDocument, pdfMergerUtility);

    emptyDocument.save("output-merged.pdf");
}

private static void appendFile(String filename,
                              RandomAccessStreamCache.StreamCacheCreateFunction streamCache,
                              PDDocument emptyDocument,
                              PDFMergerUtility pdfMergerUtility) throws IOException {
    File file = new File(filename);
    PDDocument document = Loader.loadPDF(new RandomAccessReadBuffer(new FileInputStream(file)),
                                         streamCache);
    pdfMergerUtility.appendDocument(emptyDocument, document);
}

public static PDDocument createBlankValidDocument() {
    try {
        RandomAccessStreamCache.StreamCacheCreateFunction streamCache =
            IOUtils.createMemoryOnlyStreamCache();
        PDDocument document = new PDDocument(streamCache);

        // Conformance level + Part
        XMPMetadata xmp = XMPMetadata.createXMPMetadata();
        PDFAIdentificationSchema id = xmp.createAndAddPDFAIdentificationSchema();
        id.setConformance("A");
        id.setPart(1);

        // Metadata
        setMetadata(document, xmp);
        
        return document;
    } catch (Exception e) {

    }
    return null;
}
private static void setMetadata(PDDocument document, XMPMetadata xmp)
    throws TransformerException, IOException {
    PDDocumentCatalog catalogue = document.getDocumentCatalog();
    XmpSerializer serializer = new XmpSerializer();
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    serializer.serialize(xmp, outputStream, true);

    PDMetadata metadata = new PDMetadata(document);
    metadata.importXMPMetadata(outputStream.toByteArray());
    catalogue.setMetadata(metadata);
}

我在这篇文章中找到了一个代码如何使用pdfbox或其他java库减少合并的PDF/A-1b文件的大小搜索文件中的复杂对象并合并它,我希望如果可能的话找到一个解决方案不要使用大量内存,因为有时我会有 100 个包含很多页面的文件。

提前谢谢您。

pdf optimization memory pdfbox
1个回答
0
投票

如果,正如您所说,您正在重复使用相同的文件(或同一文件中的页面),那么生成的图像对象应该是相同的。

在你的输出上尝试

cpdf -squeeze out.pdf -o out2.pdf
,以检验这个假设。如果确实发生了这种情况,相同的对象将被合并,并且大小将减小到您期望的大小。

(顺便说一句,如果您多次使用文件中的范围,Cpdf 的合并应该正确共享数据。例如,

cpdf a.pdf 1-3 b.pdf a.pdf 1-10 c.pdf
应该仅包含 a.pdf 第 1-3 页的内容一次,即使这些页面出现输出中的两次)。

© www.soinside.com 2019 - 2024. All rights reserved.