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

时间:2014-02-22 18:21:09

标签: pdf itextsharp jpeg image-compression

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

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

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

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

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

  • 不同的颜色压缩方法(FlateDecode,LZWDecode,DCTDecode,...)
  • 不同的JPEG质量设置
  • 缩小JPEG的像素宽度和高度,仅在显示PDF时将其拉伸。
  • 将图像内容切割成较小的图像块。

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

然而,我从其他公司收集的一些样本PDF中找不到一种方法,就是有些人拥有多阶段过滤的JPEG图像。我的意思是:

  • 过滤器名称是两个数组:/ DCTDecode,/ FlateDecode
  • 生成PDF时,首先应用JPEG压缩,然后进行Deflated。在查看PDF时,数据首先被充气,然后JPEG解压缩成像素。

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

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

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

1 个答案:

答案 0 :(得分: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示例。

由于这需要尚未正式发布的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,情况可能并非如此。