最近做了一个关于图片blog的系统,当中涉及到大量的图片上传与下载,这也是blog工程无法避免的。
对于上传图片来说,有很多开源java代码可供选择,今天这里要说的是一个比较特殊,需求中很少遇到的情况,
那就是,对于图片中,如果存在元数据(Exif)信息时,需要怎么读取?
什么是Exif?
它是一组,专门为数码相机照片设定的数据存储信息(包括拍摄日期、数码相机功能信息等数据),可附加于JPEG、TIFF、RIFF等文件之中,
它是由 日本电子工业发展协会在1996年制定的,抛却民族情怀,日本人真的有很多值得学习的方面。
我们该怎么解决?
有了这个需求,那么现在就需要为客户解决这个问题了。既然我们已经知道Exif是什么东西了,那么自然就会有针对它的办法出现。
之前,查找了好些关于这个方面的资料,很多人说出了很多办法,更有甚者说可以结合C++进行处理的方式,这个就有点过了。
个人觉得,解决问题还是要本着实际环境范围内来思考,要是天马行空的想象一通则毫无意义,你干脆说把人家日本工业协会的接口封装打包给你调用算了,这根本不可能的事情!
但好在,坚信办法永远要比困难多的强大信心,发现,在这个美丽多彩的java世界里,早已经有巨人为我们提供了更优秀的解决办法。
最后,我决定还是站在巨人的肩膀上一路向前吧!毕竟个人的精力是有限的!
到此,解决方向找到了,那就是采用 metadata-extractor 完全可以进行处理Exif数据信息。
砍柴必先利其器,所以准备工具如下:
Java包:metadata-extractor-2.13.0.jar
Eclipse:Eclipse IDE for Enterprise Java Developers. Version: 2020-03 (4.15.0)
Maven:apache-maven-3.6.3
个人比较喜欢采用Maven来构建项目,所以毫无疑问,首先来配置一段pom.xml信息。
<!-- https://mvnrepository.com/artifact/com.drewnoakes/metadata-extractor -->
<dependency>
<groupId>com.drewnoakes</groupId>
<artifactId>metadata-extractor</artifactId>
<version>2.13.0</version>
</dependency>
构建完之后,废话就不多说了,直接上核心代码,分享成果:
package music.tools;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
/**
* 图片Exif标签帮助类
*
* @author Mcqueen Xing (邢志)
* @date 2016年5月12日上午9:20:26
*
*/
public class ExifHelper {
Metadata metadata = null;
public ExifHelper(File f) throws Exception {
metadata = ImageMetadataReader.readMetadata(f);
}
public ExifHelper(String path) throws Exception {
File f = new File(path);
metadata = ImageMetadataReader.readMetadata(f);
}
public ExifHelper(InputStream is) throws Exception {
metadata = ImageMetadataReader.readMetadata(is);
}
/**
* 获取Exif信息文件夹
*
* @author Mcqueen Xing (邢志)
* @date 2016年5月12日 上午10:10:57
* @return
*/
private Iterable<Directory> getDirectoryList() {
Iterable<Directory> iterable = metadata.getDirectories();
return iterable;
}
private List<Directory> getDir() {
List<Directory> lstDir = new ArrayList<Directory>();
for (Iterator<Directory> iter = getDirectoryList().iterator(); iter
.hasNext();) {
Directory dr = iter.next();
lstDir.add(dr);
}
return lstDir;
}
/**
* 获取Exif Directory 对象下的 Tag 集合
*
* @author Mcqueen Xing (邢志)
* @date 2016年5月12日 上午10:29:18
* @return
*/
private List<Collection<Tag>> getTars() {
List<Collection<Tag>> lsttag = new ArrayList<Collection<Tag>>();
for (Directory d : getDir()) {
lsttag.add(d.getTags());
}
return lsttag;
}
/**
* 获取不同的 Exif 分类文件夹名称
*
* @author Mcqueen Xing (邢志)
* @date 2016年5月12日 上午10:29:57
* @param type
* @return
*/
private String getExifDirectoryName(int type) {
String directoryName = "File";
switch (type) {
case 1:
directoryName = "Exif SubIFD";
break;
case 2:
directoryName = "Exif IFD0";
break;
case 3:
directoryName = "JFIF";
break;
case 4:
directoryName = "JPEG";
break;
case 5:
directoryName = "File";
default:
break;
}
return directoryName;
}
/**
* 指定键获取 Exif 元数据的属性值.
*
* @author Mcqueen Xing (邢志)
* @date 2016年5月12日 上午10:21:01
* @param tagKey
* Tag 键名称
* @param type
* 获取类型:1.Exif SubIFD; 2.Exif IFD0; 3.JFIF; 4.JPEG; 5.File;
* @return
*/
public String getTagByKey(String tagKey, int type) {
String tagValue = "";
if (type > 5)
return tagValue;
List<Collection<Tag>> lstTag = getTars();
boolean sgin = true;
for (Collection<Tag> tagColl : lstTag) {
if (!sgin)
break;
for (Tag tag : tagColl) {
if (tag.getTagName().equals(tagKey)
&& tag.getDirectoryName().equals(
getExifDirectoryName(type))) {
tagValue = tag.getDescription();
sgin = false;
break;
}
}
}
return tagValue;
}
/**
* 获取图片的所有 Exif 信息.
*
* @author Mcqueen Xing (邢志)
* @date 2016年5月12日 上午10:21:01
* @param tagKey
* Tag 键名称
* @param type
* 获取类型:1.Exif SubIFD; 2.Exif IFD0; 3.JFIF; 4.JPEG; 5.File;
* @return
*/
public HashMap<String, String> getAllTags() {
HashMap<String, String> map = new HashMap<String, String>();
List<Collection<Tag>> lstTag = getTars();
for (Collection<Tag> tagColl : lstTag) {
for (Tag tag : tagColl) {
map.put(tag.getTagName(), tag.getDescription());
// System.out.println(tag.getTagName() + ":" +
// tag.getDescription() + "[" + tag.getDirectoryName() + "]");
}
}
return map;
}
/**
* 获取 Exif 日期元数据.
*
* @author Mcqueen Xing (邢志)
* @date 2016年5月12日 上午11:36:20
* @return
*/
public String getExifDateTime(boolean ishash) {
String currentTime = "";
if (!ishash) {
currentTime = getTagByKey("Date/Time Original", 1);
if (currentTime != "") {
currentTime = currentTime.split(" ")[0].replace(':', '-') + " "
+ currentTime.split(" ")[1];
} else {
currentTime = getTagByKey("File Modified Date", 5);
if (currentTime.indexOf("CST") > -1
|| currentTime.indexOf("GMT") > -1) {
currentTime = DateHelper
.TransferEnglishDateTime(currentTime);
} else {
currentTime = DateHelper.FormatDateToString(new Date(), 1);
}
}
} else {
currentTime = getExifDateTimeByKeyFromHashMap("Date/Time Original");
if (currentTime != null && !currentTime.equals("")) {
// Tue Jun 22 09:28:12 CST 2010
if (currentTime.indexOf("CST") >= 0
|| currentTime.indexOf("GMT") >= 0) {
currentTime = DateHelper
.TransferEnglishDateTime(currentTime);
} else {
currentTime = currentTime.split(" ")[0].replace(':', '-')
+ " " + currentTime.split(" ")[1];
}
} else {
currentTime = getExifDateTimeByKeyFromHashMap("File Modified Date");
if ((currentTime != null)) {
if (currentTime.indexOf("CST") > -1
|| currentTime.indexOf("GMT") > -1)
currentTime = DateHelper
.TransferEnglishDateTime(currentTime);
} else {
currentTime = DateHelper.FormatDateToString(new Date(), 1);
}
}
}
return currentTime;
}
/**
* 获取 Exif 日期元数据.通过属性名称.
*
* @author Mcqueen Xing (邢志)
* @date 2016年5月12日 上午11:36:20
* @return
*/
/*
* public String getExifDateTime(){ return ""; }
*/
private String getExifDateTimeByKeyFromHashMap(String key) {
HashMap<String, String> hash = getAllTags();
return hash.get(key);
}
/**
* 获取 Exif 相机制造商信息
*
* @author Mcqueen Xing (邢志)
* @date 2016年5月12日 上午11:47:03
* @return
*/
public String getExifMake() {
String make = "";
make = getTagByKey("Make", 2);
return make;
}
/**
* 获取 Exif 相机型号信息
*
* @author Mcqueen Xing (邢志)
* @date 2016年5月12日 上午11:47:03
* @return
*/
public String getExifModel() {
String model = "";
model = getTagByKey("Model", 2);
return model;
}
}
使用方法,如图:
为了避免Copy行为的懒惰造成思维生疏,此处采用截图展示,如何引用Exif封装类的代码。
最后,展示一下具体应用于网站的实际效果: