JAI TIFF编解码器创建工件

时间:2014-06-29 11:45:37

标签: java tiff deflate jai artifacts

我一直在使用JAI来编写和读取TIFF图像,但是我最近在编码灰度图像时遇到了一个问题,我在每个条带的末尾得到7个黑色(0)像素(每条带8行) ):

7-black-pixels-artifact on each 8th line

我只有在使用下面的SSCE设置DEFLATE压缩与deflate级别0时才能重现它。任何其他价值似乎都有效。

我有时也目睹了图像的条带向左移动了30个像素左右。虽然我无法对这个问题进行稳定的再现,但是如果你知道一些关于在JAI中编码TIFF的隐藏提示,那么它也可以摆脱它。

private static byte[] genImage(int width, int height) {
    byte[] pix = new byte[width * height];
    Arrays.fill(pix, (byte)0xcf);
    for (int j = 0; j < height; j++) {
        Arrays.fill(pix, j*width + width/3, j*width + 2*width/3, (byte)0x7f);
    }
    return pix;
}

public static void main(String[] args) throws Exception {
    int width = 256;
    int height = 256;
    byte[] pix = genImage(width, height);
    BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
    System.arraycopy(pix, 0, ((DataBufferByte)img.getRaster().getDataBuffer()).getData(), 0, width * height);
    TIFFEncodeParam comp = new TIFFEncodeParam();
    comp.setCompression(TIFFEncodeParam.COMPRESSION_DEFLATE);
    comp.setDeflateLevel(0); // Changing 0 to values 1-9 "solves" the problem

    FileOutputStream fos = new FileOutputStream("bugjai.tiff");
    ImageEncoder encoder = ImageCodec.createImageEncoder("tiff", fos, comp);
    encoder.encode(img);
    fos.close();
}

编辑:

我进一步调查了8x8图像上的文件内容。我使用级别0(使用java.util.zip.Deflater)放弃了字节内容,得到了额外的11个字节。我在条带的末尾插入了这些字节并修补了标题以反映新的长度(值4B而非位置40的{​​{1}})和voilà!不超过7个像素。

Diff OK/NOK

因此,似乎JAI中存在误解“忘记”在放气时放入/计算字节数。但是,TIFF6 specification在第15页开头说:

  

预计价值将从字边界开始;因此,相应的值偏移将是偶数

让我困惑:“开始”是指文件中的位置? “修补”值从75h切换为40,这是不均匀的。 JAI可能会以某种方式错误估算某些东西并向下舍入吗?

附录:

当“压缩”数据大于原始数据时,似乎会出现问题:在这里,当压缩数据长度为75字节时,原始数据长度为64字节。 JAI可能假设图像的最大尺寸不能超过原始数据的大小。

1 个答案:

答案 0 :(得分:1)

因此,在问题中进行了一些额外的测试(参见EDIT和ADDENDUM)后,JAI中似乎存在一个错误,将最大字节数限制为width * heigth。我猜他们认为没有压缩会增加图像的大小...除非你用因子0(我理解为“存储”)收缩,你得到像素,加上一个标题和tailer。由于JAI限制了写入的字节数,因此未正确写入尾标(如果有的话),并且数据未完全解码。

课程是:使用至少一个缩小因子1(在the javadoc中也标记为BEST_SPEED / MIN_COMPRESSION)。