zoukankan      html  css  js  c++  java
  • 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;
            }

        }
    }

  • 相关阅读:
    非阻塞式线程安全列表-ConcurrentLinkedDeque
    计数器
    Linux 查看服务器内存使用情况
    Oracle to_date, to_timestamp
    Hibernate session.flush() 使用
    阿里规约认证(题库附答案)
    多态性
    Java数据类型
    String类特点分析
    数组的定义
  • 原文地址:https://www.cnblogs.com/xianyin05/p/3076500.html
Copyright © 2011-2022 走看看