在 java 中转换 PDF 文件版本(不仅是标题版本!)

Posted

技术标签:

【中文标题】在 java 中转换 PDF 文件版本(不仅是标题版本!)【英文标题】:Convert PDF file version in java (not only header version!) 【发布时间】:2021-11-14 19:22:24 【问题描述】:

我正在尝试将 PDF 1.3 版转换为 PDF 1.5 版或更高版本。这里的挑战是:我不想像几乎所有论坛一样只更改标题版本。我想更改所有文件版本。

我读过这个主题:convert PDF to an older version from a servlet?,但首先是 iTextPdf 7 的新版本,不支持 PdfStamper,所以我跳过它。

我想我需要创建一个 TMP 文件,将 PDF 写入 TMP,用 TMP 替换原始文件并删除 TMP。但是我如何在 JAVA 中做到这一点?

此代码仅转换 HEADER 版本!我使用 Itext 版本 7。

WriterProperties wp = new WriterProperties();

wp.setPdfVersion(PdfVersion.PDF_1_7);

PdfDocument pdfDoc = new PdfDocument(new PdfReader("source"), new PdfWriter("destination", wp));

pdfDoc.close();

有什么建议吗?

图片来自 Firefox (PDF v 1.3) picture: no text available

在这里您可以下载 pdf 样本:https://wetransfer.com/downloads/ce2d2f41ac29c36baa2ac895ebc0473c20210922065257/5889b2

【问题讨论】:

AFAIK PDF 向后兼容,因此标题更新为 1.5 的有效 1.3 文件是有效的 1.5 文件。为什么要重写整个文件?这听起来像XY problem。 “此代码仅转换 HEADER 版本!我使用 Itext 版本 7。” - 正如@Joachim 所说,PDF 大多是向后兼容的。即使不更改标题,有效的 1.3 PDF 文件通常也已经是有效的 1.4、1.5、1.6 和 1.7 PDF 文件。 Tnx 伙计们!但是如果你想在 Firefox 中打开 PDF 1.3,你就无法打开它!所以我们有一些客户使用 Firefox 打开 PDF 格式。 Firefox 只支持 1.5 及以上 :( 请分享一个 Firefox 不支持的 PDF 1.3。我们可以尝试分析一下,找出FF中的错误是什么。 【参考方案1】:

无需将 PDF 1.3 版转换为 PDF 1.5 版或更高版本,因为 PDF 旨在向后兼容。因此,每个 PDF 1.3 文件也已经是一个 PDF 1.4 文件。以及一份 PDF 1.5 文档。和一个 PDF 1.6 文档。 ...

在评论中,您解释了为什么仍然要更改版本:

但是如果你想在 Firefox 中打开 PDF 1.3,你就无法打开它!所以我们有一些客户使用 Firefox 打开 PDF 格式。 Firefox 仅支持 1.5 及以上版本

鉴于上面讨论的兼容性,这是没有意义的。但有时程序会以荒谬的方式运行。因此,我对此进行了测试。

结果:我在此处安装的 Firefox 87.0接受我在文档中找到的 PDF 1.3 和 PDF 1.4 文件,没有任何问题!

很遗憾,我这里没有任何 PDF 1.2(或更早版本)文件,因此我无法检查对此类文件的支持。

所以,恐怕你得回头去分析你的客户遇到的问题,不是“火狐只支持1.5及以上”那么简单。

(一些想法:也许您的 PDF 1.3 文件实际上已损坏,因此 Firefox 无法打开它们;它们可能已经在您这边损坏了,或者在传输给您的客户时可能会损坏。或者您的客户可能有一些较旧的 Firefox 版本,其 PDF 查看器中存在一些错误。)

解决实际问题

在这里的 cmets 中,OP 提供了示例文件。分析他们发现,实际问题是Firefox无法正确确定嵌入字体的内置编码。

为了帮助 Firefox 在这方面,我们可以提供一个显式的基本编码,因此 Firefox 不需要内置编码。

当您在问题中使用 iText 7 时,这里是使用您的示例 PDF 的概念验证:

try (   PdfReader pdfReader = new PdfReader("1100-SD-9000455596.pdf");
        PdfWriter pdfWriter = new PdfWriter("1100-SD-9000455596-Fixed.pdf");
        PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter) ) 
    for (int page = 1; page <= pdfDocument.getNumberOfPages(); page++) 
        PdfPage pdfPage = pdfDocument.getPage(page);
        PdfResources pdfResources = pdfPage.getResources();
        for (Entry<PdfName, PdfObject> fontEntry : pdfResources.getResource(PdfName.Font).entrySet()) 
            PdfObject fontObject = fontEntry.getValue();
            if (fontObject != null && fontObject.getType() == PdfObject.INDIRECT_REFERENCE) 
                fontObject = ((PdfIndirectReference)fontObject).getRefersTo(true);
            
            if (fontObject instanceof PdfDictionary) 
                PdfDictionary fontDictionary = (PdfDictionary) fontObject;
                PdfDictionary encodingDictionary = fontDictionary.getAsDictionary(PdfName.Encoding);
                if (encodingDictionary != null) 
                    if (encodingDictionary.getAsName(PdfName.BaseEncoding) == null &&
                            encodingDictionary.getAsArray(PdfName.Differences) != null) 
                        encodingDictionary.put(PdfName.BaseEncoding, PdfName.WinAnsiEncoding);
                    
                
            
        
    

(FixForFirefox 测试testFix1100_SD_9000455596)

【讨论】:

谢谢mkl的回答!好吧,问题出在版本中。我敢肯定,因为如果我用 Adob​​e 阅读器(或任何开源 pdf 阅读器)打开 PDF,它会正常打开。但是当我想在Firefox中打开时,它打开PDF但没有文本。当我在一些 pdf EDITOR 中打开 PDF 并保存它时。然后我可以正常在Firefox中打开它。但保存后,设置了新版本(从 1.3 到 1.6)。 @BlazCus 这并不一定表明版本是罪魁祸首。另一种可能性是保存 PDF 会将一些损坏或非标准数据(显然 Acrobat 可以处理)更改为 Firefox 可以正确打开的更正确或标准的数据。 好吧,如果它无效,那它尤其无效.. ;) 但本质上,是的,它是无效的。 @mkl 你的代码对我有用!!谢谢!! @mkl 完成!再次感谢!

以上是关于在 java 中转换 PDF 文件版本(不仅是标题版本!)的主要内容,如果未能解决你的问题,请参考以下文章

Java 转换 PDF 版本

将任何版本的 PDF 转换为扫描/展平 PDF 文件的最佳方法

iText PDF;如何使用 Java 将 jpeg2000 转换为 jpg

wps支持linux下java文档转换成pdf吗

在linux环境下,java怎么实现从word格式转换为pdf格式

将扫描的 pdf 文件转换为可文本搜索的 pdf 文件