【问题标题】:How to change the filter of an image in a PDF file如何更改 PDF 文件中图像的过滤器
【发布时间】:2019-09-17 10:53:23
【问题描述】:

我正在构建一个压缩 PDF 文件的工具,并使用 pdfbox。 我有一些使用DCTDecode + FlateDecode 过滤器的图像,我想尝试使用JPXDecode 过滤器,看看它是否占用更少的空间。

我已经看到了一些使用iText 的代码,但是如何使用pdfbox 呢?我没有找到如何执行此操作的文档。

【问题讨论】:

  • 我试过但失败了:1) Adob​​e 不接受我的文件 2) PDFBox 显示它但颜色错误 3) 我查看了生成的 JPEG2000 图像文件,它看起来很糟糕,颜色是错了,我怀疑编码器有bug。
  • 谢谢,那么我没有其他选择可以使用iText 或其他解决方案。
  • 就其价值而言,根据我的经验,JPEG 对“小”图像占用的字节更少,而 JPEG2000 为“更大”图像提供更好的压缩。
  • 我的 PDF 文件通常是扫描页面,而且很大。
  • 是否有关于如何将FlateDecode 过滤器添加到图像的示例?它似乎提高了压缩率。

标签: java image pdf pdfbox jpeg2000


【解决方案1】:

此代码无需更改 COSWriter 即可替换图像流(这听起来很可怕),但是我尝试使用 PDF 的经验是编码的图像不正确,即 JPEG 2000 编码器中存在错误,因此请检查您的结果 PDF。

public class SO57972743
{
    public static void main(String[] args) throws IOException
    {
        System.out.println("supported formats: " + Arrays.toString(ImageIO.getReaderFormatNames()));

        try (PDDocument doc = PDDocument.load(new File("test.pdf")))
        {
            // get 1st level images only here (there may be more in form XObjects!)
            PDResources res = doc.getPage(0).getResources();
            for (COSName name : res.getXObjectNames())
            {
                PDXObject xObject = res.getXObject(name);
                if (xObject instanceof PDImageXObject)
                {
                    replaceImageWithJPX(xObject);
                }
            }
            doc.save("test-result.pdf");
        }
    }

    private static void replaceImageWithJPX(PDXObject xObject) throws IOException
    {
        PDImageXObject img = (PDImageXObject) xObject;
        BufferedImage bim = img.getOpaqueImage(); // the mask (if there) won't be touched
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        boolean written = ImageIO.write(bim, "JPEG2000", baos);
        if (!written)
        {
            System.err.println("write failed");
            return;
        }
        // replace image stream
        try (OutputStream os = img.getCOSObject().createRawOutputStream())
        {
            os.write(baos.toByteArray());
        }
        img.getCOSObject().setItem(COSName.FILTER, COSName.JPX_DECODE); // replace filter
        img.getCOSObject().removeItem(COSName.COLORSPACE); // use the colorspace in the image itself
    }
}

【讨论】:

  • 我没有重新实现完整的COSWriter,只是从它派生并覆盖处理流的方法。你的解决方案似乎比我的简单。
【解决方案2】:

使用pdfbox 可以压缩所有图像,方法是使用自定义COSWriter 处理所有图像流并使用JPXDecode 过滤器重新编码它们。 pdfbox 不能这样做,但是带有插件的 JAI 库可以生成 JPEG2000 图像。压缩因子是可配置的,可以在不损失太多质量的情况下实现高压缩比。

通过另外使用FlateDecode 过滤器,可以获得更多的压缩而不损失质量。

【讨论】:

    猜你喜欢
    • 2020-02-03
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-11
    • 1970-01-01
    • 2022-09-29
    • 2011-09-03
    相关资源
    最近更新 更多