这两天在处理网络图片数据时,需要对不同格式的图片采用不用的处理办法,这就需要掌握图片的格式识别。结合这两天的学习内容,对其进行总结,以备将来不时之需。
常见的图片格式有jpg(jpeg),png,gif这三种,可以分别通过字符创的contains(“jpg”);contains(“png”); contains(“gif”) 来获取对应格式的图片,这种方法我认为是简单粗暴的,识别率一般情况下也会很高,但是,有的url中包含的 jpg 这个字符,却是一个 gif 格式的图片,比如说下面这个链接(http://img4.imgtn.bdimg.com/it/u=14736324,2917249387&fm=214&gp=0.jpg),他实质上是一个 gif 文件,可是如两种显示它是一个 jpg 文件。这种情况下直接通过 url 去识别就不正确了,所以就需要下面的解决方法。
通过二进制流我总结有两种解决方法。
package com.myapp.image;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
/**
* Created by lionel on 16/12/2.
*/
public class ImageFormat {
//第一种方法,只适用于判断 gif 格式和 png 格式
public static String getImageFormat(String url) {
String imageFormat = "";
HttpURLConnection conn;
InputStream inputStream = null;
byte[] buffer = new byte[4];
int len;
try {
URL url1 = new URL(url);
conn = (HttpURLConnection) url1.openConnection();
inputStream = conn.getInputStream();
len = inputStream.read(buffer);
if (len == 4 && buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F') {
imageFormat = "gif";
} else if (len == 4 && buffer[1] == 'P' && buffer[2] == 'N' && buffer[3] == 'G') {
imageFormat = "png";
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return imageFormat;
}
//第二种方法:使用 javax.ImageIo类
public static String getImageFormat2(String url) {
String picFormat = "";
try {
File file = File.createTempFile("tmp", "jpg");
URL url1 = new URL(url);
URLConnection connection = url1.openConnection();
InputStream inputStream = connection.getInputStream();
byte[] bytes = new byte[1024];
int len;
OutputStream outputStream = new FileOutputStream(file);
while ((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
}
outputStream.close();
inputStream.close();
ImageInputStream imageInputStream = ImageIO.createImageInputStream(file);
Iterator iterator = ImageIO.getImageReaders(imageInputStream);
if (!iterator.hasNext()) {
throw new RuntimeException("No readers found!");
}
ImageReader reader = iterator.next();
picFormat = reader.getFormatName();
} catch (IOException e) {
e.printStackTrace();
}
return picFormat;
}
//第三种方法:使用metadata-extractor工具包
public static String getImageFormat3(String url) {
HttpURLConnection conn = null;
InputStream is = null;
try {
URL uri = new URL(url);
conn = (HttpURLConnection) uri.openConnection();
is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
FileType fileType = com.drew.imaging.FileTypeDetector.detectFileType(bis);
return fileType.name();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
@Test
public void test() {
System.out.println(ImageFormat.getImageFormat("http://heilongjiang.sinaimg.cn/2016/0713/U11780P1274DT20160713151843.gif"));//gif
System.out.println(ImageFormat.getImageFormat("http://img01.lianzhong.com/upload/newbbs/2013/03/06/562/128564577804426.png"));//png
}
@Test
public void test2() {
System.out.println(ImageFormat.getImageFormat2("http://mmbiz.qpic.cn/mmbiz_gif/bTTVNfzmRM8Xmc0YsntZGSlBZCnPYLOBLTqXAoac53kRUJU3wUic0qQhJRCxYpf6F4g8MYfIXaY2SOwcwQnxXSw/0?wx_fmt=gif"));//gif
System.out.println(ImageFormat.getImageFormat2("http://mmbiz.qpic.cn/mmbiz_jpg/bTTVNfzmRM8Xmc0YsntZGSlBZCnPYLOB2msB91o8lzwVK5kAtibh93FE9YqwsTaTU6SZUgRUwfdgD3Bxqib3v9hw/0?wx_fmt=jpeg"));//JPEG
System.out.println(ImageFormat.getImageFormat2("http://www.pooban.com/forum/attachments/month_0803/20080312_efbadda4f99208eddd17Wvc0F7LaegE2.png"));//png
}
@Test
public void test3(){
System.out.println(ImageFormat.getImageFormat3("http://img01.lianzhong.com/upload/newbbs/2013/03/06/562/128564577804426.png"));
System.out.println(ImageFormat.getImageFormat3("http://heilongjiang.sinaimg.cn/2016/0713/U11780P1274DT20160713151843.gif"));
System.out.println(ImageFormat.getImageFormat3("http://mmbiz.qpic.cn/mmbiz_jpg/bTTVNfzmRM8Xmc0YsntZGSlBZCnPYLOB2msB91o8lzwVK5kAtibh93FE9YqwsTaTU6SZUgRUwfdgD3Bxqib3v9hw/0?wx_fmt=jpeg"));
}
第一种方法中,如果图片的格式是 gif 的,则对应的二进制流的buffer[0],buffer[1],buffer[2]分别返回的是’G’,’I’,’F’的 Ascii 码;如果图片的格式是 png 的,则对应的二进制流的buffer[1],buffer[2],buffer[3]分别返回的是’P’,’N’,’G’的 Ascii 码,有兴趣的同学可以自己测试下,但是如果是 jpeg 或者 jpg 的,则对应的流,就我自己而言,无法找出规律。第二种方法是把文件暂时写到本地文件中,然后通过ImageIO类中的方法来获取文件对应的格式。第三种方法:使用metadata-extractor工具包。其实质和第一种方法一样,通过阅读文件的前几个字节流来判断图片格式。要想了解具体过程可以去github进行阅读。
最后,我想讲一下 google 最近出的一种图片格式-webp,这种格式的图片有些浏览器不支持查看,如 safari 和 firefox ,以下的 url 就不能查看:
http://mmbiz.qpic.cn/mmbiz/HZIIEPB0r1zh8HuU1Ytk9NaYhEJkXticqicCu4zTvEABpvINyI1FfcHEfEic7sGK4JLaZ9bOGJ6jmWuZmKTYH63HQ/640?wx_fmt=jpeg&tp=webp&wxfrom=5
http://mmbiz.qpic.cn/mmbiz/SRbibgDh1zOswibjegzOHnwyGOuXexaK4ggpHFejhdiaN2eQz6pGvZhFgPEicziaTDEQBmaEk1bdGVeyONe2YC0qoSQ/640?wxfrom=5&wx_fmt=jpeg&tp=webp
http://mmbiz.qpic.cn/mmbiz/SRbibgDh1zOswibjegzOHnwyGOuXexaK4gZ4WMa8hdg2iacZic3SaYA2NEcjjjeGZShd3FSbzVgM3ejXVnOWXTIvPQ/640?wxfrom=5&wx_fmt=jpeg&tp=webp
有什么办法可以查看了?
告诉一个小窍门,就是把 url 中 &tp=webp 这一块去掉就可以了
上面的三个 url 修改后如下所示:
http://mmbiz.qpic.cn/mmbiz/HZIIEPB0r1zh8HuU1Ytk9NaYhEJkXticqicCu4zTvEABpvINyI1FfcHEfEic7sGK4JLaZ9bOGJ6jmWuZmKTYH63HQ/640?wx_fmt=jpeg&wxfrom=5
http://mmbiz.qpic.cn/mmbiz/SRbibgDh1zOswibjegzOHnwyGOuXexaK4ggpHFejhdiaN2eQz6pGvZhFgPEicziaTDEQBmaEk1bdGVeyONe2YC0qoSQ/640?wxfrom=5&wx_fmt=jpeg
http://mmbiz.qpic.cn/mmbiz/SRbibgDh1zOswibjegzOHnwyGOuXexaK4gZ4WMa8hdg2iacZic3SaYA2NEcjjjeGZShd3FSbzVgM3ejXVnOWXTIvPQ/640?wxfrom=5&wx_fmt=jpeg
这样就可以去 safari 和 firefox 下查看了。
还有另外一种方法,就是使用 webp-imageIo 对图片进行处理,具体内容可以去官网进行学习,下面附上我测试的代码:
public void test() {
File file1 = new File("/usr/local/a.webp");
File file = new File("/usr/local/b.jpg");
try {
BufferedImage image = ImageIO.read(file1);
if (image != null) {
ImageIO.write(image, "jpg", file);
}
System.out.println(image == null);
} catch (IOException e) {
e.printStackTrace();
}
}
注意在官网中有这样一段介绍:
Ensure libwebp-imageio.so, libwebp-imageio.dylib or webp-imageio.dll is accessible on the Java native library path (java.library.path system property)
就是在执行代码前需要把根据你用的操作系统来选择其中的包,比如,mac 就选libwebp-imageio.dylib 放在你的java.library.path 路径下,要是不知道路径在哪的话,可以执行 System.out.println(System.getProperty(“java.library.path”))打印出来看看,然后把文件拷贝到其中一个路径下面就可以了。