C# 获取图片的EXIF 信息
关于 EXIF 信息的介绍。
1 EXIF,是英文Exchangeable Image File(可交换图像文件)的缩写。EXIF是一种图像文件格式,只是文件的后缀名为jpg。EXIF信息是由数码相机在拍摄过程中采集一系列的信息,然后把信息放置在jpg文件的头部,也就是说EXIF信息是镶嵌在JPEG图像文件格式内的一组拍摄参数,主要包括摄影时的光圈、快门、ISO、日期时间等各种与当时摄影条件相关的讯息,相机品牌型号,色彩编码,拍摄时录制的声音以及全球定位系统(GPS)等信息。不管是硬件厂商的配套软件还是专业名门的看图工具,所有这些软件都是为了方便数码摄影者能更方便地保存查看摄影图像的重要信息。
2 如何获取EXIF信息
在.NET中,我们可以用PropertyItem对象来获取jpg 图片的EXIF信息。取得PropertyItem很简单。
Image img = Image.FromFile("支持Exif的图片文件路径");
PropertyItem[] pt = img.PropertyItems;
这样就可以了,Exif信息都已载入到PropertyItem数组中了。其中PropertyItem的ID,Type,Value属性是最重要的。
ID可以唯一表明当前PropertyItem的含义。比如,0x010F代表相机制造商,0x8827代表ISO速度,0x829D代表相机。
Value永远都是字节数组,但具体内容的取值方法随Type不同而不同。
Type是个整数,表示的类型在MSDN中是这么描述的:
1 指定 Value 为字节数组。
2 指定 Value 为空终止 ASCII 字符串。如果将类型数据成员设置为 ASCII 类型,则应该将 Len 属性设置为包括空终止的字符串长度。例如,字符串“Hello”的长度为 6
3 指定 Value 为无符号的短(16 位)整型数组。
4 指定 Value 为无符号的长(32 位)整型数组。
5 指定 Value 数据成员为无符号的长整型对数组。每一对都表示一个分数;第一个整数是分子,第二个整数是分母。
6 指定 Value 为可以包含任何数据类型的值的字节数组。
7 指定 Value 为有符号的长(32 位)整型数组。
10 指定 Value 为有符号的长整型对数组。每一对都表示一个分数;第一个整数是分子,第二个整数是分母。
所以获取Exif信息的算法重点在于如何根据Type值将Value字节数组变成人类可以理解的值。
public void FindExifinfo(string filePath)
{
Image img = Image.FromFile(filePath);
PropertyItem[] pt = img.PropertyItems;
for (int i = 0; i < pt.Length; i++)
{
PropertyItem p = pt[i];
switch (pt[i].Id)
{ // 设备制造商 20.
case 0x010F:
this.textBox1.Text = System.Text.ASCIIEncoding.ASCII.GetString(pt[i].Value);
break;
case 0x0110: // 设备型号 25.
this.textBox4.Text = GetValueOfType2(p.Value);
break;
case 0x0132: // 拍照时间 30.
this.textBox2.Text = GetValueOfType2(p.Value);
break;
case 0x829A: // .曝光时间
this.textBox3.Text = GetValueOfType5(p.Value)+" sec";
break;
case 0x8827: // ISO 40.
this.textBox5.Text = GetValueOfType3(p.Value);
break;
case 0x010E: // 图像说明info.description
this.textBox6.Text = GetValueOfType2(p.Value);
break;
case 0x920a: //相片的焦距
this.textBox7.Text = GetValueOfType5A(p.Value) + " mm";
break;
case 0x829D: //相片的光圈值
this.textBox8.Text = GetValueOfType5A(p.Value);
break;
default:
break;
}
}
}
public string GetValueOfType2(byte[] b)// 对type=2 的value值进行读取
{
return System.Text.Encoding.ASCII.GetString(b);
}
private static string GetValueOfType3(byte[] b) //对type=3 的value值进行读取
{
if (b.Length != 2) return "unknow";
return Convert.ToUInt16(b[1] << 8 | b[0]).ToString();
}
private static string GetValueOfType5(byte[] b) //对type=5 的value值进行读取
{
if (b.Length != 8) return "unknow";
UInt32 fm, fz;
fm = 0;
fz = 0;
fz = Convert.ToUInt32(b[7] << 24 | b[6] << 16 | b[5] << 8 | b[4]);
fm = Convert.ToUInt32(b[3] << 24 | b[2] << 16 | b[1] << 8 | b[0]);
return fm.ToString() + "/" + fz.ToString()+" sec";
}
private static string GetValueOfType5A(byte[] b)//获取光圈的值
{
if (b.Length != 8) return "unknow";
UInt32 fm, fz;
fm = 0;
fz = 0;
fz = Convert.ToUInt32(b[7] << 24 | b[6] << 16 | b[5] << 8 | b[4]);
fm = Convert.ToUInt32(b[3] << 24 | b[2] << 16 | b[1] << 8 | b[0]);
double temp = (double)fm / fz;
return (temp).ToString();
}
一下是运行效果图: