2012-04-19 12 views
10

Witam mam instancję BufferedImage w pamięci i chcesz przekonwertować go na byte [], aby kodować jako base64 ciąg bez operacji I/O do rozpatrzenia wydajności. Używałem następujący API:Konwersja BufferedImage do byte [] bez I/O

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

to jednak API nadal domyślnie zapisuje obraz do katalogu OS temp, co doprowadzi do awarii w przypadku, gdy bazowy katalog OS temp jest pełny oraz plik tymczasowy nie może być stworzony. stosu Ślad:

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) 

Czy istnieje skuteczny (jak przemiany w pamięci lub efektywnego I/O) sposób to zrobić bez konwersji I/O? Proszę doradź.

+3

jestem .. Zaskoczony, że tak się dzieje. –

+0

Jest to prawie na pewno błąd w JVM. Czy wypróbowałeś najnowszą wersję? –

+0

@PeterLawrey: dlaczego uważasz, że to błąd? Istnieje cała klasa ["FileCacheImageOutputStream"] (http://docs.oracle.com/javase/7/docs/api/javax/imageio/stream/FileCacheImageOutputStream.html). Jednak w ogóle nie wiedziałem o tym mechanizmie w "ImageIO". –

Odpowiedz

11

wyłączyć pamięć podręczną ImageIO dzięki metodzie ImageIO.setUseCache():

ImageIO.setUseCache(false); 

Jest on domyślnie według javadoc:

ustawia flagę wskazującą, czy plik cache oparte powinny być stosowane podczas tworzenia ImageInputStreams i ImageOutputStreams.

Podczas odczytu ze standardowego InputStream>, może być konieczne, aby zapisać wcześniej przeczytać informacje w pamięci podręcznej, ponieważ podstawowa strumień danych nie pozwala być ponownie przeczytać. Podobnie, przy zapisie do standardowego OutputStream, pamięć podręczna może być użyta, aby umożliwić uprzednio zapisaną wartość, która zostanie zmieniona, przed wypłukaniem jej do ostatecznego miejsca docelowego.

Pamięć podręczna może znajdować się w pamięci głównej lub na dysku. Ustawienie tej flagi na false uniemożliwia użycie dysku dla przyszłych strumieni, co może być korzystne w przypadku pracy z małymi obrazami, ponieważ koszty związane z tworzeniem i niszczeniem plików są usuwane.

Na starcie, wartość jest ustawiona na wartość true.

3

ImageIO domyślnie zapisuje pamięć podręczną na dysk, nawet jeśli używasz tylko strumieni. Spróbuj wyłączyć pamięć podręczną z:

ImageIO.setUseCache(false); 
1

((DataBufferByte)img.getRaster().getDataBuffer()).getData() automatycznie zwraca tablicę bajtów, jeśli obraz był w formacie bajtów. W ogóle nie potrzeba żadnej IO.

2

Obie wzmianki o ImageIO.setUseCache(false) są poprawne. Jednakże, jeśli nie chcesz wyłączyć buforowanie dysku dla ImageIO globalnie, alternatywą jest wyraźnie zawinąć strumienia w MemoryCacheImageOutputStream (co robi buforowania w pamięci zamiast buforowania dysku):

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

Wygląda na to, że nie jest to prawda, przynajmniej w 1.8. 'com.sun.imageio.spi.OutputStreamImageOutputStreamSpi # createOutputStreamInstance' nie sprawdza typu strumienia, ale sprawdza parametr' useCache'. W każdym razie byłoby naprawdę dobrze mieć sposób na wyłączenie buforowania lokalnie. – sedovav

+0

@sedovav Powyższe rozwiązanie rzeczywiście umożliwia "lokalne" wyłączenie pamięci podręcznej dysku. Kiedy tworzysz MemoryCacheImageOutputStream bezpośrednio tak jak nigdy, nie trafisz w Spi, więc cokolwiek robi, jest nieistotne. PS: Zauważ, że ImageOutputSream nie jest podklasą OutputStream, pomimo swojej nazwy. I istnieje oddzielne przeciążenie ImageIO.write. – haraldK

+1

Rzeczywiście. Dziękuję Ci bardzo! – sedovav