java – 多页Tiff压缩

我已经看到了关于多重tiff的一些问题和一些关于压缩的问题,但没有(我见过)将这两者联系起来.
This question就像我见过的那样近,让我非常接近,所以我希望如此.我进入了提到的Oracle论坛帖子(它正在讨论带有压缩的多页PDF到TIFF)并且我认为我很难完成代码.有人可以帮忙吗?我将删除try / catches以尝试将其缩短(基本上他们所做的只是在控制台中输出一条消息并返回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问题.但是,它不会在第一个页面之外添加任何页面.

最佳答案 如果它有帮助,这是我用来修改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编码器将它们写入损坏,所以需要修补它们.

点赞