TIFFPackBitsCompressor — NPE?

Я использую com.sun.media.imageioimpl.plugins.tiff.TIFFPackBitsCompressor, чтобы попытаться закодировать массив байтов tiff, который у меня есть, с помощью PackBits. Я не знаком с этим классом и не нашел много примеров того, как его использовать. Но, следуя javadoc, я получаю NPE каждый раз, когда пытаюсь кодировать свои данные. Насколько я вижу, ни одно из моих значений не равно нулю. На данный момент я пробовал эти тесты с несколькими значениями, но ниже моя последняя итерация:

                TIFFPackBitsCompressor pack = new TIFFPackBitsCompressor();
                //bImageFromConvert is a 16-bit BufferedImage with all desired data.
                short[] bufferHolder = ((DataBufferUShort) bImageFromConvert.getRaster().getDataBuffer()).getData();
                //Since bImageFromConvert is 16-bits, the short array isn't the right length. 
                //The below conversion handles tihs issue
                byte[] byteBuffer = convertShortToByte(bufferHolder);
                //I'm not entirely sure what this int[] in the parameters should be. 
                //For now, it is a test int[] array containing all 1s
                int[] testint = new int[byteBuffer.length];
                Arrays.fill(testint, 1);
                //0 offset. dimWidth = 1760, dimHeight = 2140. Not sure what that last param is supposed to be in layman's terms.
                //npe thrown at this line.
                int testOut = pack.encode(byteBuffer, 0, dimWidth, dimHeight, testint, 1);

Есть ли у кого-нибудь понимание того, что происходит? Кроме того, если возможно, кто-нибудь знает лучший способ кодировать мои файлы TIFF с помощью PackBits в программе Java?

Дайте мне знать, если есть что-нибудь, чтобы прояснить мой вопрос.

Спасибо!


person Sarah    schedule 24.03.2017    source источник
comment
Где трассировка стека? В любом случае, я не думаю, что вы должны использовать компрессор самостоятельно, вместо этого он используется плагином JAI ImageIO TIFF (TIFFImageWriter), когда вы указываете PackBits в качестве типа сжатия в файле ImageWriteParam. Вы также можете передать экземпляр компрессора в параметре, если вы сначала приведете его к TIFFImageWriteParam, но это более полезно для пользовательских сжатий, не известных плагину.   -  person Harald K    schedule 30.03.2017


Ответы (1)


Как сказано в комментарии, вы не должны использовать TIFFPackBitsCompressor напрямую, вместо этого он используется внутри плагина JAI ImageIO TIFF (TIFFImageWriter), когда вы указываете «PackBits» в качестве типа сжатия в файле ImageWriteParam. Вы также можете передать экземпляр компрессора в параметре, если вы сначала примените его к TIFFImageWriteParam, но это более полезно для пользовательских сжатий, не известных плагину.

Также обратите внимание, что компрессор будет записывать только сжатые пиксельные данные PackBits, он не создаст полный файл TIFF.

Обычный способ записи сжатого файла TIFF PackBits:

BufferedImage image = ...; // Your input image

ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next(); // Assuming a TIFF plugin is installed

try (ImageOutputStream out = ImageIO.createImageOutputStream(...)) { // Your output file or stream
    writer.setOutput(out);

    ImageWriteParam param = writer.getDefaultWriteParam();
    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    param.setCompressionType("PackBits");

    writer.write(null, new IIOImage(image, null, null), param);
}

writer.dispose();

Приведенный выше код должен нормально работать с плагинами JAI ImageIO и TwelveMonkeys ImageIO TIFF.


PS: PackBits — это очень простой алгоритм сжатия, основанный на кодирование длины выполнения байтовых данных. Поскольку 16-битные данные могут сильно различаться между старшим и младшим байтами одной выборки, PackBits обычно не является хорошим выбором для сжатия таких данных.

Как указано в моих комментариях, используя полностью случайные значения, я получил следующие результаты:

Compression      | File size
-----------------|-----------------
None             |  7 533 680 bytes
PackBits         |  7 593 551 bytes
LZW w/predictor  | 10 318 091 bytes
ZLib w/predictor | 10 318 444 bytes

Это неудивительно, так как полностью случайные данные обычно не поддаются сжатию (без потери данных). Для линейного градиента, который может быть больше похож на «фотографические» данные изображения, я получил совершенно другие результаты:

Compression      | File size
-----------------|-----------------
None             |  7 533 680 bytes
PackBits         |  7 588 779 bytes
LZW w/predictor  |    200 716 bytes
ZLib w/predictor |    144 136 bytes

Как видите, здесь алгоритмы LZW и Deflate/Zlib (с шагом предиктора) работают НАМНОГО лучше. Для «реальных» данных, вероятно, больше шума, поэтому ваши результаты, вероятно, находятся где-то между этими крайностями.

person Harald K    schedule 30.03.2017
comment
Пока файл записывается и находится в формате tiff, он примерно в два раза превышает размер исходного файла. Если это поможет, short[] содержит завернутые байты для 16-битного изображения. Изображение имеет размер 1760x2140 пикселей, а исходный размер изображения составляет 7 532 800 байт (без метаданных, только байты в пикселях). Файл, полученный в результате этого кода, 15 119 390 байт (включая метаданные tiff). - person Sarah; 30.03.2017
comment
@Sarah Вы только что обнаружили, что PackBits - очень неэффективный алгоритм сжатия ваших данных (в целом он неэффективен для 16-битных данных). Используя приведенный выше код, я сжал черное изображение (по-прежнему 1760x2140, 16 бит/пиксель) до 120 Кбайт. Заполнив изображение случайным шумом, размер файла стал 7,5 Мбайт. Использование LZW или ZLib с предиктором дало размеры примерно 10 Мбайт, но это все же может дать вам лучшие результаты, поскольку ваши данные не случайны. - person Harald K; 31.03.2017