4

我见过一些关于多页 tiff 的问题和一些关于压缩的问题,但没有一个(我见过)将两者联系起来。这个问题与我所见过的一样接近,让我非常接近,所以我希望。我进入了提到的 Oracle 论坛主题(它正在谈论一个多页 PDF 到 TIFF 的压缩),我想我已经接近完成代码来执行此操作了。有人可以帮忙吗?我将删除 try/catch 以尝试将其缩短(基本上他们所做的只是在控制台中输出一条消息并返回 false)。

 public static boolean CompressedTiff(List<BufferedImage> images, File path)
 {
    if (!path.getParentFile().exists())
         path.getParentFile().mkdirs();
    path.createNewFile();
    ImageOutputStream ios;
         ios = ImageIO.createImageOutputStream(path);

    Iterator<ImageWriter> imageWriters = ImageIO.getImageWritersByFormatName("TIFF");
    ImageWriter writer = (ImageWriter)imageWriters.next();
    writer.setOutput(ios);
    TIFFImageWriteParam writeParam = (TIFFImageWriteParam)writer.getDefaultWriteParam();
    writeParam.setCompressionMode(2);
    writeParam.setCompressionType("LZW"); 
    writer.prepareWriteSequence(null);

    for(int i = 0; i < images.size(); i++)
    {
        ImageTypeSpecifier spec = ImageTypeSpecifier.createFromRenderedImage(images.get(i));
        javax.imageio.metadata.IIOMetadata metadata = writer.getDefaultImageMetadata(spec, writeParam);
        IIOImage iioImage = new IIOImage(images.get(i), null, metadata);
        writer.writeToSequence(iioImage, writeParam);
        images.get(i).flush();//modified after release.

        images.get(i).flush();
        writer.endWriteSequence();
        ios.flush();
        writer.dispose();
        ios.close();
    }
    return true;

}

它在 writer.writeToSequence 的下一次传递中失败,说我需要调用 prepareWriteSequence。我把它改成

 writer.prepareWriteSequence(metadata);
 writer.writeToSequence(iioImage, writeParam);

还删除了较早的 writer.prepareWriteSequence(null);

它似乎可以正确导航文件,但是,输出不是任何类型的可渲染 tif。多页或其他。

我已经安装了 JAI,所以如果可以以某种方式使用它来实现压缩图像,那就太好了。我正在使用的生成 TIFF 的代码正在使用它,但我还没有看到任何可以为页面添加压缩的东西。

编辑:我添加了一堆 ios.flush(); ios.close(); 调用 catch 块,它可以防止不可渲染的 TIFF 问题。但是,除了第一个页面之外,它没有添加任何页面。

4

1 回答 1

3

如果有帮助,这是我用来修改 TiffImageWriteParam 以设置压缩的代码:

try {
    jWriteParam.setCompressionMode(_compression != TiffCompression.NO_COMPRESSION 
                  ? ImageWriteParam.MODE_EXPLICIT : ImageWriteParam.MODE_DISABLED);

    if (_compression != TiffCompression.NO_COMPRESSION) {
        // this code corrects the compression if, say, the client code asked for
        // CCITT but the actual image pixel format was CMYK or some other non-1 bit
        // image type.
        TiffCompression mode = recastToValidCompression(_compression, pf);
        jWriteParam.setCompressionType(getCompressionType(mode));
        TIFFCompressor compressor = getTiffCompressor(mode, jWriteParam, shouldUsePredictor(pf));
        jWriteParam.setTIFFCompressor(compressor);
        if (_compression == TiffCompression.JPEG_COMPRESSION) {
            // Java supports setting to 1.0 (ie 100), but it will not actually do lossless (maybe)
            if (_jpegQuality == 100 && !jWriteParam.isCompressionLossless())
                continue;
            jWriteParam.setCompressionQuality(toJavaJpegQuality());
        }
    }
}
catch (UnsupportedOperationException e)
{
    // this shouldn't get here, but you should consider what to do if it does.
    // set a default? throw?
}

这里是 getTiffCompressor():

private TIFFCompressor getTiffCompressor (TiffCompression compression, TIFFImageWriteParam writeParam, boolean usePredictor)
{
    int predictor = usePredictor 
            ? BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING 
            : BaselineTIFFTagSet.PREDICTOR_NONE;

    switch (compression) 
    {
    case GROUP_3_FAX_ENCODING:
        return new TIFFT4Compressor();
    case GROUP_4_FAX_ENCODING:
        return new TIFFT6Compressor();
    case JPEG_COMPRESSION:
        return new TIFFJPEGCompressor(writeParam);
    case MACINTOSH_PACKBITS:
        return new TIFFPackBitsCompressor();
    case DEFLATE:
        return new TIFFDeflateCompressor(writeParam, predictor);
    case LZW:
        return new TIFFLZWCompressor(predictor);
    case MODIFIED_HUFFMAN:
        return new TIFFRLECompressor();
    case NO_COMPRESSION:
    case DEFAULT:
    default:
        return null;
    }
}

TiffCompression 是我自己的枚举,它模拟了我为 TIFF 文件提供的压缩。最后,这里是 getCompressionType():

private String getCompressionType (TiffCompression compression)
{
    switch (compression)
    {
    case GROUP_3_FAX_ENCODING:
        return "CCITT T.4";
    case GROUP_4_FAX_ENCODING:
        return "CCITT T.6";
    case JPEG_COMPRESSION:
        return "JPEG";
    case MACINTOSH_PACKBITS:
        return "PackBits";
    case DEFLATE:
        return "Deflate";
    case LZW:
        return "LZW";
    case MODIFIED_HUFFMAN:
        return "CCITT RLE";
    case NO_COMPRESSION:
    case DEFAULT:
    default:
        return null;
    }
}

现在,我无法向您展示所有内容,因为我的代码是为编码任意数量的图像而构建的,而您的不是,因此我们的代码结构差异很大。就我而言,我设置了编码器以使用具有更开放架构的序列编写器。我拉入一个图像,触发一个事件以选择性地更改默认压缩,创建写入器并写入参数,设置元数据/图像标签,触发进度事件然后写入序列。然后我必须进入并修补最后写入的 ifd,因为 tiff 编码器将它们写入损坏,因此需要修补它们。

于 2012-04-25T15:25:32.533 回答