C#读取JPEG图片中Exif信息

C#读取JPEG图片中Exif信息

抽空把C++代码改为C#代码了,发现C#不如C语言来的灵活,类型转换还是,唉...

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing.Imaging;
using System.Reflection;
using System.IO;

namespace Exif
{

    public struct TIFDEntry
    {
        public int tag;         // Tag的含义可以查阅TIFF的规范文档
        public int type;        // 指明此Entry中记录的数据类型,TIFF规范只定义了五种类型,EXIF增加了三种
        public int size;        // 大小
        public int val;         // 取值, 根据type含义会改变
    };

    public class ExifReader
    {
        const int SOI = 0xD8;       // 图像开始 
        const int APP0 = 0xE0;      // JFIF应用数据块 
        const int APP1 = 0xE1;      // Exif数据块(APP1)
        const int MAX_WORD = 65535;

        bool jpegFault;
        bool APP0Fault;
        bool ExifFault;

        FileStream fs = null;
        long pos = 0;               // 流中的位置
        bool isLittleEndian;        // 低字节是否在前

        byte[] stringData;
        int index = 0;              // (stringData中的位置)
        List<TIFDEntry> entries = new List<TIFDEntry>();

        JPEGInfo info = new JPEGInfo();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="filePath">图片路径</param>
        public ExifReader(string filePath)
        {
            jpegFault = false;
            APP0Fault = false;
            ExifFault = false;

            try
            {
                fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);

                if (!readSOI())
                {
                    jpegFault = true;
                    return;
                }

                if (!readAPP0())
                {
                    APP0Fault = true;
                }

                if (!readExif())
                {
                    ExifFault = true;
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                    fs.Dispose();
                }
            }
        }

