简体   繁体   English

Java BufferedImage转PNG格式Base64字符串

[英]Java BufferedImage to PNG format Base64 String

I'm trying to get a screenshot output as a base64 encoded string but not getting very far.我正在尝试将屏幕截图输出作为 base64 编码的字符串,但并没有得到很远。 The code I have so far uses a Base64 library ( http://iharder.sourceforge.net/current/java/base64/ ):到目前为止,我的代码使用 Base64 库( 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.注意:我不想将 png 写入磁盘上的文件。

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).我遵循了xehpuk 的回答,但是在某些浏览器中通过数据 url 呈现时,某些图像的最后几行像素丢失了问题(Chrome 和 Firefox,Safari 似乎可以很好地呈现它们)。 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 Base64.wrap(OutputStream os) 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 close() isn't called on it.因此,根据数据的长度,最后几个字节可能不会从流中刷新,因为没有调用close() My solution to this was to not bother wrapping the stream and just encode the stream directly:我对此的解决方案是不费心包装流而直接对流进行编码:

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.这解决了在浏览器中呈现时丢失像素行的问题。

The following statement works in the wrong direction:以下语句的工作方向错误:

out.writeTo(b64);

It overwrites the Base 64 data with the empty byte array of out .它用out的空字节数组覆盖 Base 64 数据。

What's the purpose of out anyway? out的目的是什么? I don't think you need it.我不认为你需要它。

Update:更新:

And you write the image directly to os instead of writing through the Base 64 encoder.并且您将图像直接写入os而不是通过 Base 64 编码器写入。

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

Base64 encoding and decoding of images using Java 8:使用 Java 8 对图像进行 Base64 编码和解码:

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

Use it like this for your screenshot scenario:像这样在你的截图场景中使用它:

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

This works for me:这对我有用:

Encode Image to Base64 String将图像编码为 Base64 字符串

public static String encodeToString(BufferedImage image, String type) {
    String imageString = null;
    ByteArrayOutputStream bos = new ByteArrayOutputStream();

    try {
        ImageIO.write(image, type, bos);
        byte[] imageBytes = bos.toByteArray();

        Base64.Encoder encoder = Base64.getEncoder();
        imageString = encoder.encodeToString(imageBytes);

        bos.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return imageString;
}

Decode Base64 String to Image将 Base64 字符串解码为图像

public static BufferedImage decodeToImage(String imageString) {
    BufferedImage image = null;
    byte[] imageByte;
    try {
        Base64.Decoder decoder = Base64.getDecoder();
        imageByte = decoder.decode(imageString);
        ByteArrayInputStream bis = new ByteArrayInputStream(imageByte);
        image = ImageIO.read(bis);
        bis.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return image;
}

Actually, the combination of two different solutions worked for me.实际上,两种不同解决方案的组合对我有用。 My use case is to read images from a zip file.我的用例是从 zip 文件中读取图像。 Here is the code that worked for me :这是对我有用的代码:

BufferedImage bgTileSprite = ImageIO.read(inputStream);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(bgTileSprite, "png", os);
String result = Base64.getEncoder().encodeToString(os.toByteArray());
LOGGER.info(result);

I Confirmed the result by converting the result to actual image.我通过将结果转换为实际图像来确认结果。 It works wonder.它的作用很神奇。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM