最近做了一個關於圖片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封裝類的代碼。
最后,展示一下具體應用於網站的實際效果: