之前一直想写个读取图片Exif信息的工具,也好方便上传到自己网站上显示,现在终于有时间来写写,只获取关键参数。
下面是完整代码,其中exif规范参考了2个文档,文章附件中应该有下载链接。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Exif
{
#region 枚举
public enum CnType:int
{
焦距 = 0x920A,
ISO = 0x8827,
快门 = 0x9201,
光圈值 = 0x9202,
曝光补偿 = 0x9204,
曝光模式 = 0x8822,
测光模式 = 0x9207,
白平衡 = 0xA403,
闪光灯 = 0x9209,
拍摄时间=0x132,
EXIF版本=0x9000,
镜头=0xA434,
相机=0x110
}
#endregion
internal class Rational
{
private int n;
private int d;
public Rational(int n, int d)
{
this.n = n;
this.d = d;
simplify(ref this.n, ref this.d);
}
public Rational(uint n, uint d)
{
this.n = Convert.ToInt32(n);
this.d = Convert.ToInt32(d);
simplify(ref this.n, ref this.d);
}
public Rational()
{
this.n = this.d = 0;
}
public string ToString(string sp)
{
if (sp == null) sp = "/";
return n.ToString() + sp + d.ToString();
}
public double ToDouble()
{
if (d == 0)
return 0.0;
return Math.Round(Convert.ToDouble(n) / Convert.ToDouble(d), 2);
}
private void simplify(ref int a, ref int b)
{
if (a == 0 || b == 0)
return;
int gcd = euclid(a, b);
a /= gcd;
b /= gcd;
}
private int euclid(int a, int b)
{
if (b == 0)
return a;
else
return euclid(b, a % b);
}
}
public class ExifHelper : IEnumerable
{
private Hashtable properties;
public ExifHelper(System.Drawing.Bitmap bmp)
{
properties = new Hashtable();
var parr = bmp.PropertyItems;
foreach (System.Drawing.Imaging.PropertyItem p in parr)
{
var v = GetValue(p);
properties.Add(p.Id, v);
}
}
public IEnumerator GetEnumerator()
{
return (new EXIFextractorEnumerator(this.properties));
}
public object this[int index]
{
get
{
return properties[index];
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(" 相机:" + this[0x110]);
sb.AppendLine(" 镜头:" + this[0xA434]);
sb.AppendLine(" 焦距:" + this[0x920A]);
sb.AppendLine(" ISO:" + this[0x8827]);
sb.AppendLine(" 快门:" + this[0x9201]);
sb.AppendLine(" 光圈值:" + this[0x9202]);
sb.AppendLine(" 曝光补偿:" + this[0x9204]);
sb.AppendLine(" 曝光模式:" + this[0x8822]);
sb.AppendLine(" 测光模式:" + this[0x9207]);
sb.AppendLine(" 白平衡:" + this[0xA403]);
sb.AppendLine(" 闪光灯:" + this[0x9209]);
sb.AppendLine(" 拍摄时间:" + this[0x132]);
return sb.ToString();
}
private object GetValue(System.Drawing.Imaging.PropertyItem p)
{
Encoding ascii = Encoding.ASCII;
//关于PropertyItem.Type 参照http://msdn.microsoft.com/zh-cn/library/system.drawing.imaging.propertyitem.type(v=VS.80).aspx
if (p.Type == 0x1)
{
return p.Value[0].ToString();
}
//2 = ASCII An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated with NULL.,
else if (p.Type == 0x2)
{
return ascii.GetString(p.Value).Replace("\0", "").Trim();
}
else if (p.Type == 0x3)
{
object v = null;
switch (p.Id)
{
case 0xA403: // 白平衡
{
switch (convertToInt16U(p.Value))
{
case 0: v = "自动"; break;
case 1: v = "手动"; break;
default: v = " reserved"; break;
}
}
break;
case 0x8822: // aperture 曝光模式
switch (convertToInt16U(p.Value))
{
case 0: v = "Not defined"; break;
case 1: v = "手动曝光"; break;
case 2: v = "正常"; break;
case 3: v = "光圈优先"; break;
case 4: v = "快门优先"; break;
case 5: v = "Creative program (biased toward depth of field)"; break;
case 6: v = "Action program (biased toward fast shutter speed)"; break;
case 7: v = "Portrait mode (for closeup photos with the background out of focus)"; break;
case 8: v = "Landscape mode (for landscape photos with the background in focus)"; break;
default: v = "reserved"; break;
}
break;
case 0x9207: // metering mode 测光模式
switch (convertToInt16U(p.Value))
{
case 0: v = "unknown"; break;
case 1: v = "平均测光"; break;
case 2: v = "中央重点平均测光"; break;
case 3: v = "点测光"; break;
case 4: v = "多点测光"; break;
case 5: v = "评价测光"; break;
case 6: v = "局部测光"; break;
case 255: v = "Other"; break;
default: v = "reserved"; break;
}
break;
case 0x9209:
{
switch (convertToInt16U(p.Value))
{
case 0: v = "Flash did not fire"; break;
case 1: v = "Flash fired"; break;
case 5: v = "Strobe return light not detected"; break;
case 7: v = "Strobe return light detected"; break;
case 9: v = "开"; break;
case 16: v = "关"; break;
default: v = "reserved"; break;
}
}
break;
default:
v = convertToInt16U(p.Value).ToString();
break;
}
return v;
}
else if (p.Type == 0x4)
{
return convertToInt32U(p.Value);
}
else if (p.Type == 0x5)
{
byte[] n = new byte[p.Len / 2];
byte[] d = new byte[p.Len / 2];
Array.Copy(p.Value, 0, n, 0, p.Len / 2);
Array.Copy(p.Value, p.Len / 2, d, 0, p.Len / 2);
uint a = convertToInt32U(n);
uint b = convertToInt32U(d);
Rational r = new Rational(a, b);
object v = null;
switch (p.Id)
{
case 0x9202: // aperture
v = "F/" + Math.Round(Math.Pow(Math.Sqrt(2), r.ToDouble()),1);
break;
case 0x920A:
v = r.ToDouble().ToString();
break;
case 0x829A:
v = r.ToDouble().ToString();
break;
case 0x829D: // F-number
v = "F/" + r.ToDouble().ToString();
break;
default:
v = r.ToString("/");
break;
}
return v;
}
else if (p.Type == 0x7)
{
return convertToInt32(p.Value);
}
else if (p.Type == 0xA)
{
byte[] n = new byte[p.Len / 2];
byte[] d = new byte[p.Len / 2];
Array.Copy(p.Value, 0, n, 0, p.Len / 2);
Array.Copy(p.Value, p.Len / 2, d, 0, p.Len / 2);
int a = convertToInt32(n);
int b = convertToInt32(d);
Rational r = new Rational(a, b);
object v = null;
switch (p.Id)
{
case 0x9201: // 快门速度
v = "1/" + Math.Round(Math.Pow(2, r.ToDouble())).ToString();
break;
case 0x9203:
v = Math.Round(r.ToDouble(), 4).ToString();
break;
case 0x9204: //曝光补偿
v = a+"/"+ b;
break;
default:
v = r.ToString("/");
break;
}
return v;
}
else
{
return p.Value;
}
}
int convertToInt32(byte[] arr)
{
if (arr.Length != 4)
return 0;
else
return arr[3] << 24 | arr[2] << 16 | arr[1] << 8 | arr[0];
}
int convertToInt16(byte[] arr)
{
if (arr.Length != 2)
return 0;
else
return arr[1] << 8 | arr[0];
}
uint convertToInt32U(byte[] arr)
{
if (arr.Length != 4)
return 0;
else
return Convert.ToUInt32(arr[3] << 24 | arr[2] << 16 | arr[1] << 8 | arr[0]);
}
uint convertToInt16U(byte[] arr)
{
if (arr.Length != 2)
return 0;
else
return Convert.ToUInt16(arr[1] << 8 | arr[0]);
}
class EXIFextractorEnumerator : IEnumerator
{
Hashtable exifTable;
IDictionaryEnumerator index;
internal EXIFextractorEnumerator(Hashtable exif)
{
this.exifTable = exif;
this.Reset();
index = exif.GetEnumerator();
}
#region IEnumerator Members
public void Reset()
{
this.index = null;
}
public object Current
{
get
{
return (new System.Web.UI.Pair(this.index.Key, this.index.Value));
}
}
public bool MoveNext()
{
if (index != null && index.MoveNext())
return true;
else
return false;
}
#endregion
}
}
}
相关资料:
http://blog.csdn.net/apollokk/article/details/8043202
http://www.cnblogs.com/jxsoft/archive/2012/08/29/2662521.html
http://www.opanda.com/cn/iexif/exif.htm
http://sourceforge.net/projects/libexif/
http://sourceforge.net/projects/openexif/
http://sourceforge.net/projects/exifmdreader/
http://www.codeproject.com/Articles/43665/ExifLibrary-for-NET
珂珂的个人博客 - 一个程序猿的个人网站