前些日子接到了一个需求,要求代码中计算一个网络图片的宽高,于是我想到了ImageIO.read(URL url)方法,很快就开发完了这个功能,可是到了生产后就懵逼了,很多图片地址读取不到内容。
图片都是七牛服务器的地址,全是jpg格式,在网页中显示也没有问题,这是为什么呢?
一开始有同事说图片有问题,有可能是图片原本不是jpg格式,后来直接重命名为jpg格式导致的,于是乎我下载了一张图片,在本地测试了一下,完美通过测试,应该不是这个问题。
那就应该是网络问题了,我跟了一下源码,发现在筛选ImageReaderSpi对象的时候,返回了空,jpg图片应该命中JPEGImageReaderSpi才对。又跟了一次源码,在JPEGImageReaderSpi的canDecodeInput(Object source)方法中,我发现图片流返回的前两个字节分别是0x1F和0x8B,导致这个校验返回false。百度了一下,这两个字节应该是gzip流的标识符,猜测这个图片地址是经过gzip处理之后的图片流。
那么是不是我在经过GZIPInputStream处理一下就OK了?
写个单元测试吧。
@Test
public void testReadImage() throws IOException {
String urlStr = "http://img5.mtime.cn/mg/2019/07/19/104427.91760942_235X132X4.jpg";
BufferedImage image = readImage(urlStr);
System.out.println(String.format("size: %d * %d", image.getWidth(), image.getHeight()));
}
private static BufferedImage readImage(String urlStr) throws IOException {
InputStream is = new URL(urlStr).openStream();
BufferedInputStream bis = new BufferedInputStream(is);
if (isGzip(bis)) {
return ImageIO.read(new GZIPInputStream(bis));
} else {
return ImageIO.read(bis);
}
}
private static boolean isGzip(BufferedInputStream is) throws IOException {
is.mark(0);
int b1 = is.read();
int b2 = is.read();
is.reset();
return b1 == 0x1F && b2 == 0x8B;
}
测试通过。