【问题标题】:Convert BufferedImage into byte[] without I/O无需 I/O 将 BufferedImage 转换为 byte[]
【发布时间】:2012-05-01 10:03:41
【问题描述】:

您好,我在内存中有一个 BufferedImage 实例,出于性能考虑,我想将其转换为 byte[] 以编码为 base64 字符串而无需 I/O 操作。我使用的是以下 API:

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

但是,该 API 仍然会隐式地将镜像写入 OS 临时目录,如果底层 OS 临时目录已满,无法创建临时文件,则会导致失败。 堆栈跟踪:

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)

是否有一种高效的(如内存转换或高效的 I/O)方法可以在没有 I/O 的情况下进行转换?请指教。

【问题讨论】:

  • 我……很惊讶会发生这种情况。
  • 这几乎可以肯定是 JVM 中的一个错误。你试过最新版本吗?
  • @PeterLawrey:你为什么认为这是一个错误?有一整班FileCacheImageOutputStream。但是我根本不知道ImageIO 中的这种机制。
  • 恕我直言,磁盘缓存在填满驱动器之前不应自动写入数据。你的浏览器最后一次因为它填满你的驱动器而崩溃是什么时候。 ;)
  • 有没有办法在不使用 ImageIO 的情况下做到这一点?我遇到了类似的问题,但出于性能原因,我想使用替代方法

标签: java bufferedimage javax.imageio in-memory


【解决方案1】:

通过ImageIO.setUseCache()方法禁用ImageIO缓存:

ImageIO.setUseCache(false);

根据javadoc默认开启:

设置一个标志,指示在创建 ImageInputStreams 和 ImageOutputStreams 时是否应使用基于磁盘的缓存文件。

从标准 InputStream 读取时>,可能需要将先前读取的信息保存在缓存中,因为底层流不允许重新读取数据。类似地,当写入标准的 OutputStream 时,可以使用缓存来允许在将之前写入的值刷新到最终目的地之前对其进行更改。

缓存可能驻留在主内存或磁盘上。将此标志设置为 false 将禁止将磁盘用于未来的流,这在处理小图像时可能是有利的,因为创建和销毁文件的开销被消除了。

在启动时,该值设置为 true。

【讨论】:

    【解决方案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();
    

    【讨论】:

    • 似乎,它不再是真的,至少在 1.8 中。 com.sun.imageio.spi.OutputStreamImageOutputStreamSpi#createOutputStreamInstance 不检查流的类型,但会检查 useCache 参数。无论如何,如果有一种方法可以在本地禁用缓存,那就太好了。
    • @sedovav 上述解决方案确实提供了一种“本地”禁用磁盘缓存的方法。当您像这样直接创建 MemoryCacheImageOutputStream 时,您永远不会碰到 Spi,所以无论它做什么都是无关紧要的。 PS:请注意,ImageOutputSream 不是 OutputStream 的子类,尽管它的名称。为此,还有一个单独的 ImageIO.write 重载。
    • 确实如此。非常感谢!
    【解决方案3】:

    默认情况下,即使您只使用流,ImageIO 也会将其缓存写入磁盘。尝试禁用缓存:

    ImageIO.setUseCache(false);
    

    【讨论】:

      【解决方案4】:

      ((DataBufferByte)img.getRaster().getDataBuffer()).getData() 如果您的图像是字节格式,则自动返回一个字节数组。根本不需要任何 IO。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-05-23
        • 2020-02-16
        • 2013-02-12
        • 2018-09-05
        • 2011-06-08
        • 2014-07-21
        • 1970-01-01
        • 2012-11-30
        相关资源
        最近更新 更多