最近做了一个关于图片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信息。
<dependency> <groupId>com.drewnoakesgroupId> <artifactId>metadata-extractorartifactId> <version>2.13.0version> 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 IterablegetDirectoryList() { Iterable iterable = metadata.getDirectories(); return iterable; } private List getDir() { List lstDir = new ArrayList (); for (Iterator 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 > getTars() { List > lsttag = new ArrayList >(); 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 > lstTag = getTars(); boolean sgin = true; for (Collection 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 getAllTags() { HashMap map = new HashMap (); List > lstTag = getTars(); for (Collection 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 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封装类的代码。
最后,展示一下具体应用于网站的实际效果: