Java BufferedImage to PNG format Base64 String

2022-09-01 12:50:13

I'm trying to get a screenshot output as a base64 encoded string but not getting very far. The code I have so far uses a Base64 library ( http://iharder.sourceforge.net/current/java/base64/ ):

    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");

Each time I run this, "result" is always an empty string but I don't understand why. Any ideas?

Note: I don't want to have to write the png to a file on disk.


答案 1

I followed xehpuk's answer but had issues with certain images having the last few rows of pixels missing when rendered in certain browsers via a data url (Chrome and Firefox, Safari seemed to render them fine). I suspect this is because the browser is doing it's best to interpret the data but the last few bytes of data was missing so it shows what it can.

The wrapping of the output stream seems to be the cause of this problem. The documentation for explains: Base64.wrap(OutputStream os)

It is recommended to promptly close the returned output stream after use, during which it will flush all possible leftover bytes to the underlying output stream.

So depending on the length of the data, it's possible the last few bytes are not flushed from the stream because isn't called on it. My solution to this was to not bother wrapping the stream and just encode the stream directly:close()

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);
  }
}

This resolved the issues with the missing rows of pixels when rendered in a browser.


答案 2

The following statement works in the wrong direction:

out.writeTo(b64);

It overwrites the Base 64 data with the empty byte array of .out

What's the purpose of anyway? I don't think you need it.out

Update:

And you write the image directly to instead of writing through the Base 64 encoder.os

The following code should work:

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

推荐