Как обойти медлительность ImageIO.write

Недавно я обнаружил, что библиотека ImageIO, которую я использовал, записывала изображения в байтовые массивы/потоки невероятно медленно и переключалась с

BufferedImage img;//initialized elsewhere
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img,"png",baos);

to

BufferedImage img;//initialized elsewhere
byte[] argb = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();

Хотя этот второй метод почти в 70 раз быстрее, я не могу найти быстрый способ воссоздать BufferedImage из этого массива байтов argb.


person codersarepeople    schedule 19.09.2013    source источник
comment
Я так понимаю, что это похоже на ваш старый импл, это не вариант?   -  person radai    schedule 19.09.2013
comment
ранее я использовал ImageIO.read, чтобы прочитать его обратно, но это зависит от потока байтов, закодированного с помощью ImageIO.write. Массив байтов во втором примере кода — это просто дамп всех значений пикселей, а не закодированный поток байтов.   -  person codersarepeople    schedule 19.09.2013
comment
Разве это не делает его просто БМП? это должно позволить сделать что-то вроде этого - stackoverflow.com/questions/4234703/ или, может быть, это - stackoverflow.com/questions/6319465/   -  person radai    schedule 19.09.2013
comment
Кажется, распространенной проблемой является то, что стандартный модуль записи Java ImageIO PNG работает медленно. Попробуйте поискать в Google быстрый декодер png, и вы найдете несколько замен, таких как objectplanet, fastpng и sixlegs. Вы пробовали писать в другом формате (например, BMP)?. В любом случае вы можете воссоздать свое изображение из необработанных пикселей (на SO уже есть масса вопросов об этом), но вам нужно знать такие вещи, как цветовая модель, ширина, высота и т. д., которые обычно хранятся в заголовке формата файла.   -  person Harald K    schedule 19.09.2013
comment
PS: Просто хочу отметить, что код во втором массиве — это не дамп пикселей, это пиксели. Код безумно быстрый, потому что это всего лишь одно задание. Вы можете создать новое изображение из этих пикселей, но если вы сделаете это без копирования (что займет немного больше времени), изменения в одном изображении будут отражены в другом.   -  person Harald K    schedule 20.09.2013
comment
Что ж, в конце концов мне нужно будет скопировать их, так как я отправляю их по сети. Мой вопрос заключается в том, как создать новый объект BufferedImage с копией этого массива байтов.   -  person codersarepeople    schedule 21.09.2013
comment
Вы точно знаете, что ваши изображения а) всегда используют байты буфера данных б) имеют одинаковую цветовую модель в) имеют одинаковые размеры? В противном случае вам также понадобится эта информация. И в конечном итоге вы создаете свой собственный собственный формат изображения.   -  person Harald K    schedule 22.09.2013
comment
Да, я могу быть уверен, что они всегда будут одинаковыми.   -  person codersarepeople    schedule 23.09.2013


Ответы (1)


Ну, я не собираюсь говорить, что передача необработанных пикселей — это вообще хорошая идея, но она может подойти для этого конкретного случая использования.

Судя по обсуждению в комментариях, это должно быть так же сложно, как:

DataBuffer buffer = new DataBufferByte(argb, argb.length); // arg is your input array
ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[]{8, 8, 8, 8}, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);

return new BufferedImage(cm, Raster.createInterleavedRaster(buffer, width, height, width * 4, 4, new int[] {0, 1, 2, 3}, null), false, null);

Все это при условии, что у вас действительно есть пиксели ARGB в массиве argb, а width и height известны. Сделайте все массивы и цветовую модель постоянными для повышения производительности.

person Harald K    schedule 26.09.2013