之前一直想写个读取图片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