数码照片的文件高级信息获取

        ////调用
        string strfile = "fffff.jpg";//文件名
        System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(strfile);
        exif.exifextractor er = new exif.exifextractor(ref bmp, " ");
        string a = strfile + "</br>";
        foreach (exif.pair pr in er)
        {
            a += pr.first + ":" + pr.second + "<br />";
        }
        div1.InnerHtml = a;
--------------------------------------------------------------------------------------------------------------------------
 translation类:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
 
namespace exif
{
    /// <summary>
    /// summary description for translation.
    /// </summary>
    public class translation : Hashtable
    {
        /// <summary>
        /// 
        /// </summary>
        public translation()
        {
            this.Add(0x8769, "exif ifd_Exif 子IFD的偏移量");//Exif 子IFD的偏移量
            this.Add(0x8825, "gps ifd");//GPSInfo
            this.Add(0xfe, "new subfile type");//NewSubfileType
            this.Add(0xff, "subfile type");//SubfileType
 
            //表示缩略图的大小.
            this.Add(0x100, "image width_缩略图的大小");
            this.Add(0x101, "image height_缩略图的大小");
 
            this.Add(0x102, "bits per sample_当图像格式没有经过压缩, 这个值表示每像素的比特位的数目");//当图像格式没有经过压缩, 这个值表示每像素的比特位的数目. 通常这个值是 '8,8,8'
            this.Add(0x103, "compression_压缩的方式");//代表压缩的方式. '1' 表示非压缩, '6' 表示JPEG 压缩格式.
            this.Add(0x106, "photometric interp_图像数据组件的色彩空间");//表示图像数据组件的色彩空间. '1' 意味着单色, '2'表示 RGB, '6' 表示 YCbCr.
            this.Add(0x107, "thresh holding");
            this.Add(0x108, "cell width");
            this.Add(0x109, "cell height");
            this.Add(0x10a, "fill order");
            this.Add(0x10d, "document name");
            this.Add(0x10e, "image description_描述图像");//用来描述图像. 双字节的字符码不能使用, 如 中文/韩文/日文.
            this.Add(0x10f, "equip make_数字相机的制造商");//表示数字相机的制造商. 在 Exif 标准中, 这个标签是可选的, 但是在DCF中它是必需的.
            this.Add(0x110, "equip model_数字相机的模块代码");//表示数字相机的模块代码. 在 Exif 标准中, 这个标签是可选的, 但在DCF中它也是必需的.
            this.Add(0x111, "strip offsets_图像数据的偏移量");//如果图像格式没有经过压缩, 这个值表示的是到图像数据的偏移量. 在图像数据被分割的 情况下它有多个值.
            //当拍照时, 相机相对于场景的方向. 在右边表示的是'0th row' 以及 '0th column' 在视觉位置上的关系.
            //Value|0th Row   |0th Column
            //1    |top       |left side
            //2    |top       |right side
            //3    |bottom    |right side
            //4    |bottom    |left side
            //5    |left side |top
            //6    |right side|top
            //7    |right side|bottom
            //8    |left side |bottom
            this.Add(0x112, "orientation_相机相对于场景的方向");
            this.Add(0x115, "samples perpixel_每个像素中存储的组件数目");//如果图像格式没有经过压缩, 这个值表示每个像素中存储的组件数目. 在彩色图像中, 此值为 '3'.
            this.Add(0x116, "rows per strip_每条数据带存储了多少行数据");//如果图像格式没有经过压缩 并且 图像被分割存储, 这个值表示每条数据带存储了多少行数据 . 如果图像没有被分割, 它与ImageLength(0x0101)同值.
            this.Add(0x117, "strip bytes count_每条数据带使用了多少字节的 数据 且 有多个值");//如果图像格式没有经过压缩 并且 图像被分割存储, 这个值表示每条数据带使用了多少字节的 数据 且 有多个值. 如果图像没有被分割, 它只有一个且表示为图像的所有数据的大小.
            this.Add(0x118, "min sample value");
            this.Add(0x119, "max sample value");
 
            //图像的 显示/打印 分辨率. 缺省值是 1/72英寸, 但是它没有意义因为个人PC在 显示/打印 图像的时候不使用这个值.
            this.Add(0x11a, "x resolution_图像的 显示/打印 分辨率");
            this.Add(0x11b, "y resolution_图像的 显示/打印 分辨率");
 
            this.Add(0x11c, "planar config_YCbCr数据的字节对齐顺序");//如果图像格式是非压缩YCbCr的, 这个值表示YCbCr数据的字节对齐顺序. '1', 表示Y/Cb/Cr值是一个 chunky format, 对于每个子采样像素都是连续的. '2', 则表示Y/Cb/Cr 值被分割存储在 Y plane/Cb plane/Cr plane 格式中.
            this.Add(0x11d, "page name");
            this.Add(0x11e, "x position");
            this.Add(0x11f, "y position");
            this.Add(0x120, "free offset");
            this.Add(0x121, "free byte counts");
            this.Add(0x122, "gray response unit");
            this.Add(0x123, "gray response curve");
            this.Add(0x124, "t4 option");
            this.Add(0x125, "t6 option");
            this.Add(0x128, "resolution unit_分辨率单位");//XResolution(0x011a)/YResolution(0x011b)的单位. '1' 表示没有单位, '2' 意味着英寸, '3' 表示厘米. 缺省值是 '2'(英寸).
            this.Add(0x129, "page number");
            this.Add(0x12d, "transfer funcition");
            this.Add(0x131, "software used_显示固件的版本号");//显示固件的版本号(数字相机的内部控制软件).
            this.Add(0x132, "date time_图像最后一次被修改时的日期/时间");//图像最后一次被修改时的日期/时间. 日期的格式是 "YYYY:MM:DD HH:MM:SS"+0x00, 一共 20个字节. 如果没有设置时钟或者数字相机没有时钟, 则这个域是用空格来填充. 通常, 它和DateTimeOriginal(0x9003)具有相同的值
            this.Add(0x13b, "artist");
            this.Add(0x13c, "host computer");
            this.Add(0x13d, "predictor");
            this.Add(0x13e, "white point_定义图像白点");//定义图像白点(white point/白点:在彩色分色、照相或摄影时作为色彩平衡测量用途的参考点) 的色度(chromaticity). 如果图像是用CIE标准照度 D65(著名的是 '光线/daylight'的国际标准), 这个值是 '3127/10000,3290/10000'.
            this.Add(0x13f, "primary chromaticities_定义图像的原始色度");//定义图像的原始色度. 如果图像使用 CCIR 推荐 709原始色度, 则这个值是 '640/1000,330/1000,300/1000,600/1000,150/1000,0/1000'.
            this.Add(0x140, "colormap");
            this.Add(0x141, "halftone hints");
            this.Add(0x142, "tile width");
            this.Add(0x143, "tile length");
            this.Add(0x144, "tile offset");
            this.Add(0x145, "tile bytecounts");
            this.Add(0x14c, "inkset");
            this.Add(0x14d, "ink names");
            this.Add(0x14e, "number of inks");
            this.Add(0x150, "dot range");
            this.Add(0x151, "target printer");
            this.Add(0x152, "extra samples");
            this.Add(0x153, "sample format");
            this.Add(0x154, "s min sample value");
            this.Add(0x155, "s max sample value");
            this.Add(0x156, "transfer range");
            this.Add(0x200, "jpeg proc_照片的拍摄模式");//表示照片的拍摄模式. 第一个值的意思是 0=正常, 1=未知, 2=快速, 3=全景. 第二个值意思是序列号, 第三个值表示全景的方向 1=从左到右, 2=从右到左, 3=从下到上, 4=从上到下.
            this.Add(0x201, "jpeg interformat_到 JPEG 数据的偏移量");//当图像格式是JPEG时, 这个值表示到 JPEG 数据的偏移量.
            this.Add(0x202, "jpeg interlength_JPEG 图像的数据大小");//当图像格式是JPEG时, 表示JPEG 图像的数据大小.
            this.Add(0x203, "jpeg restartinterval");
            this.Add(0x205, "jpeg losslesspredictors");
            this.Add(0x206, "jpeg pointtransforms");
            this.Add(0x207, "jpeg qtables_固件版本");//表示固件版本.
            this.Add(0x208, "jpeg dctables_包含 ASCII 格式的数据");//包含 ASCII 格式的数据如 [PictureInfo]. 它跟老的奥林帕斯数码相机(没有采用Exif 数据格式, 如C1400/C820/D620/D340等)采用相同的数据格式.
            this.Add(0x209, "CameraID 的数据");//包含CameraID 的数据, 用户可以使用客户端工具来改变它的内容
            this.Add(0x211, "ycbcr coefficients_转换成 RGB格式的一个常量");//当图像的格式是 YCbCr(JPEG的格式), 这个值表示转换成 RGB格式的一个常量. 通常, 这个值是'0.299/0.587/0.114'.
            this.Add(0x212, "ycbcr subsampling_有多少个色度数据被采样了");//当图像格式是YCbCr时 并且 使用子采样(色度数据的剪切值, 所有的数字相机都使用)时, 这个值表示有多少个色度数据被采样了. 首先第一个值表示水平的, 下一个值表示垂直的 采样率.
            this.Add(0x213, "ycbcr positioning_定义了被采样的像素阵列的色度采样点");//当图像格式是YCbCr时 并且 使用子采样(色度数据的剪切值, 所有的数字相机都使用)时, 这个值定义了被采样的像素阵列的色度采样点. '1' 表示像素阵列的中心, '2' 表示基准点(0,0).
            this.Add(0x214, "ref black white_黑点/白点的参考值");//表示黑点/白点的参考值. 在 YCbCr 格式的情况下, 前两个表示了Y的黑/白, 下两个是 Cb, 最后两个是 Cr. 在 RGB 的情况下, 前两个表示R的黑/白, 下两个是 G, 最后两个是 B.
            this.Add(0x8773, "icc profile");
            this.Add(0x301, "gamma");
            this.Add(0x302, "icc profile descriptor");
            this.Add(0x303, "srgb renderingintent");
            this.Add(0x320, "image title");
            this.Add(0x8298, "copyright_版权信息");//表示版权信息
            this.Add(0x5001, "resolution x unit");
            this.Add(0x5002, "resolution y unit");
            this.Add(0x5003, "resolution x lengthunit");
            this.Add(0x5004, "resolution y lengthunit");
            this.Add(0x5005, "print flags");
            this.Add(0x5006, "print flags version");
            this.Add(0x5007, "print flags crop");
            this.Add(0x5008, "print flags bleed width");
            this.Add(0x5009, "print flags bleed width scale");
            this.Add(0x500a, "halftone lpi");
            this.Add(0x500b, "halftone lpiunit");
            this.Add(0x500c, "halftone degree");
            this.Add(0x500d, "halftone shape");
            this.Add(0x500e, "halftone misc");
            this.Add(0x500f, "halftone screen");
            this.Add(0x5010, "jpeg quality");
            this.Add(0x5011, "grid size");
            this.Add(0x5012, "thumbnail format");
            this.Add(0x5013, "thumbnail width");
            this.Add(0x5014, "thumbnail height");
            this.Add(0x5015, "thumbnail colordepth");
            this.Add(0x5016, "thumbnail planes");
            this.Add(0x5017, "thumbnail rawbytes");
            this.Add(0x5018, "thumbnail size");
            this.Add(0x5019, "thumbnail compressedsize");
            this.Add(0x501a, "color transfer function");
            this.Add(0x501b, "thumbnail data");
            this.Add(0x5020, "thumbnail imagewidth");
            this.Add(0x502, "thumbnail imageheight");
            this.Add(0x5022, "thumbnail bitspersample");
            this.Add(0x5023, "thumbnail compression");
            this.Add(0x5024, "thumbnail photometricinterp");
            this.Add(0x5025, "thumbnail imagedescription");
            this.Add(0x5026, "thumbnail equipmake");
            this.Add(0x5027, "thumbnail equipmodel");
            this.Add(0x5028, "thumbnail stripoffsets");
            this.Add(0x5029, "thumbnail orientation");
            this.Add(0x502a, "thumbnail samplesperpixel");
            this.Add(0x502b, "thumbnail rowsperstrip");
            this.Add(0x502c, "thumbnail stripbytescount");
            this.Add(0x502d, "thumbnail resolutionx");
            this.Add(0x502e, "thumbnail resolutiony");
            this.Add(0x502f, "thumbnail planarconfig");
            this.Add(0x5030, "thumbnail resolutionunit");
            this.Add(0x5031, "thumbnail transferfunction");
            this.Add(0x5032, "thumbnail softwareused");
            this.Add(0x5033, "thumbnail datetime");
            this.Add(0x5034, "thumbnail artist");
            this.Add(0x5035, "thumbnail whitepoint");
            this.Add(0x5036, "thumbnail primarychromaticities");
            this.Add(0x5037, "thumbnail ycbcrcoefficients");
            this.Add(0x5038, "thumbnail ycbcrsubsampling");
            this.Add(0x5039, "thumbnail ycbcrpositioning");
            this.Add(0x503a, "thumbnail refblackwhite");
            this.Add(0x503b, "thumbnail copyright");
            this.Add(0x5090, "luminance table");
            this.Add(0x5091, "chrominance table");
            this.Add(0x5100, "frame delay");
            this.Add(0x5101, "loop count");
            this.Add(0x5110, "pixel unit");
            this.Add(0x5111, "pixel perunit x");
            this.Add(0x5112, "pixel perunit y");
            this.Add(0x5113, "palette histogram");
            this.Add(0x829a, "exposure time_曝光时间");//曝光时间 (快门速度的倒数). 单位是秒.
            this.Add(0x829d, "f-number_拍照时的光圈");//拍照时的光圈F-number(F-stop).
            this.Add(0x8822, "exposure prog_拍照时相机使用的曝光程序");//拍照时相机使用的曝光程序. '1' 表示手动曝光, '2' 表示正常程序曝光, '3' 表示光圈优先曝光, '4' 表示快门优先曝光, '5' 表示创意程序(慢速程序), '6' 表示动作程序(高速程序), '7'表示 肖像模式, '8' 表示风景模式.
            this.Add(0x8824, "spectral sense");
            this.Add(0x8827, "iso speed_CCD 的感光度");//CCD 的感光度, 等效于 Ag-Hr 胶片的速率.
            this.Add(0x8828, "oecf");
            this.Add(0x9000, "ver_Exif 的版本号");//Exif 的版本号. 用4个ASCII字符来存储. 如果图片是基于Exif V2.1的, 这个值是 "0210". 因为它不是一个用NULL(0x00)来终结的字符串,所以这里的类型是 'undefined'.
            this.Add(0x9003, "dtorig_照片在被拍下来的日期/时间");//照片在被拍下来的日期/时间. 使用用户的软件是不能被修改这个值的. 日期的格式是 "YYYY:MM:DD HH:MM:SS"+0x00, 一共占用20个字节. 如果数字相机没有设置时钟或者 数字相机没有时钟, 这个域使用空格来填充. 在Exif标准中, 这个标签是可选的, 但是在 DCF中是必需的.
            this.Add(0x9004, "dtdigitized_照片被数字化时的日期/时间");//照片被数字化时的日期/时间. 通常, 它与DateTimeOriginal(0x9003)具有相同的值. 数据格式是 "YYYY:MM:DD HH:MM:SS"+0x00, 一共占用20个字节. 如果数字相机没有设置时钟或者 数字相机没有时钟, 这个域使用空格来填充. 在Exif标准中, 这个标签是可选的, 但是在 DCF中是必需的.
            this.Add(0x9101, "compconfig_像素数据的顺序");//表示的是像素数据的顺序. 大多数情况下RGB格式使用 '0x04,0x05,0x06,0x00' 而YCbCr 格式使用 '0x01,0x02,0x03,0x00'. 0x00:并不存在, 其他的对应关系为 0x01:Y, 0x02:Cb, 0x03:Cr, 0x04:Red, 0x05:Green, 0x06:Bllue.
            this.Add(0x9102, "compbpp_平均压缩率");//JPEG (粗略的估计)的平均压缩率.
            this.Add(0x9201, "shutter speed_出的快门速度");//用APEX表示出的快门速度. 为了转换成原始的 'Shutter Speed'; 则先要计算2的ShutterSpeedValue次幂, 然后求倒数. 例如, 如果 ShutterSpeedValue 是 '4', 快门速度则是1/(24)=1/16秒.
            this.Add(0x9202, "aperture_拍照时镜头的光圈");//拍照时镜头的光圈. 单位是 APEX. 为了转换成普通的 F-number(F-stop), 则要先计算出根号2 2 (=1.4142)的ApertureValue次幂. 例如, 如果ApertureValue 是 '5', F-number 就等于1.41425 = F5.6.
            this.Add(0x9203, "brightness_被拍摄对象的明度");//被拍摄对象的明度, 单位是 APEX. 为了从BrigtnessValue(Bv)计算出曝光量(Ev), 你必须加上 SensitivityValue(Sv).     Ev=Bv+Sv Sv=log2(ISOSpeedRating/3.125)    ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32.
            this.Add(0x9204, "exposure bias_照片拍摄时的曝光补偿");//照片拍摄时的曝光补偿. 单位是APEX(EV).
            this.Add(0x9205, "maxaperture_镜头的最大光圈值");//镜头的最大光圈值. 你可以通过计算根号2的MaxApertureValue次幂来转换成普通的光圈 F-number (跟ApertureValue:0x9202的处理过程一样).
            this.Add(0x9206, "subjectdist_到焦点的距离");//到焦点的距离, 单位是米.
            this.Add(0x9207, "metering mode_曝光的测光方法");//曝光的测光方法. '0' 表示未知, '1' 为平均测光, '2' 为中央重点测光, '3' 是点测光, '4' 是多点测光, '5' 是多区域测光, '6' 部分测光, '255' 则是其他.
            this.Add(0x9208, "lightsource_光源, 实际上是表示白平衡设置");//光源, 实际上是表示白平衡设置. '0' 意味着未知, '1'是日光, '2'是荧光灯, '3' 白炽灯(钨丝), '10' 闪光灯, '17' 标准光A, '18' 标准光B, '19' 标准光C, '20' D55, '21' D65, '22' D75, '255' 为其他.
            this.Add(0x9209, "flash_闪光灯");//'0' 表示闪光灯没有闪光, '1' 表示闪光灯闪光, '5' 表示闪光但没有检测反射光, '7' 表示闪光且检测了反射光.
            this.Add(0x920a, "focallength_拍摄照片时的镜头的焦距长度");//拍摄照片时的镜头的焦距长度. 单位是毫米.
            this.Add(0x927c, "_maker note制造商的内部数据");//制造商的内部数据. 一些制造商如 Olympus/Nikon/Sanyo 等在这个区域中使用IFD 格式的数据.
            //存储用户的注释. 这个标签允许使用两字节的德字符或者 unicode. 前8 个字节描述的是字符集. 'JIS' 是日文 (著名的有 Kanji).
            //'0x41,0x53,0x43,0x49,0x49,0x00,0x00,0x00':ASCII
            //'0x4a,0x49,0x53,0x00,0x00,0x00,0x00,0x00':JIS
            //'0x55,0x4e,0x49,0x43,0x4f,0x44,0x45,0x00':Unicode
            //'0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00':Undefined
            this.Add(0x9286, "user comment_存储用户的注释");
 
            //一些数字相机每秒能拍摄 2~30 张照片, 但是DateTime/DateTimeOriginal/DateTimeDigitized 标签只能记录到秒单位的时间. SubsecTime 标签就是用来记录秒后面的数据(微秒).
            //例如, DateTimeOriginal = "1996:09:01 09:15:30", SubSecTimeOriginal = "130", 合并起来的原始的拍摄 时间就是 "1996:09:01 09:15:30.130" 
            this.Add(0x9290, "dtsubsec_拍摄微秒时间");
            this.Add(0x9291, "dtorigss_拍摄微秒时间");
            this.Add(0x9292, "dtdigss_拍摄微秒时间");
 
            this.Add(0xa000, "fpxver_存储FlashPix 的版本信息");//存储FlashPix 的版本信息. 如果图像数据是基于 FlashPix formar Ver.1.0, 则这个值为 "0100". 因为它不是一个用NULL(0x00)来终结的字符串,所以这里的类型是 'undefined'.
            this.Add(0xa001, "colorspace_定义色彩空间");//定义色彩空间. DCF 图像必须使用 sRGB 色彩空间因此这个值总是 '1'. 如果这个照片使用了 其他的色彩空间, 这个值是 '65535':未校准(Uncalibrated).
 
            //主图像的尺寸大小.
            this.Add(0xa002, "pixxdim_主图像的尺寸大小Width");//ExifImageWidth
            this.Add(0xa003, "pixydim_主图像的尺寸大小Height");//ExifImageHeight
 
            this.Add(0xa004, "relatedwav_音频数据的名字");//如果数字相机能够纪录图像的音频数据, 则表示音频数据的名字.
            this.Add(0xa005, "interop_扩展");//表示这是一个扩展"ExifR98", 细节未知. 这个值经常是IFD格式的数据. 当前这儿有两个 目录项, 第一个是 Tag0x0001, 值是"R98", 下一个是 Tag0x0002, 它的值为 "0100".
            this.Add(0xa20b, "flashenergy");
            this.Add(0xa20c, "spatialfr");
 
            //表示CCD的像素密度. 如果你的相机是百万像素的并且是用低分辨率(如VGA模式) 来拍摄照片, 这个值可以通过照片的分辨率来重新采样. 在这种情况下, FocalPlaneResolution 就不是CCD的实际的分辨率.
            this.Add(0xa20e, "focalxres_CCD的像素密度");
            this.Add(0xa20f, "focalyres_CCD的像素密度");
 
            //FocalPlaneXResoluton/FocalPlaneYResolution的单位. '1' 表示没有单位, '2'是英寸inch, '3' 表示厘米. 
            //注意:一些Fujifilm的数码相机(如.FX2700,FX2900,Finepix4700Z/40i 等) 使用的值是 '3' 所以它的单位一定是 '厘米' , 但是它们的分辨率单位就变成'8.3mm?'(1/3in.?). 这是Fuji 的 BUG? 从Finepix4900Z 开始这个值就使用 '2' 了但仍然跟实际的值不吻合.
            this.Add(0xa210, "focalresunit_FocalPlaneXResoluton/FocalPlaneYResolution的单位");
 
            this.Add(0xa214, "subject loc");
            this.Add(0xa215, "exposure index");//跟ISOSpeedRatings(0x8827)一样但是数据类型是 unsigned rational. 只有Kodak的数字相机使用 这个标签来替代 ISOSpeedRating, 我不知道这是为什么(历史原因?).
            this.Add(0xa217, "sensing method_图像传感器单元的类型");//表示图像传感器单元的类型. '2' 意味着这是一个芯片颜色区域传感器, 几乎所有的数字相机都 使用这个类型.
            this.Add(0xa300, "filesource_显示图像来源");//显示图像来源. 值 '0x03' 表示图像源是数字定格相机.
            this.Add(0xa301, "scenetype_拍摄场景的类型");//表示拍摄场景的类型. 值 '0x01' 表示图像是通过相机直接拍摄出来的.
 
            //表示色彩过滤阵列(CFA) 几何模式.
            //长度类型意义
            //2    shortHorizontal repeat pixel unit = n
            //2    shortVertical repeat pixel unit = m
            //1    byteCFA value[0,0]
            //:     :       :
            //1    byteCFA value[n-1,0]
            //1    byteCFA value[0,1]
            //:     :       :
            //1    byteCFA value[n-1,m-1]
            //色彩过滤和CFA值之间的关系.
            //Filter ColorRedGreenBlueCyanMagentaYellowWhite
            //CFA value    01    2    3    4    5    6
            //RG例如, 普通的 RGB 过滤器使用左表的副本, 这个值是 '0x0002,0x0002,0x00,0x01,0x01,0x02'. 
            //GB
            this.Add(0xa302, "cfapattern_色彩过滤阵列(CFA) 几何模式");
 
            this.Add(0x0, "gps ver");
            this.Add(0x1, "gps latituderef");
            this.Add(0x2, "gps latitude");
            this.Add(0x3, "gps longituderef");
            this.Add(0x4, "gps longitude");
            this.Add(0x5, "gps altituderef");
            this.Add(0x6, "gps altitude");
            this.Add(0x7, "gps gpstime");
            this.Add(0x8, "gps gpssatellites");
            this.Add(0x9, "gps gpsstatus");
            this.Add(0xa, "gps gpsmeasuremode");
            this.Add(0xb, "gps gpsdop");
            this.Add(0xc, "gps speedref");
            this.Add(0xd, "gps speed");
            this.Add(0xe, "gps trackref");
            this.Add(0xf, "gps track");
            this.Add(0x10, "gps imgdirref_纪录图像文件的文件格式");//纪录图像文件的文件格式. 这个值是 ascii 字符串(如. "Exif JPEG Ver. 2.1").
            this.Add(0x11, "gps imgdir");
            this.Add(0x12, "gps mapdatum");
            this.Add(0x13, "gps destlatref");
            this.Add(0x14, "gps destlat");
            this.Add(0x15, "gps destlongref");
 
            //地址0x0016~0x0017处存放的数据为0x6987, 表示下一个标签是 ExifOffset(0x8769). 这就是 指向 Exif子IFD的偏移量
            this.Add(0x16, "gps destlong_指向 Exif子IFD的偏移量");
            this.Add(0x17, "gps destbearref_指向 Exif子IFD的偏移量");
 
            this.Add(0x18, "gps destbear");
            this.Add(0x19, "gps destdistref");
            this.Add(0x1a, "gps destdist");
        }
    }
    /// <summary>
    /// private class
    /// </summary>
    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);
        }
    }
}
--------------------------------------------------------------------------------------------------------------------------
exifextractor类: 
using System;
using System.Text;
using System.Collections;
using System.Drawing.Imaging;
using System.Reflection;
using System.IO;
 
