Заобикаляне на забавянето на 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
приемам, че четенето му е подобно на стария ви impl, не е опция?   -  person radai    schedule 19.09.2013
comment
преди това използвах ImageIO.read, за да го прочета обратно, но това зависи от това, че потокът от байтове е бил кодиран с ImageIO.write. Масивът от байтове във втория пример за код е просто дъмп на всички стойности на пикселите, а не кодиран поток от байтове.   -  person codersarepeople    schedule 19.09.2013
comment
няма ли това да го направи просто BMP? което трябва да направи възможно да се направи нещо подобно - stackoverflow.com/questions/4234703/ или може би това - stackoverflow.com/questions/6319465/   -  person radai    schedule 19.09.2013
comment
Изглежда често срещан проблем, че стандартният Java ImageIO PNG писател е бавен. Опитайте да търсите в Google за бърз png декодер Java и ще намерите няколко заместители, като 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