将PDF转换为多页tiff(第4组)

我正在尝试将org.apache.pdfbox.pdmodel.PDDocument类和icafe库( https://github.com/dragon66/icafe/ )所代表的PDF转换为具有第4组压缩和300 dpi的多页tiff 。 示例代码适用于我288 dpi,但奇怪的是不是300 dpi,导出的tiff仍然只是白色。 有谁知道这里的问题是什么?

我在示例中使用的示例pdf位于: http : //www.bergophil.ch/a.pdf

import java.awt.image.BufferedImage; import java.io.FileOutputStream; import java.io.IOException; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import cafe.image.ImageColorType; import cafe.image.ImageParam; import cafe.image.options.TIFFOptions; import cafe.image.tiff.TIFFTweaker; import cafe.image.tiff.TiffFieldEnum.Compression; import cafe.io.FileCacheRandomAccessOutputStream; import cafe.io.RandomAccessOutputStream; public class Pdf2TiffConverter { public static void main(String[] args) { String pdf = "a.pdf"; PDDocument pddoc = null; try { pddoc = PDDocument.load(pdf); } catch (IOException e) { } try { savePdfAsTiff(pddoc); } catch (IOException e) { } } private static void savePdfAsTiff(PDDocument pdf) throws IOException { BufferedImage[] images = new BufferedImage[pdf.getNumberOfPages()]; for (int i = 0; i < images.length; i++) { PDPage page = (PDPage) pdf.getDocumentCatalog().getAllPages() .get(i); BufferedImage image; try { // image = page.convertToImage(BufferedImage.TYPE_INT_RGB, 288); //works image = page.convertToImage(BufferedImage.TYPE_INT_RGB, 300); // does not work images[i] = image; } catch (IOException e) { e.printStackTrace(); } } FileOutputStream fos = new FileOutputStream("a.tiff"); RandomAccessOutputStream rout = new FileCacheRandomAccessOutputStream( fos); ImageParam.ImageParamBuilder builder = ImageParam.getBuilder(); ImageParam[] param = new ImageParam[1]; TIFFOptions tiffOptions = new TIFFOptions(); tiffOptions.setTiffCompression(Compression.CCITTFAX4); builder.imageOptions(tiffOptions); builder.colorType(ImageColorType.BILEVEL); param[0] = builder.build(); TIFFTweaker.writeMultipageTIFF(rout, param, images); rout.close(); fos.close(); } } 

或者是否有另一个库来编写多页TIFF?

编辑:

感谢dragon66,icafe中的错误现已修复。 与此同时,我尝试了其他库,并调用了ghostscript 。 因为我认为ghostscript是非常可靠的,因为id是一个广泛使用的工具,另一方面,我必须依赖我的代码的用户有一个ghostscript-installation ,如下所示:

  /** * Converts a given pdf as specified by its path to an tiff using group 4 compression * * @param pdfFilePath The absolute path of the pdf * @param tiffFilePath The absolute path of the tiff to be created * @param dpi The resolution of the tiff * @throws MyException If the conversion fails */ private static void convertPdfToTiffGhostscript(String pdfFilePath, String tiffFilePath, int dpi) throws MyException { // location of gswin64c.exe String ghostscriptLoc = context.getGhostscriptLoc(); // enclose src and dest. with quotes to avoid problems if the paths contain whitespaces pdfFilePath = "\"" + pdfFilePath + "\""; tiffFilePath = "\"" + tiffFilePath + "\""; logger.debug("invoking ghostscript to convert {} to {}", pdfFilePath, tiffFilePath); String cmd = ghostscriptLoc + " -dQUIET -dBATCH -o " + tiffFilePath + " -r" + dpi + " -sDEVICE=tiffg4 " + pdfFilePath; logger.debug("The following command will be invoked: {}", cmd); int exitVal = 0; try { exitVal = Runtime.getRuntime().exec(cmd).waitFor(); } catch (Exception e) { logger.error("error while converting to tiff using ghostscript", e); throw new MyException(ErrorMessages.GHOSTSTSCRIPT_ERROR, e); } if (exitVal != 0) { logger.error("error while converting to tiff using ghostscript, exitval is {}", exitVal); throw new MyException(ErrorMessages.GHOSTSTSCRIPT_ERROR); } } 

我发现从ghostscript生成的tificafe产生的tiff质量差别icafe (来自ghostscript 4组tiff看起来像灰度一样)

问题被问到已经有一段时间了,我终于找到了时间和一个精彩的有序抖动矩阵,它允许我提供一些关于如何使用“icafe”来获得与调用外部ghostscript可执行文件类似或更好结果的细节。 最近在“icafe”中添加了一些新function,例如更好的量化和有序抖动算法,这些算法在以下示例代码中使用。

这里我将使用的示例pdf是princeCatalogue 。 以下大多数代码来自OP,由于包名称更改和更多ImageParam控件设置而发生一些更改。

 import java.awt.image.BufferedImage; import java.io.FileOutputStream; import java.io.IOException; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import com.icafe4j.image.ImageColorType; import com.icafe4j.image.ImageParam; import com.icafe4j.image.options.TIFFOptions; import com.icafe4j.image.quant.DitherMethod; import com.icafe4j.image.quant.DitherMatrix; import com.icafe4j.image.tiff.TIFFTweaker; import com.icafe4j.image.tiff.TiffFieldEnum.Compression; import com.icafe4j.io.FileCacheRandomAccessOutputStream; import com.icafe4j.io.RandomAccessOutputStream; public class Pdf2TiffConverter { public static void main(String[] args) { String pdf = "princecatalogue.pdf"; PDDocument pddoc = null; try { pddoc = PDDocument.load(pdf); } catch (IOException e) { } try { savePdfAsTiff(pddoc); } catch (IOException e) { } } private static void savePdfAsTiff(PDDocument pdf) throws IOException { BufferedImage[] images = new BufferedImage[pdf.getNumberOfPages()]; for (int i = 0; i < images.length; i++) { PDPage page = (PDPage) pdf.getDocumentCatalog().getAllPages() .get(i); BufferedImage image; try { // image = page.convertToImage(BufferedImage.TYPE_INT_RGB, 288); //works image = page.convertToImage(BufferedImage.TYPE_INT_RGB, 300); // does not work images[i] = image; } catch (IOException e) { e.printStackTrace(); } } FileOutputStream fos = new FileOutputStream("a.tiff"); RandomAccessOutputStream rout = new FileCacheRandomAccessOutputStream( fos); ImageParam.ImageParamBuilder builder = ImageParam.getBuilder(); ImageParam[] param = new ImageParam[1]; TIFFOptions tiffOptions = new TIFFOptions(); tiffOptions.setTiffCompression(Compression.CCITTFAX4); builder.imageOptions(tiffOptions); builder.colorType(ImageColorType.BILEVEL).ditherMatrix(DitherMatrix.getBayer8x8Diag()).applyDither(true).ditherMethod(DitherMethod.BAYER); param[0] = builder.build(); TIFFTweaker.writeMultipageTIFF(rout, param, images); rout.close(); fos.close(); } } 

对于ghostscript,我直接使用命令行和OP提供的相同参数。 结果TIFF图像第一页的屏幕截图如下所示:

在此处输入图像描述

左侧显示“ghostscript”的输出,右侧显示“icafe”的输出。 可以看出,至少在这种情况下,“icafe”的输出优于“ghostscript”的输出。

使用CCITTFAX4压缩,“ghostscript”的文件大小为2.22M,“icafe”的文件大小为2.08M。 考虑到在创建黑白输出时使用抖动的事实,两者都不是那么好。 实际上,不同的压缩算法会创建更小的文件大小。 例如,使用LZW,“icafe”的相同输出仅为634K,如果使用DEFLATE压缩,则输出文件大小降至582K。

这里有一些代码可以保存在我使用PDFBox的多页tiff中。 它需要来自PDFBox的TIFFUtil类 (它不是公共的,所以你必须复制)。

 void saveAsMultipageTIFF(ArrayList bimTab, String filename, int dpi) throws IOException { Iterator writers = ImageIO.getImageWritersByFormatName("tiff"); ImageWriter imageWriter = writers.next(); ImageOutputStream ios = ImageIO.createImageOutputStream(new File(filename)); imageWriter.setOutput(ios); imageWriter.prepareWriteSequence(null); for (BufferedImage image : bimTab) { ImageWriteParam param = imageWriter.getDefaultWriteParam(); IIOMetadata metadata = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(image), param); param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); TIFFUtil.setCompressionType(param, image); TIFFUtil.updateMetadata(metadata, image, dpi); imageWriter.writeToSequence(new IIOImage(image, null, metadata), param); } imageWriter.endWriteSequence(); imageWriter.dispose(); ios.flush(); ios.close(); } 

我前段时间通过使用以下代码对自己进行了实验: https : //www.java.net/node/670205 (我使用的是解决方案2)

然而…

如果你创建一个包含大量图像的数组,你的内存消耗肯定会增加。 因此,渲染图像,然后将其添加到tiff文件,然后渲染下一页并丢失前一页的引用可能会更好,这样gc可以在需要时获取空间。

Interesting Posts