namespace exif
{
    /// <summary>
    /// exifextractor class
    /// 
    /// </summary>
    public class exifextractor : IEnumerable
    {
        /// <summary>
        /// get the individual property value by supplying property name
        /// these are the valid property names :
        /// 
        /// "exif ifd"
        /// "gps ifd"
        /// "new subfile type"
        /// "subfile type"
        /// "image width"
        /// "image height"
        /// "bits per sample"
        /// "compression"
        /// "photometric interp"
        /// "thresh holding"
        /// "cell width"
        /// "cell height"
        /// "fill order"
        /// "document name"
        /// "image description"
        /// "equip make"
        /// "equip model"
        /// "strip offsets"
        /// "orientation"
        /// "samples perpixel"
        /// "rows per strip"
        /// "strip bytes count"
        /// "min sample value"
        /// "max sample value"
        /// "x resolution"
        /// "y resolution"
        /// "planar config"
        /// "page name"
        /// "x position"
        /// "y position"
        /// "free offset"
        /// "free byte counts"
        /// "gray response unit"
        /// "gray response curve"
        /// "t4 option"
        /// "t6 option"
        /// "resolution unit"
        /// "page number"
        /// "transfer funcition"
        /// "software used"
        /// "date time"
        /// "artist"
        /// "host computer"
        /// "predictor"
        /// "white point"
        /// "primary chromaticities"
        /// "colormap"
        /// "halftone hints"
        /// "tile width"
        /// "tile length"
        /// "tile offset"
        /// "tile bytecounts"
        /// "inkset"
        /// "ink names"
        /// "number of inks"
        /// "dot range"
        /// "target printer"
        /// "extra samples"
        /// "sample format"
        /// "s min sample value"
        /// "s max sample value"
        /// "transfer range"
        /// "jpeg proc"
        /// "jpeg interformat"
        /// "jpeg interlength"
        /// "jpeg restartinterval"
        /// "jpeg losslesspredictors"
        /// "jpeg pointtransforms"
        /// "jpeg qtables"
        /// "jpeg dctables"
        /// "jpeg actables"
        /// "ycbcr coefficients"
        /// "ycbcr subsampling"
        /// "ycbcr positioning"
        /// "ref black white"
        /// "icc profile"
        /// "gamma"
        /// "icc profile descriptor"
        /// "srgb renderingintent"
        /// "image title"
        /// "copyright"
        /// "resolution x unit"
        /// "resolution y unit"
        /// "resolution x lengthunit"
        /// "resolution y lengthunit"
        /// "print flags"
        /// "print flags version"
        /// "print flags crop"
        /// "print flags bleed width"
        /// "print flags bleed width scale"
        /// "halftone lpi"
        /// "halftone lpiunit"
        /// "halftone degree"
        /// "halftone shape"
        /// "halftone misc"
        /// "halftone screen"
        /// "jpeg quality"
        /// "grid size"
        /// "thumbnail format"
        /// "thumbnail width"
        /// "thumbnail height"
        /// "thumbnail colordepth"
        /// "thumbnail planes"
        /// "thumbnail rawbytes"
        /// "thumbnail size"
        /// "thumbnail compressedsize"
        /// "color transfer function"
        /// "thumbnail data"
        /// "thumbnail imagewidth"
        /// "thumbnail imageheight"
        /// "thumbnail bitspersample"
        /// "thumbnail compression"
        /// "thumbnail photometricinterp"
        /// "thumbnail imagedescription"
        /// "thumbnail equipmake"
        /// "thumbnail equipmodel"
        /// "thumbnail stripoffsets"
        /// "thumbnail orientation"
        /// "thumbnail samplesperpixel"
        /// "thumbnail rowsperstrip"
        /// "thumbnail stripbytescount"
        /// "thumbnail resolutionx"
        /// "thumbnail resolutiony"
        /// "thumbnail planarconfig"
        /// "thumbnail resolutionunit"
        /// "thumbnail transferfunction"
        /// "thumbnail softwareused"
        /// "thumbnail datetime"
        /// "thumbnail artist"
        /// "thumbnail whitepoint"
        /// "thumbnail primarychromaticities"
        /// "thumbnail ycbcrcoefficients"
        /// "thumbnail ycbcrsubsampling"
        /// "thumbnail ycbcrpositioning"
        /// "thumbnail refblackwhite"
        /// "thumbnail copyright"
        /// "luminance table"
        /// "chrominance table"
        /// "frame delay"
        /// "loop count"
        /// "pixel unit"
        /// "pixel perunit x"
        /// "pixel perunit y"
        /// "palette histogram"
        /// "exposure time"
        /// "f-number"
        /// "exposure prog"
        /// "spectral sense"
        /// "iso speed"
        /// "oecf"
        /// "ver"
        /// "dtorig"
        /// "dtdigitized"
        /// "compconfig"
        /// "compbpp"
        /// "shutter speed"
        /// "aperture"
        /// "brightness"
        /// "exposure bias"
        /// "maxaperture"
        /// "subjectdist"
        /// "metering mode"
        /// "lightsource"
        /// "flash"
        /// "focallength"
        /// "maker note"
        /// "user comment"
        /// "dtsubsec"
        /// "dtorigss"
        /// "dtdigss"
        /// "fpxver"
        /// "colorspace"
        /// "pixxdim"
        /// "pixydim"
        /// "relatedwav"
        /// "interop"
        /// "flashenergy"
        /// "spatialfr"
        /// "focalxres"
        /// "focalyres"
        /// "focalresunit"
        /// "subject loc"
        /// "exposure index"
        /// "sensing method"
        /// "filesource"
        /// "scenetype"
        /// "cfapattern"
        /// "gps ver"
        /// "gps latituderef"
        /// "gps latitude"
        /// "gps longituderef"
        /// "gps longitude"
        /// "gps altituderef"
        /// "gps altitude"
        /// "gps gpstime"
        /// "gps gpssatellites"
        /// "gps gpsstatus"
        /// "gps gpsmeasuremode"
        /// "gps gpsdop"
        /// "gps speedref"
        /// "gps speed"
        /// "gps trackref"
        /// "gps track"
        /// "gps imgdirref"
        /// "gps imgdir"
        /// "gps mapdatum"
        /// "gps destlatref"
        /// "gps destlat"
        /// "gps destlongref"
        /// "gps destlong"
        /// "gps destbearref"
        /// "gps destbear"
        /// "gps destdistref"
        /// "gps destdist"
        /// </summary>
        public object this[string index]
        {
            get
            {
                return properties[index];
            }
        }
        //
        private System.Drawing.Bitmap bmp;
        //
        private string data;
        //
        private translation myhash;
        //
        private Hashtable properties;
        //
        internal int count
        {
            get
            {
                return this.properties.Count;
            }
        }
        //
        string sp;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="len"></param>
        /// <param name="type"></param>
        /// <param name="data"></param>
        public void settag(int id, string data)
        {
            Encoding ascii = Encoding.ASCII;
            this.settag(id, data.Length, 0x2, ascii.GetBytes(data));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="len"></param>
        /// <param name="type"></param>
        /// <param name="data"></param>
        public void settag(int id, int len, short type, byte[] data)
        {
            PropertyItem p = createpropertyitem(type, id, len, data);
            this.bmp.SetPropertyItem(p);
            builddb(this.bmp.PropertyItems);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="tag"></param>
        /// <param name="len"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private static PropertyItem createpropertyitem(short type, int tag, int len, byte[] value)
        {
            PropertyItem item;
 
            // loads a propertyitem from a jpeg image stored in the assembly as a resource.
            Assembly assembly = Assembly.GetExecutingAssembly();
            Stream emptybitmapstream = assembly.GetManifestResourceStream("exifextractor.decoy.jpg");
            System.Drawing.Image empty = System.Drawing.Image.FromStream(emptybitmapstream);
 
            item = empty.PropertyItems[0];
 
            // copies the data to the property item.
            item.Type = type;
            item.Len = len;
            item.Id = tag;
            item.Value = new byte[value.Length];
            value.CopyTo(item.Value, 0);
 
            return item;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="bmp"></param>
        /// <param name="sp"></param>
        public exifextractor(ref System.Drawing.Bitmap bmp, string sp)
        {
            properties = new Hashtable();
            //
            this.bmp = bmp;
            this.sp = sp;
            //
            myhash = new translation();
            builddb(this.bmp.PropertyItems);
        }
        string msp = "";
        public exifextractor(ref System.Drawing.Bitmap bmp, string sp, string msp)
        {
            properties = new Hashtable();
            this.sp = sp;
            this.msp = msp;
            this.bmp = bmp;
            //    
            myhash = new translation();
            this.builddb(bmp.PropertyItems);
 
        }
        public static PropertyItem[] getexifproperties(string filename)
        {
            FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read);
            System.Drawing.Image image = System.Drawing.Image.FromStream(stream,
                /* useembeddedcolormanagement = */ true,
                /* validateimagedata = */ false);
            return image.PropertyItems;
        }
        public exifextractor(string file, string sp, string msp)
        {
            properties = new Hashtable();
            this.sp = sp;
            this.msp = msp;
 
            myhash = new translation();
            //    
            this.builddb(getexifproperties(file));
 
        }
 
        /// <summary>
        /// 
        /// </summary>
        private void builddb(System.Drawing.Imaging.PropertyItem[] parr)
        {
            properties.Clear();
            //
            data = "";
            //
            Encoding ascii = Encoding.ASCII;
            //
            foreach (System.Drawing.Imaging.PropertyItem p in parr)
            {
                string v = "";
                string name = (string)myhash[p.Id];
                // tag not found. skip it
                if (name == null) continue;
                //
                data += name + ": ";
                //
                //1 = byte an 8-bit unsigned integer.,
                if (p.Type == 0x1)
                {
                    v = 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)
                {
                    // string     
                    v = ascii.GetString(p.Value);
                }
                //3 = short a 16-bit (2 -byte) unsigned integer,
                else if (p.Type == 0x3)
                {
                    // orientation // lookup table     
                    switch (p.Id)
                    {
                        case 0x8827: // iso
                            v = "iso-" + converttoint16u(p.Value).ToString();
                            break;
                        case 0xa217: // sensing method
                            {
                                switch (converttoint16u(p.Value))
                                {
                                    case 1: v = "not defined"; break;
                                    case 2: v = "one-chip color area sensor"; break;
                                    case 3: v = "two-chip color area sensor"; break;
                                    case 4: v = "three-chip color area sensor"; break;
                                    case 5: v = "color sequential area sensor"; break;
                                    case 7: v = "trilinear sensor"; break;
                                    case 8: v = "color sequential linear sensor"; break;
                                    default: v = " reserved"; break;
                                }
                            }
                            break;
                        case 0x8822: // aperture 
                            switch (converttoint16u(p.Value))
                            {
                                case 0: v = "not defined"; break;
                                case 1: v = "manual"; break;
                                case 2: v = "normal program"; break;
                                case 3: v = "aperture priority"; break;
                                case 4: v = "shutter priority"; 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 = "average"; break;
                                case 2: v = "centerweightedaverage"; break;
                                case 3: v = "spot"; break;
                                case 4: v = "multispot"; break;
                                case 5: v = "pattern"; break;
                                case 6: v = "partial"; break;
                                case 255: v = "other"; break;
                                default: v = "reserved"; break;
                            }
                            break;
                        case 0x9208: // light source
                            {
                                switch (converttoint16u(p.Value))
                                {
                                    case 0: v = "unknown"; break;
                                    case 1: v = "daylight"; break;
                                    case 2: v = "fluorescent"; break;
                                    case 3: v = "tungsten"; break;
                                    case 17: v = "standard light a"; break;
                                    case 18: v = "standard light b"; break;
                                    case 19: v = "standard light c"; break;
                                    case 20: v = "d55"; break;
                                    case 21: v = "d65"; break;
                                    case 22: v = "d75"; 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;
                                    default: v = "reserved"; break;
                                }
                            }
                            break;
                        default:
                            v = converttoint16u(p.Value).ToString();
                            break;
                    }
                }
                //4 = long a 32-bit (4 -byte) unsigned integer,
                else if (p.Type == 0x4)
                {
                    // orientation // lookup table     
                    v = converttoint32u(p.Value).ToString();
                }
                //5 = rational two longs. the first long is the numerator and the second long expresses the//denominator.,
                else if (p.Type == 0x5)
                {
                    // rational
                    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);
                    //
                    //convert here
                    //
                    switch (p.Id)
                    {
                        case 0x9202: // aperture
                            v = "f/" + Math.Round(Math.Pow(Math.Sqrt(2), r.todouble()), 2).ToString();
                            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;
                    }
 
                }
                //7 = undefined an 8-bit byte that can take any value depending on the field definition,
                else if (p.Type == 0x7)
                {
                    switch (p.Id)
                    {
                        case 0xa300:
                            {
                                if (p.Value[0] == 3)
                                {
                                    v = "dsc";
                                }
                                else
                                {
                                    v = "reserved";
                                }
                                break;
                            }
                        case 0xa301:
                            if (p.Value[0] == 1)
                                v = "a directly photographed image";
                            else
                                v = "not a directly photographed image";
                            break;
                        default:
                            v = "-";
                            break;
                    }
                }
                //9 = slong a 32-bit (4 -byte) signed integer (2s complement notation),
                else if (p.Type == 0x9)
                {
                    v = converttoint32(p.Value).ToString();
                }
                //10 = srational two slongs. the first slong is the numerator and the second slong is the
                //denominator.
                else if (p.Type == 0xa)
                {
 
                    // rational
                    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);
                    //
                    // convert here
                    //
                    switch (p.Id)
                    {
                        case 0x9201: // shutter speed
                            v = "1/" + Math.Round(Math.Pow(2, r.todouble()), 2).ToString();
                            break;
                        case 0x9203:
                            v = Math.Round(r.todouble(), 4).ToString();
                            break;
                        default:
                            v = r.tostring("/");
                            break;
                    }
                }
                // add it to the list
                if (properties[name] == null)
                    properties.Add(name, v);
                // cat it too
                data += v;
                data += this.sp;
            }
 
        }
 
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return data;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="arr"></param>
        /// <returns></returns>
        int converttoint32(byte[] arr)
        {
            if (arr.Length != 4)
                return 0;
            else
                return arr[3] << 24 | arr[2] << 16 | arr[1] << 8 | arr[0];
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="arr"></param>
        /// <returns></returns>
        int converttoint16(byte[] arr)
        {
            if (arr.Length != 2)
                return 0;
            else
                return arr[1] << 8 | arr[0];
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="arr"></param>
        /// <returns></returns>
        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]);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="arr"></param>
        /// <returns></returns>
        uint converttoint16u(byte[] arr)
        {
            if (arr.Length != 2)
                return 0;
            else
                return Convert.ToUInt16(arr[1] << 8 | arr[0]);
        }
        #region ienumerable members
 
        public IEnumerator GetEnumerator()
        {
            // todo:  add exifextractor.getenumerator implementation
            return (new exifextractorenumerator(this.properties));
        }
 
        #endregion
    }
 
    //
    // dont touch this class. its for ienumerator
    // 
    //
    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 pair(this.index.Key, this.index.Value));
            }
        }
 
        public bool MoveNext()
        {
            if (index != null && index.MoveNext())
                return true;
            else
                return false;
        }
 
        #endregion
 
    }
    public class pair
    {
        public string first;
        public string second;
        public pair(object key, object value)
        {
            this.first = key.ToString();
            this.second = value.ToString();
        }
    }
 
}
原文地址:https://www.cnblogs.com/deep-blue/p/5109950.html