Кодек JAI TIFF для создания артефактов
Я использовал JAI для записи и чтения изображений в формате TIFF, но недавно я столкнулся с проблемой при кодировании серого изображения, когда я получаю 7 черных (0
) пикселей в конце каждой полосы (8 строк на полосу):
Я смог воспроизвести его только при настройке DEFLATE
сжатие с уровнем дефляции 0
используя SSCE ниже. Любая другая ценность, кажется, работает.
Я также был свидетелем того, как полосы изображения смещались влево на 30 пикселей или около того. Я не смог получить стабильное воспроизведение этой проблемы, но если вы знаете некоторые скрытые советы о кодировании TIFF в JAI, это также может помочь избавиться от этого.
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
в положении 75h
) и вуаля! Не более 7 пикселей.
Таким образом, кажется, что в JAI есть неправильное кодирование, которое "забывает" ставить / считать байты при дефляции. Тем не менее, спецификация TIFF6 говорит в начале страницы 15:
Ожидается, что значение начинается с границы слова; соответствующее смещение значения, таким образом, будет четным числом
Что меня смущает: "начало" относится к позиции в файле? "Исправленное" значение переключилось с 40
в 4B
что даже не Может ли JAI как-то просчитаться и округлить?
ДОПОЛНЕНИЕ:
Кажется, проблема возникает, когда "сжатые" данные больше исходных: здесь исходные данные имеют длину 64 байта, а сжатые данные имеют длину 75 байтов. JAI, вероятно, предполагает, что максимальный размер изображения не может превышать размер исходных данных.
1 ответ
Так что после некоторого дополнительного тестирования (см. РЕДАКТИРОВАТЬ и ДОБАВИТЬ) в этом вопросе, кажется, есть ошибка в JAI, ограничивающая максимальное количество байтов до width * heigth
, Я предполагаю, что они предполагали, что никакое сжатие никогда не увеличит размер изображения... за исключением случая, когда вы сдули с фактором 0
(который я понимаю как "магазин"), где вы получаете пиксели, а также заголовок и тейлер. Поскольку JAI ограничивает количество записанных байтов, программа-тейлер не написана должным образом (если вообще), и данные не полностью декодируются.
Урок: используйте как минимум фактор дефляции 1
(который также помечен BEST_SPEED
/ MIN_COMPRESSION
в javadoc).