2011-08-24 12 views
12

Sto cercando di ottenere uno screenshot come stringa codificata in base64 ma non molto lontano. Il codice che ho finora utilizza una libreria Base64 (http://iharder.sourceforge.net/current/java/base64/):Java BufferedImage in formato PNG Base64 String

Robot robot = new Robot(); 
    Rectangle r = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); 
    BufferedImage bi = robot.createScreenCapture(r); 
    ByteArrayOutputStream os = new ByteArrayOutputStream(); 
    OutputStream b64 = new Base64.OutputStream(os); 
    ImageIO.write(bi, "png", os); 
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    out.writeTo(b64); 
    String result = out.toString("UTF-8"); 

Ogni volta che corro questo "risultato" è sempre una stringa vuota, ma non capisco perché. Qualche idea?

Nota: non voglio dover scrivere il png su un file su disco.

risposta

5

Ho seguito la risposta xehpuk's ma ho riscontrato problemi con alcune immagini con le ultime righe o f pixel mancanti durante il rendering in determinati browser tramite un URL di dati (Chrome e Firefox, Safari sembra renderli soddisfacenti). Sospetto che ciò sia dovuto al fatto che il browser sta facendo il meglio per interpretare i dati, ma mancano gli ultimi pochi byte di dati, quindi mostra ciò che può.

L'involucro del flusso di output sembra essere la causa di questo problema. La documentazione per Base64.wrap(OutputStream os) spiega:

Si raccomanda di chiudere immediatamente il flusso di output restituito dopo l'uso, durante i quali saranno svuotati tutti i possibili byte rimanenti nel flusso di output sottostante.

Quindi, a seconda della lunghezza dei dati, è possibile ultimi byte non vengono svuotati dal flusso perché close() non viene chiamato su di esso. La mia soluzione a questo è stato quello di non preoccuparsi avvolgendo il torrente e appena codificare il flusso direttamente:

public static String imgToBase64String(final RenderedImage img, final String formatName) 
{ 
    final ByteArrayOutputStream os = new ByteArrayOutputStream(); 

    try 
    { 
    ImageIO.write(img, formatName, os); 
    return Base64.getEncoder().encodeToString(os.toByteArray()); 
    } 
    catch (final IOException ioe) 
    { 
    throw new UncheckedIOException(ioe); 
    } 
} 

Questo risolto i problemi con i file mancanti di pixel se fusi in un browser.

+0

Hai un'immagine di esempio? 'ImageIO.write()' chiama 'close()' sul sottostante 'ImageOutputStream' che dovrebbe chiudere' Base64.EncOutputStream' che dovrebbe scrivere tutti i restanti byte nell'output 'OutputStream'. Mi piacerebbe sapere dove mi sto sbagliando. – xehpuk

+0

@xehpuk Penso che potresti sbagliare, 'ImageIO.write()' afferma esplicitamente che non chiama 'close()' su 'OutputStream': *** Questo metodo non chiude il' OutputStream' fornito dopo il operazione di scrittura completata; è responsabilità del chiamante chiudere il flusso, se lo si desidera. *** –

+0

So che non chiude il flusso. Chiude il flusso che crea internamente. – xehpuk

15

la seguente dichiarazione lavora nella direzione sbagliata:

out.writeTo(b64); 

sovrascrive il Base 64 dati con l'array di byte vuoto di out.

Qual è lo scopo di out? Non penso che tu ne abbia bisogno.

Aggiornamento:

E si scrive l'immagine direttamente os invece di scrivere attraverso il codificatore Base 64.

Il seguente codice dovrebbe funzionare:

... 
ByteArrayOutputStream os = new ByteArrayOutputStream(); 
OutputStream b64 = new Base64.OutputStream(os); 
ImageIO.write(bi, "png", b64); 
String result = os.toString("UTF-8"); 
+0

Il mio javac ha generato un errore. Dice che non riesce a trovare il simbolo, quindi punta a '.' tra' Base64' e 'OutputStream (os)'. Sto usando jdk1.7.0_51 e commons-codec-1.4.jar. – Tgwizman

+1

Ho rimosso il punto ed è ora 'nuovo Base64OutputStream (os)' e l'importazione è 'org.apache.commons.codec.binary.Base64OutputStream'. Funziona – Tgwizman

+0

Ciao!Sto usando esattamente lo stesso codice, ma ottengo sempre java.lang.VerifyError nel 'nuovo costruttore Base64OutputStream (os)'. 'os' è' java.io.ByteArrayOutputStream'. 'Base64OutputStream' è' org.apache.commons.codec.binary.Base64OutputStream' da commons-codec-1.10.jar. Mi sto perdendo qualcosa? – Chechulin

9

Base64 codifica e la decodifica delle immagini utilizzando Java 8:

public static String imgToBase64String(final RenderedImage img, final String formatName) { 
    final ByteArrayOutputStream os = new ByteArrayOutputStream(); 
    try { 
     ImageIO.write(img, formatName, Base64.getEncoder().wrap(os)); 
     return os.toString(StandardCharsets.ISO_8859_1.name()); 
    } catch (final IOException ioe) { 
     throw new UncheckedIOException(ioe); 
    } 
} 

public static BufferedImage base64StringToImg(final String base64String) { 
    try { 
     return ImageIO.read(new ByteArrayInputStream(Base64.getDecoder().decode(base64String))); 
    } catch (final IOException ioe) { 
     throw new UncheckedIOException(ioe); 
    } 
} 

usare in questo modo per lo scenario screenshot:

final Robot robot = new Robot(); 
final Rectangle r = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); 
final BufferedImage bi = robot.createScreenCapture(r); 
final String base64String = imgToBase64String(bi, "png");