2012-04-19 5 views
10

Привет У меня есть экземпляр BufferedImage в памяти и вы хотите преобразовать его в байты [] для кодирования в качестве строки base64 без операции ввода-вывода для рассмотрения производительности. Я использую следующий API:Преобразование BufferedImage в байт [] без ввода/вывода

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
ImageIO.write(image,"png",baos); 
return baos.toByteArray(); 

Однако этот API еще неявно записывает изображение во временном каталоге ОС, что приведет к отказу в случае, если основной временный каталог ОС заполнен и временный файл не может быть создано. Трассировка стека:

Caused by: java.io.IOException: No space left on device 
    at java.io.RandomAccessFile.write(RandomAccessFile.java:493) 
    at javax.imageio.stream.FileCacheImageOutputStream.write(FileCacheImageOutputStream.java:134) 
    at javax.imageio.stream.ImageOutputStreamImpl.write(ImageOutputStreamImpl.java:66) 
    at com.sun.imageio.plugins.png.PNGImageWriter.write_magic(PNGImageWriter.java:376) 
    at com.sun.imageio.plugins.png.PNGImageWriter.write(PNGImageWriter.java:1115) 
    at javax.imageio.ImageWriter.write(ImageWriter.java:628) 
    at javax.imageio.ImageIO.write(ImageIO.java:1480) 
    at javax.imageio.ImageIO.write(ImageIO.java:1554) 

Есть ли эффективный (например, преобразование в памяти или эффективного ввода/вывода) способ сделать преобразование без ввода/вывода? Пожалуйста, порекомендуйте.

+3

я есть .. что это происходит. –

+0

Это почти наверняка ошибка в JVM. Вы пробовали последнюю версию? –

+0

@PeterLawrey: почему вы считаете это ошибкой? Существует целый класс [FileCacheImageOutputStream'] (http://docs.oracle.com/javase/7/docs/api/javax/imageio/stream/FileCacheImageOutputStream.html). Однако я вообще не знал об этом механизме в «ImageIO». –

ответ

11

Отключение кэша ImageIO через ImageIO.setUseCache() метод:

ImageIO.setUseCache(false); 

Он находится по умолчанию в соответствии с Javadoc:

Устанавливает флаг, указывающий, следует ли использовать диск на основе кэш-файл при создании ImageInputStreams и ImageOutputStreams.

При чтении из стандартного InputStream> может потребоваться сохранить ранее прочитанную информацию в кеше, поскольку базовый поток не позволяет перечитывать данные. Аналогично, при записи в стандартный OutputStream кеш может использоваться, чтобы позволить ранее записанное значение быть изменено до того, как оно будет сброшено до конечного адресата.

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

При запуске значение равно true.

3

ImageIO по умолчанию записывает кеш на диск, даже если вы используете только потоки. Попробуйте отключить кэш с:

ImageIO.setUseCache(false); 
1

((DataBufferByte)img.getRaster().getDataBuffer()).getData() автоматически возвращает массив байтов, если изображение было в формате байта. Не требуется никакого ввода-вывода.

2

Оба упоминания о ImageIO.setUseCache(false) верны. Однако, если вам не нравится, чтобы отключить кэширование диска для ImageIO глобально, альтернативой является явно обернуть поток в MemoryCacheImageOutputStream (который делает кэширование в памяти вместо кэширования диска):

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
ImageOutputStream stream = new MemoryCacheImageOutputStream(baos); 
ImageIO.write(image, "png", stream); 
stream.close(); 
return baos.toByteArray(); 
+0

Похоже, это не так, по крайней мере, в 1.8. 'com.sun.imageio.spi.OutputStreamImageOutputStreamSpi # createOutputStreamInstance' не проверяет тип потока, но проверяет параметр' useCache'. Во всяком случае, было бы неплохо иметь способ отключить кеширование локально. – sedovav

+0

@sedovav Данное решение действительно обеспечивает способ «локального» отключения дискового кэша. Когда вы создаете MemoryCacheImageOutputStream прямо так, вы никогда не попадаете в Spi, поэтому все, что он делает, не имеет значения. PS: Обратите внимание, что ImageOutputSream не является подклассом OutputStream, несмотря на его имя. И для этого есть отдельная перегрузка ImageIO.write. – haraldK

+1

Действительно. Большое спасибо! – sedovav