我一直在使用JAI来编写和读取TIFF图像,但是我最近在编码灰度图像时遇到了一个问题,我在每个条带的末尾得到7个黑色(0
)像素(每条带8行) ):
我只有在使用下面的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个像素。
因此,似乎JAI中存在误解“忘记”在放气时放入/计算字节数。但是,TIFF6 specification在第15页开头说:
预计价值将从字边界开始;因此,相应的值偏移将是偶数
让我困惑:“开始”是指文件中的位置? “修补”值从75h
切换为40
,这是不均匀的。 JAI可能会以某种方式错误估算某些东西并向下舍入吗?
附录:
当“压缩”数据大于原始数据时,似乎会出现问题:在这里,当压缩数据长度为75字节时,原始数据长度为64字节。 JAI可能假设图像的最大尺寸不能超过原始数据的大小。
答案 0 :(得分:1)
因此,在问题中进行了一些额外的测试(参见EDIT和ADDENDUM)后,JAI中似乎存在一个错误,将最大字节数限制为width * heigth
。我猜他们认为没有压缩会增加图像的大小...除非你用因子0
(我理解为“存储”)收缩,你得到像素,加上一个标题和tailer。由于JAI限制了写入的字节数,因此未正确写入尾标(如果有的话),并且数据未完全解码。
课程是:使用至少一个缩小因子1
(在the javadoc中也标记为BEST_SPEED
/ MIN_COMPRESSION
)。