ImageIO读取8x8像素灰度JPEG报Bogus virtual array access如何解决
ImageIO读取小尺寸灰度JPEG抛出"Bogus virtual array access"异常问题
我无法使用ImageIO读取如下这张简单的8x8像素灰度JPEG图片:
复现该问题的最小可运行源码如下:
import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; public class ImageExceptionMain { public static void main(String[] args) throws IOException { ImageIO.read(new File("image.jpg")); } }
程序运行输出的异常信息如下:
Exception in thread "main" javax.imageio.IIOException: Bogus virtual array access at java.desktop/com.sun.imageio.plugins.jpeg.JPEGImageReader.readImage(Native Method) at java.desktop/com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:1334) at java.desktop/com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:1127) at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1470) at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1317) at ImageExceptionMain.main(ImageExceptionMain.java:8)
复现环境信息:
- 操作系统:Ubuntu 22.04 LTS
- Java版本:
OpenJDK Runtime Environment (build 18-ea+36-Ubuntu-1)
测试验证现象:在GIMP中将该图片缩放至16x16像素即可避免触发该异常,但缩放至4x4像素仍会报错。
问题根因
这个报错是OpenJDK自带原生JPEG解码器的已知bug:你当前使用的Java 18早期预览版中,JPEG解码器基于libjpeg的原生实现对单通道灰度图的内存边界计算有缺陷,当图片边长小于等于8像素时,会错误判定虚拟数组访问越界,直接抛出异常。16x16像素的图片边长刚好超过8,避开了出问题的逻辑分支,所以不会报错。
解决方案
- 优先选择升级JDK版本:该bug在Java 18正式版及后续所有Java稳定发行版中都已经修复,直接替换成正式版JDK即可,不需要修改任何业务代码。
- 无法升级JDK时,替换JPEG解码实现:引入纯Java实现的第三方ImageIO JPEG插件(比如TwelveMonkeys的JPEG扩展包)到项目依赖中,原有
ImageIO.read()调用逻辑不需要改动,就可以绕过原生解码器的bug正常读取图片。 - 以上两种方案都无法落地时,从源头上规避:生成这类小尺寸灰度图时,要么将尺寸调整到8像素以上,要么存储为PNG等不存在该解码兼容问题的格式,避免触发bug。
内容的提问来源于stack exchange,提问作者Tordanik
相关产品推荐
相关产品推荐

