Кодек JAI TIFF для создания артефактов

Я использовал JAI для записи и чтения изображений в формате TIFF, но недавно я столкнулся с проблемой при кодировании серого изображения, когда я получаю 7 черных (0) пикселей в конце каждой полосы (8 строк на полосу):

7-черный пиксель-артефакт на каждой 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 пикселей.

Diff OK / NOK

Таким образом, кажется, что в JAI есть неправильное кодирование, которое "забывает" ставить / считать байты при дефляции. Тем не менее, спецификация TIFF6 говорит в начале страницы 15:

Ожидается, что значение начинается с границы слова; соответствующее смещение значения, таким образом, будет четным числом

Что меня смущает: "начало" относится к позиции в файле? "Исправленное" значение переключилось с 40 в 4B что даже не Может ли JAI как-то просчитаться и округлить?

ДОПОЛНЕНИЕ:

Кажется, проблема возникает, когда "сжатые" данные больше исходных: здесь исходные данные имеют длину 64 байта, а сжатые данные имеют длину 75 байтов. JAI, вероятно, предполагает, что максимальный размер изображения не может превышать размер исходных данных.

1 ответ

Решение

Так что после некоторого дополнительного тестирования (см. РЕДАКТИРОВАТЬ и ДОБАВИТЬ) в этом вопросе, кажется, есть ошибка в JAI, ограничивающая максимальное количество байтов до width * heigth, Я предполагаю, что они предполагали, что никакое сжатие никогда не увеличит размер изображения... за исключением случая, когда вы сдули с фактором 0 (который я понимаю как "магазин"), где вы получаете пиксели, а также заголовок и тейлер. Поскольку JAI ограничивает количество записанных байтов, программа-тейлер не написана должным образом (если вообще), и данные не полностью декодируются.

Урок: используйте как минимум фактор дефляции 1 (который также помечен BEST_SPEED / MIN_COMPRESSION в javadoc).

Другие вопросы по тегам