珂珂的个人博客 - 一个程序猿的个人网站

c# 读取图片的Exif 信息

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


上一篇:jUploader上传

下一篇:个人代码全部开源


0 评论

查看所有评论

给个评论吧