如何更改 PDF 文件中图像的过滤器
How to change the filter of an image in a PDF file
我正在构建一个压缩 PDF 文件的工具,并使用 pdfbox。
我有一些带有 DCTDecode
+ FlateDecode
滤镜的图像,我想尝试使用 JPXDecode
滤镜看看它是否占用更少 space.
我看过一些使用 iText
的代码,但是如何使用 pdfbox
来实现呢?我没有找到如何执行此操作的文档。
使用 pdfbox
可以压缩所有图像,方法是使用处理所有图像流并使用 JPXDecode 过滤器重新编码的自定义 COSWriter
。 pdfbox
无法这样做,但带有插件的 JAI 库可以生成 JPEG2000 图像。压缩因子是可配置的,可以在不损失太多质量的情况下实现高压缩比。
通过另外使用 FlateDecode
过滤器,可以在没有质量损失的情况下获得更多的压缩。
此代码无需更改 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
}
}
我正在构建一个压缩 PDF 文件的工具,并使用 pdfbox。
我有一些带有 DCTDecode
+ FlateDecode
滤镜的图像,我想尝试使用 JPXDecode
滤镜看看它是否占用更少 space.
我看过一些使用 iText
的代码,但是如何使用 pdfbox
来实现呢?我没有找到如何执行此操作的文档。
使用 pdfbox
可以压缩所有图像,方法是使用处理所有图像流并使用 JPXDecode 过滤器重新编码的自定义 COSWriter
。 pdfbox
无法这样做,但带有插件的 JAI 库可以生成 JPEG2000 图像。压缩因子是可配置的,可以在不损失太多质量的情况下实现高压缩比。
通过另外使用 FlateDecode
过滤器,可以在没有质量损失的情况下获得更多的压缩。
此代码无需更改 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
}
}