        // 读取SOI段
        private bool readSOI()
        {
            byte[] title = new byte[2];
            fs.Seek(pos, SeekOrigin.Begin);
            fs.Read(title, 0, 2);
            pos = fs.Position;

            if (title[0] != 0xFF || title[1] != SOI)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        // 读取APP0段
        private bool readAPP0()
        {
            byte[] title = new byte[2];
            fs.Seek(pos, SeekOrigin.Begin);
            fs.Read(title, 0, 2);
            pos = fs.Position;

            if (title[0] != 0xFF || title[1] != APP0)
            {
                pos -= 2;
                return false;
            }

            byte[] len = new byte[2];
            fs.Seek(pos, SeekOrigin.Begin);
            fs.Read(len, 0, 2);
            pos = fs.Position;

            int length = (len[0] << 8) + len[1];    // APP0段长度
            byte[] data = new byte[length - 2];
            fs.Seek(pos, SeekOrigin.Begin);
            fs.Read(data, 0, data.Length);
            pos = fs.Position;

            // 处理APP0的数据(TIFF格式)
            // ......
            //Encoding.ASCII.GetString(data, 0, length - 2);

            return true;
        }

        // 读取APP1段
        private bool readExif()
        {
            byte[] title = new byte[2];
            fs.Seek(pos, SeekOrigin.Begin);
            fs.Read(title, 0, 2);
            pos = fs.Position;

            if (title[0] != 0xFF || title[1] != APP1)
            {
                return false;
            }

            byte[] len = new byte[2];
            fs.Seek(pos, SeekOrigin.Begin);
            fs.Read(len, 0, 2);
            pos = fs.Position;

            int length = (len[0] << 8) + len[1];    // APP1段长度
            stringData = new byte[length - 2];
            fs.Seek(pos, SeekOrigin.Begin);
            fs.Read(stringData, 0, stringData.Length);
            pos = fs.Position;

            string strExifHeader = Encoding.ASCII.GetString(stringData, index, 6);          // 获得EXIF Header
            // TIFF Image File Header开始
            index += 6;

            if (stringData[index] == 'I' && stringData[index + 1] == 'I')                   // 读取字节顺序方式
            {
                isLittleEndian = true;
            }
            else
            {
                isLittleEndian = false;
            }

            byte[] bysFlag = GetBytes(stringData, index + 2, 2);            // Flag(0x2A)
            byte[] bysOffset = GetBytes(stringData, index + 4, 4);          // 第一个IFD的偏移量
            int offset = BytesToUint(bysOffset);

            readIFD(offset);

            foreach (TIFDEntry entry in entries)
            {
                analyseTIFD(entry);
            }

            return true;
        }

        private void readIFD(int offset)
        {
            byte[] bysEntryCount = GetBytes(stringData, index + offset, 2);    // Entry个数
            int numOfIFD = BytesToInt(bysEntryCount);

            for (int i = 0; i < numOfIFD; i++)
            {
                entries.Add(createFromIndex(offset + 2 + 12 * i));
            }

            byte[] bysOffsetOfNext = GetBytes(stringData, index + offset + 2 + 12 * numOfIFD, 4);
            int offsetOfNext = BytesToUint(bysOffsetOfNext);

            if (offsetOfNext != 0)
            {
                readIFD(offsetOfNext);
            }

        }

        private TIFDEntry createFromIndex(int offset)
        {
            TIFDEntry entry = new TIFDEntry();
            entry.tag = BytesToInt(GetBytes(stringData, index + offset, 2));
            entry.type = BytesToInt(GetBytes(stringData, index + offset + 2, 2));
            entry.size = BytesToUint(GetBytes(stringData, index + offset + 4, 4));
            entry.val = BytesToUint(GetBytes(stringData, index + offset + 8, 4));
            return entry;
        }


        private void analyseTIFD(TIFDEntry entry)
        {
            switch (entry.tag)
            {
                case 0x010E:   // 图像说明
                    info.description = getEntryASCII(entry);
                    break;

                case 0x010F:   // 制造厂商
                    info.maker = getEntryASCII(entry);
                    break;

                case 0x0110:   // 型号
                    info.model = getEntryASCII(entry);
                    break;

                case 0x011A:   // x分辩率
                    info.xResolution = getEntryRational(entry);
                    break;

                case 0x011B:   // y分辩率
                    info.yResolution = getEntryRational(entry);
                    break;

                case 0x0128:   // 分辩率单位
                    info.resolutionUnit = entry.val;
                    break;

                case 0x0131:   // 创建软件名称
                    info.software = getEntryASCII(entry);
                    break;

                case 0x0132:   // 创建时间
                    info.createTime = getEntryASCII(entry);
                    break;

                case 0x0213:   // YCbCr位置
                    info.YCbCrPosition = entry.val;
                    break;

                case 0x8298:   // 版权信息
                    info.copyright = getEntryASCII(entry);
                    break;

                case 0x8769:   // Exif末尾
                    //readIFD(entry.val);
                    break;

                case 0x0103:   // 压缩信息
                    info.compression = entry.val;
                    break;

                case 0x829A:   // 曝光时间
                    info.exposureTime = getEntryRational(entry);
                    break;

                case 0x829D:   // F-值
                    info.fNumber = getEntryRational(entry);
                    break;

                case 0x8822:   // 曝光设定
                    info.exposureProgram = entry.val;
                    break;

                case 0x8827:   // ISO速率
                    info.ISOSpeedRatings = entry.val;
                    break;

                case 0x9003:   // 拍摄时间
                    info.orgTime = getEntryASCII(entry);
                    break;

                case 0x9004:   // 被软件修改的时间
                    info.digTime = getEntryASCII(entry);
                    break;

                case 0x9102:   // 每像素压缩位数
                    info.compressBit = getEntryRational(entry);
                    break;

                case 0x9201:   // 快门速度
                    info.shutterSpeed = getEntrySRational(entry);
                    break;

                case 0x9202:   // 光圈值
                    info.aperture = getEntryRational(entry);
                    break;

                case 0x9204:   // 曝光补偿值
                    info.exposureBias = getEntrySRational(entry);
                    break;

                case 0x9205:   // 最大光圈
                    info.maxAperture = getEntryRational(entry);
                    break;

                case 0x9207:   // 测光模式
                    info.meteringMode = entry.val;
                    break;

                case 0x9208:   // 光源
                    info.lightSource = entry.val;
                    break;

                case 0x9209:   // 闪光灯
                    info.flash = entry.val;
                    break;

                case 0x920a:   // 焦距
                    info.focalLength = getEntryRational(entry);
                    break;

                /* case 0x927c:
                   makerNote = getEntryUndefined(entry);
                   cout << makerNote << endl;
                   break;*/

                case 0xa001:   // 色彩空间
                    info.colorSpace = entry.val;
                    break;

                case 0xa002:   // Exif宽度
                    info.width = entry.val;
                    break;

                case 0xa003:   // Exif高度
                    info.height = entry.val;
                    break;

                case 0xa215:   // 曝光指数
                    info.exposureIndex = getEntryRational(entry);
                    break;

                case 0xa217:
                    info.sensingMethod = entry.val;
                    break;
            }

        }

        /// <summary>
        /// 获取图片信息
        /// </summary>
        /// <returns>JPEG信息</returns>
        public JPEGInfo GetJPEGInfo()
        {
            return info;
        }

        //取指定偏移量的byte数组
        private byte[] GetBytes(byte[] bys, int offset, int length)
        {
            byte[] retBytes = new byte[length];
            for (int i = 0; i < length; i++)
            {
                retBytes[i] = bys[i + offset];
            }
            return retBytes;
        }

        //2byte数组转int
        private int BytesToInt(byte[] bstr)
        {
            if (isLittleEndian)
            {
                return (bstr[1] << 8) + bstr[0];
            }
            else
            {
                return (bstr[0] << 8) + bstr[1];
            }
        }
        //4byte数组转int
        private int BytesToUint(byte[] bstr)
        {
            if (isLittleEndian)
            {
                return (bstr[3] << 24) + (bstr[2] << 16) + (bstr[1] << 8) + bstr[0];
            }
            else
            {
                return (bstr[0] << 24) + (bstr[1] << 16) + (bstr[2] << 8) + bstr[3];
            }
        }

        private string getEntryASCII(TIFDEntry entry)
        {
            string ret = string.Empty;

            if (entry.type != 2)
            {
                return ret;
            }
            ret = Encoding.ASCII.GetString(stringData, index + entry.val, entry.size);
            return ret;
        }

        private string getEntryUndefined(TIFDEntry entry)
        {
            string ret = string.Empty;

            if (entry.type != 7)
            {
                return ret;
            }

            if (entry.size > 4)
            {
                ret = Encoding.ASCII.GetString(stringData, index + entry.val, entry.size);
            }
            return ret;
        }

        private string getEntrySRational(TIFDEntry entry)
        {
            string ret = string.Empty;
            int a = 0;
            int b = 1;

            if (entry.type != 10)
            {
                return ret;
            }

            byte[] data = GetBytes(stringData, entry.val, 4);
            a = (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
            data = GetBytes(stringData, entry.val + 4, 4);
            b = (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
            ret = string.Format("{0}/{1}", a, b);
            return ret;
        }

        private string getEntryRational(TIFDEntry entry)
        {
            string ret = string.Empty;
            int a = 0;
            int b = 1;

            if (entry.type != 5)
            {
                return ret;
            }

            byte[] data = GetBytes(stringData, entry.val, 4);
            a = BytesToUint(data);
            data = GetBytes(stringData, entry.val + 4, 4);
            b = BytesToUint(data);
            ret = string.Format("{0}/{1}", a, b);
            return ret;
        }

    }
}

posted on 2013-05-13 21:25  大胡子青松  阅读(795)  评论(0编辑  收藏  举报

导航