一、引言及介绍
最近在开发中用到了metadata-extractor-xxx.jar 和 xmpcore-xxx.jar这个玩意,索性查阅大量文章了解学习,来分享分享。本身工作也是经常和处理大图片打交道,摸索摸索也是多多益善。
首先介绍一下什么是EXIF,EXIF是Exchangeable Image File的缩写,这是一种专门为数码相机照片设定的格式。这种格式可以用来记录数字照片的属性信息,如相机的品牌及型号、相片的拍摄时间、拍摄时所设置的光圈大小、快门速度、ISO等信息。除此之外它还能够记录拍摄数据,以及图片格式化方式,这样就可以输出到兼容EXIF格式的外设上,如照片打印机等。
目前最常见的支持EXIF信息的图片格式是JPG,很多的图像工具都可以直接显示图片的EXIF信息,包括现在的一些著名的相册网站也提供页面用于显示照片的EXIF信息。本文介绍Java如何读取图像的EXIF信息,包括如何根据EXIF信息对图像进行调整以便适合用户浏览。
用BufferedImage类来读的时候,过大的图片时常会抛出OutOfMemoryException异常,挺蛋疼的。
BufferedImage image = ImageIO.read(File file);
目前最简单易用的EXIF信息处理的Java包是 Drew Noakes 写的 metadata-extractor。这是一个能够从图像文件中读取元数据(Exif, IPTC, XMP, ICC等)的简单的Java库,使用简单:
Metadata metadata = ImageMetadataReader.readMetadata(imagePath);该库能了解多种格式的元数据,其中许多可以存在于单个图像:Exif、IPTC、XMP、JFIF / JFXX、ICC Profiles、Photoshop fields、PNG properties、BMP properties、GIF properties
它能处理类型的文件:JPEG、TIFF、PSD、PNG、BMP、GIF、Camera Raw (NEF/CR2/ORF/ARW/RW2/…)
注:并不是每个JPG图像文件都包含有EXIF信息,你可以在Windows资源管理器单击选中图片后,如果该图片包含EXIF信息,则在窗口状态栏会显示出相机的型号。
二、示例代码及描述
下面我们给出一些代码将含有EXIF的图片信息全部打印出来。
示例1):
import java.io.File;import java.util.Iterator;import com.drew.imaging.jpeg.JpegMetadataReader;import com.drew.metadata.Directory;import com.drew.metadata.Metadata;import com.drew.metadata.Tag;import com.drew.metadata.exif.ExifDirectory;/*** 读取图片的EXIF信息*/public class ExifTest {public static void main(String[] args) throws Exception {//包含EXIF信息的图片地址File jpegFile = new File("D:\\XXXX\\XXXX\\XXXX.JPG");Metadata metadata = JpegMetadataReader.readMetadata(jpegFile);Directory exif = metadata.getDirectory(ExifDirectory.class);Iterator tags = exif.getTagIterator();while (tags.hasNext()) {Tag tag = (Tag)tags.next();System.out.println(tag);}}}
示例2:)
public static void main(String[] args) throws Exception {File mFile = new File("F:/XXX.JPG");Metadata metadata = ImageMetadataReader.readMetadata(mFile);for (Directory directory : metadata.getDirectories()) {if("ExifSubIFDDirectory".equalsIgnoreCase( directory.getClass().getSimpleName() )){//光圈F值=镜头的焦距/镜头光圈的直径System.out.println("光圈值: f/" + directory.getString(ExifSubIFDDirectory.TAG_FNUMBER) );System.out.println("曝光时间: " + directory.getString(ExifSubIFDDirectory.TAG_EXPOSURE_TIME)+ "秒" );System.out.println("ISO速度: " + directory.getString(ExifSubIFDDirectory.TAG_ISO_EQUIVALENT) );System.out.println("焦距: " + directory.getString(ExifSubIFDDirectory.TAG_FOCAL_LENGTH) + "毫米" );System.out.println("拍照时间: " + directory.getString(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL) );System.out.println("宽: " + directory.getString(ExifSubIFDDirectory.TAG_EXIF_IMAGE_WIDTH) );System.out.println("高: " + directory.getString(ExifSubIFDDirectory.TAG_EXIF_IMAGE_HEIGHT) );}if("ExifIFD0Directory".equalsIgnoreCase( directory.getClass().getSimpleName() )){System.out.println("照相机制造商: " + directory.getString(ExifIFD0Directory.TAG_MAKE) );System.out.println("照相机型号: " + directory.getString(ExifIFD0Directory.TAG_MODEL) );System.out.println("水平分辨率: " + directory.getString(ExifIFD0Directory.TAG_X_RESOLUTION) );System.out.println("垂直分辨率: " + directory.getString(ExifIFD0Directory.TAG_Y_RESOLUTION) );}}}
示例3):
File mFilePath="C://XXX.jpg";Metadata metadata = com.drew.imaging.jpeg.JpegMetadataReader.readMetadata(mFilePath);JpegDirectory jd = (JpegDirectory)metadata.getDirectory(JpegDirectory.class);System.out.println("————" + jd.getImageHeight()); //图片的高System.out.println("————" + jd.getImageWidth()); //图片的宽//由于只是读取图片的头信息,所以无论多大的图片都能读取,而且速度很快.
从执行的中可以看到照片的详细拍摄时间,拍摄用的相机型号,曝光时间,光圈值,焦距,ISO值 等等。
你也可以直接指定读取其中任意参数的值,ExifDirectory类中定义了很多以 TAG_ 开头的整数常量,这些常量代表特定的一个参数值,,例如要读取相机的型号,可以用下面代码来获取。
可是我要如何在浅薄的纸上为你画上我所有的命轮?