最近在做一个项目的时候需要要用的解析图像的拍摄时间,这些信息用图像查看工具基本都可以看到,之前有研究过MP3的文件格式,通过一些Tag来标记文件的一些信息,受此启发,猜测图像应该也有类似的机制。所以网上搜索了一下图像文件的存储格式,然后就查到了Exif
规范,相机在拍照后按照Exif的相关规范,可以将拍摄时间、GPS等信息写入文件,我们按照规范格式将相关信息独取出来就好了,我上传了一份《Exif2.2》的官方文档,有兴趣可以下载查看。
知道了存储的格式,开始动手写代码解析?如果我完全自己动手按照规范解析,还是挺麻烦的,而且我们不需要重复造轮子,网上已经有了相关的库可以实现该功能。
Imaging (previously called Sanselan)
之前写过一篇《Imaging (previously called Sanselan)读取图像信息》,简单的介绍了一下这个库以及用法,下面我们就烂看一下,如何读取metadata信息。
package test;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.common.IImageMetadata;
import org.apache.sanselan.formats.jpeg.JpegImageMetadata;
import org.apache.sanselan.formats.tiff.TiffImageMetadata;
import org.junit.Test;
public class ImageMetaDataTest
{
@Test
public void test() throws Exception
{
File imageFile = new File("C:\\Users\\admin\\Desktop\\mmexport1501076450193.jpg");
sanselan(imageFile);
}
public void sanselan(File file) throws ImageReadException, IOException
{
IImageMetadata metadata = Sanselan.getMetadata(file);
if (metadata == null)
{
return;
}
System.err.println("metadata items:");
ArrayList items = metadata.getItems();
for (Object item : items)
{
System.err.println(item);
}
System.err.println("GPS info:");
if (metadata instanceof JpegImageMetadata)
{
JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
TiffImageMetadata exifMetadata = jpegMetadata.getExif();
if (null != exifMetadata)
{
TiffImageMetadata.GPSInfo gpsInfo = exifMetadata.getGPS();
if (null != gpsInfo)
{
double longitude = gpsInfo.getLongitudeAsDegreesEast();
double latitude = gpsInfo.getLatitudeAsDegreesNorth();
System.err.println("GPS Description: " + gpsInfo);
System.err.println("GPS Longitude (Degrees East): " + longitude);
System.err.println("GPS Latitude (Degrees North): " + latitude);
}
}
}
}
}
在这段示例代码中,我们首先读取图像的MetaData信息和GPS数据,如果我们只需要读取拍摄时间的话,我们可以这样写:
public String getDateBySanselan(File file) throws ImageReadException, IOException
{
IImageMetadata metadata = Sanselan.getMetadata(file);
if (metadata instanceof JpegImageMetadata)
{
JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
TiffField field = jpegMetadata.findEXIFValue(TiffConstants.EXIF_TAG_DATE_TIME_ORIGINAL);
if (field != null)
{
return field.getValueDescription().replace("'", "");
}
}
return null;
}
metadata-extractor
项目地址为:https://github.com/drewnoakes/metadata-extractor
package test;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import org.junit.Test;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
public class ImageMetaDataTest
{
@Test
public void test() throws Exception
{
File imageFile = new File("C:\\Users\\admin\\Desktop\\mmexport1501076450193.jpg");
metadataExtractor(imageFile);
}
public void metadataExtractor(File file) throws ImageProcessingException, IOException
{
Metadata metadata = ImageMetadataReader.readMetadata(file);
for (Directory directory : metadata.getDirectories())
{
System.err.println(directory.getClass());
for (Tag tag : directory.getTags())
{
System.err.println(tag);
}
}
}
}
同样的,上面一段代码也是打印图像的metadata信息,我个人感觉使用该包比Sanselan要方便一些,我们想要获得拍摄时间,只需要这样写:
public Date getDateByMetadataExtractor(File file) throws ImageProcessingException, IOException
{
Metadata metadata = ImageMetadataReader.readMetadata(file);
ExifSubIFDDirectory directory = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
return directory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
}