首页 文章

iTextSharp能否生成具有多级滤波(DCTDecode和FlateDecode)的JPEG图像的PDF?

提问于
浏览
1

最近我的任务是减少从空白办公文档生成的PDF文件大小 .

图像大多是空白的,但它们有各种公司信头(彩色),边框和页脚 . 有些是由软件生成的(因此具有非常干净的像素),其他则由桌面扫描仪扫描 .

作为“空白”,我的意思是页面的中心部分(距离每个边距两英寸)将是绝对空白和白色 .

我的老板想要保持这些PDF的颜色,但不要介意让它们变得模糊,只要它们不是太难看 .

我已经测试了许多文件缩减方案:

  • 不同的颜色压缩方法(FlateDecode,LZWDecode,DCTDecode,...)

  • 不同的JPEG质量设置

  • 缩小JPEG的像素宽度和高度,仅在显示PDF时将其拉伸 .

  • 将图像内容切割成较小的图像块 .

到目前为止,我发现第三种方法(减少像素尺寸)比降低JPEG质量设置更有效(比如,将图像缩小50%而不是将质量从50降低到20)

然而,我从其他公司收集的一些样本PDF中找不到一种方法,就是有些人的JPEG图像是 multi-stage filtered . 我的意思是:

  • 过滤器名称是两个数组:/ DCTDecode,/ FlateDecode

  • 生成PDF时,首先应用JPEG压缩,然后是Deflated . 在查看PDF时,首先对数据进行膨胀,然后将JPEG解压缩为像素 .

我将解压缩的第一步(FlateDecode)应用于多阶段过滤数据,给出原始JPEG数据 . 我使用十六进制查看器来检查JPEG数据,发现在JPEG图像的空白区域中,大多数字节都是重复的模式 . 这解释了为什么在JPEG文件的顶部应用二次压缩是有利的 - 如果只有一个人知道JPEG图像大部分是空白的 .

显然这些PDF也是由iText创建的 . 但是,我不清楚是否有 iTextSharp.text.Image 类的实例支持这种两阶段过滤的组合 .

如果iText没有内置支持来创建这样的两阶段压缩图像,如果我处理两阶段压缩并使用像PdfImageObject这样的东西,是否可以插入图像?

1 回答

  • 1

    我创建了两个示例,一个可以使用当前的iText版本,一个只能用于下一个iText版本(因为我添加了一些功能) .

    这是最简单的方法(但只能从iText 5.5.1开始):

    Image img = Image.getInstance("some.jpg");
    img.setCompressionLevel(PdfStream.BEST_COMPRESSION);
    

    当您将JPEG传递给iText时,过滤器将为 /DCTDecode . 我已经重新使用现有的 setCompressionLevel() 方法,因为流也将被放气 . 您将在过滤器中有两个条目: /FlateDecode/DCTDecode . 这显示在FlateCompressJPEG1Pass示例中 .

    因为这需要一个没有't been officially released yet, I'的iText版本也创建了FlateCompressJPEG2Passes示例 .

    PdfReader reader = new PdfReader(src);
    // We assume that there's a single large picture on the first page
    PdfDictionary page = reader.getPageN(1);
    PdfDictionary resources = page.getAsDict(PdfName.RESOURCES);
    PdfDictionary xobjects = resources.getAsDict(PdfName.XOBJECT);
    PdfName imgName = xobjects.getKeys().iterator().next();
    PRStream imgStream = (PRStream)xobjects.getAsStream(imgName);
    imgStream.setData(PdfReader.getStreamBytesRaw(imgStream), true);
    PdfArray array = new PdfArray();
    array.add(PdfName.FLATEDECODE);
    array.add(PdfName.DCTDECODE);
    imgStream.put(PdfName.FILTER, array);
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
    stamper.close();
    reader.close();
    

    此代码示例对现有文档进行后处理,它需要更多代码,并且更容易出错:在这个简短的代码片段中,我假设有一个XObject,并且这个单个对象是一个图像 . 这可能不是您的PDF的情况 .

相关问题