引言:
EXIF,是英文Exchangeable Image File(可交換圖像文件)的縮寫,最初由日本電子工業發展協會(JEIDA --Japan Electronic Industry Development Association) 制訂,目前的版本是修改發表于1998年6月的2.1版。國際標準化組織(ISO)正在制訂的相機文件設計標準(DCF -- Design role for Camera File system)就是以EXIF2.1格式為基礎而設定的。記住,EXIF是一種圖像文件格式,只是文件的后綴名還是沿用大家熟悉的jpg而已。實際上,EXIF信息就是由數碼相機在拍攝過程中采集一系列的信息,然后把信息放置在我們熟知的jpg文件的頭部,也就是說EXIF信息是鑲嵌在JPEG圖像文件格式內的一組拍攝參數,主要包括攝影時的光圈、快門、ISO、日期時間等各種與當時攝影條件相關的訊息,相機品牌型號,色彩編碼,拍攝時錄制的聲音以及全球定位系統(GPS)等信息。簡單的說,它就好像是傻瓜相機的日期打印功能一樣,只不過EXIF信息所記錄的資訊更為詳盡和完備。不過,具有EXIF信息的JPEG圖像文件要比普通的JPEG文件略大一點。就目前市場而言,新一代的數碼相機都具有附加EXIF信息功能,大多數的數碼相機廠商也都會隨數碼相機發售時附贈能夠讀取EXIF信息的軟件,例如 Nikon 系列的數碼相機就附贈 NikonView 軟件,Agfa系列的相機則附贈 Photowize V1.8版,而富士相機附送的EXIF viewer軟件更是這方面的領軍人物(目前已在很多網站提供免費下載。還有一部分的數碼相機會自動將EXIF信息轉存成文檔文件,例如:NIKON CoolPix 990和SONY FD系列。除了硬件廠商隨數碼相機附帶的EXIF信息查看軟件,很多專業的圖像軟件廠商在這方面也不甘示弱,相繼推出自己公司看圖軟件的最新版來支持這種近乎完美的JPEG-EXIF圖像信息附加技術,如最近剛推出的ACDSee 4.0版本,就對現在流行的各種數碼相機有相當好的支持,在EXIF圖像信息附加方面較之其3.0版本也有很大的進步。不管是硬件廠商的配套軟件還是專業名門的看圖工具,所有這些軟件都是為了方便數碼攝影者能更方便地保存查看攝影圖像的重要信息。我們將這些讀取EXIF信息的軟件歸納后分為四類:專業EXIF信息查看工具(以富士的EXIF viewer為例) 、具有查看EXIF信息的強大通用看圖工具(以ACDSee為例)、支持EXIF信息查看的操作系統(微軟的Windows XP)以及可以修改EXIF信息的另類工具(EXIF Editer),而我們這里要講的是通過C#在WEB上讀取一個圖片的EXIF信息。
二、相關類(GetEXIFMetaData):
因為代碼比較長,有五百多行,我只能將關鍵代碼的片段拿出來講講,需要源碼的請發郵件到 yubo@x263.net 索取,或者直接加到MSN上在MSN提供你的郵箱。
這個類中構造了兩個結構MetadataDetail 和 Metadata ,前者是為了存儲EXIF中某元素信息的三種格式,起到中間轉化的作用,一個是十六進制的索引信息,一個是沒用處理過的信息代碼,一個是顯示信息。后面的那個結構就是存儲一張圖片所有EXIF信息元素的!∮袃蓚方法LookupEXIFValue 和 GetEXIFMetaData ,前一個方法是處理特殊元素的對應顯示的,后者從圖片中讀取相關信息然后填充到MetaData結構中。
using System; using System.Drawing; using System.Drawing.Imaging; using System.Collections; using System.ComponentModel;
namespace Test.Com { /// <summary> /// 功能:獲得圖片EXIF信息 /// 作者:Rexsp /// 創建日期:2004-03-20 /// </summary> public class EXIFMetaData { #region 構造函數 /// <summary> /// 構造函數 /// </summary> public EXIFMetaData() { } #endregion
#region 數據轉換結構 /// <summary> /// 轉換數據結構 /// </summary> public struct MetadataDetail { public string Hex;//十六進制字符串 public string RawValueAsString;//原始值串 public string DisplayValue;//顯示值串 } #endregion
#region EXIF元素結構 /// <summary> /// 結構:存儲EXIF元素信息 /// </summary> public struct Metadata { public MetadataDetail EquipmentMake; public MetadataDetail CameraModel; public MetadataDetail ExposureTime;//曝光時間 public MetadataDetail Fstop; public MetadataDetail DatePictureTaken; public MetadataDetail ShutterSpeed;// 快門速度 public MetadataDetail MeteringMode;//曝光模式 public MetadataDetail Flash;//閃光燈 public MetadataDetail XResolution; public MetadataDetail YResolution; public MetadataDetail ImageWidth;//照片寬度 public MetadataDetail ImageHeight;//照片高度
public MetadataDetail FNumber;// f值,光圈數 public MetadataDetail ExposureProg;// 曝光程序 public MetadataDetail SpectralSense;// public MetadataDetail ISOSpeed;// ISO感光度 public MetadataDetail OECF;// public MetadataDetail Ver;// EXIF版本 public MetadataDetail CompConfig;// 色彩設置 public MetadataDetail CompBPP;// 壓縮比率 public MetadataDetail Aperture;// 光圈值 public MetadataDetail Brightness;// 亮度值Ev public MetadataDetail ExposureBias;// 曝光補償 public MetadataDetail MaxAperture;// 最大光圈值
public MetadataDetail SubjectDist;// 主體距離 public MetadataDetail LightSource;// 白平衡 public MetadataDetail FocalLength;// 焦距 public MetadataDetail FPXVer;// FlashPix版本 public MetadataDetail ColorSpace;// 色彩空間 public MetadataDetail Interop;// public MetadataDetail FlashEnergy;// public MetadataDetail SpatialFR;// public MetadataDetail FocalXRes;// public MetadataDetail FocalYRes;// public MetadataDetail FocalResUnit;// public MetadataDetail ExposureIndex;// 曝光指數 public MetadataDetail SensingMethod;// 感應方式 public MetadataDetail SceneType;// public MetadataDetail CfaPattern;// } #endregion
#region 查找EXIF元素值 public string LookupEXIFValue(string Description, string Value) { string DescriptionValue = null;
switch(Description) { case "MeteringMode":
#region MeteringMode { switch(Value) { case "0": DescriptionValue = "Unknown";break; case "1": DescriptionValue = "Average";break; case "2": DescriptionValue = "Center Weighted Average";break; case "3": DescriptionValue = "Spot";break; case "4": DescriptionValue = "Multi-spot";break; case "5": DescriptionValue = "Multi-segment";break; case "6": DescriptionValue = "Partial";break; case "255": DescriptionValue = "Other";break; } } #endregion break; case "ResolutionUnit":
#region ResolutionUnit { switch(Value) { case "1": DescriptionValue = "No Units";break; case "2": DescriptionValue = "Inch";break; case "3": DescriptionValue = "Centimeter";break; } }
#endregion
break; //省略N行相似代碼
} return DescriptionValue; } #endregion
#region 取得圖片的EXIF信息 public Metadata GetEXIFMetaData(string PhotoName) { // 創建一個圖片的實例 System.Drawing.Image MyImage = System.Drawing.Image.FromFile(PhotoName); // 創建一個整型數組來存儲圖像中屬性數組的ID int[] MyPropertyIdList = MyImage.PropertyIdList; //創建一個封閉圖像屬性數組的實例 PropertyItem[] MyPropertyItemList = new PropertyItem[MyPropertyIdList.Length]; //創建一個圖像EXIT信息的實例結構對象,并且賦初值
#region 創建一個圖像EXIT信息的實例結構對象,并且賦初值 Metadata MyMetadata = new Metadata(); MyMetadata.EquipmentMake.Hex = "10f"; MyMetadata.CameraModel.Hex = "110"; MyMetadata.DatePictureTaken.Hex = "9003"; MyMetadata.ExposureTime.Hex = "829a"; MyMetadata.Fstop.Hex = "829d"; MyMetadata.ShutterSpeed.Hex = "9201"; MyMetadata.MeteringMode.Hex = "9207"; MyMetadata.Flash.Hex = "9209"; MyMetadata.FNumber.Hex = "829d"; // MyMetadata.ExposureProg.Hex = ""; // MyMetadata.SpectralSense.Hex = "8824"; // MyMetadata.ISOSpeed.Hex = "8827"; // MyMetadata.OECF.Hex = "8828"; // MyMetadata.Ver.Hex = "9000"; // MyMetadata.CompConfig.Hex = "9101"; // MyMetadata.CompBPP.Hex = "9102"; // MyMetadata.Aperture.Hex = "9202"; // MyMetadata.Brightness.Hex = "9203"; // MyMetadata.ExposureBias.Hex = "9204"; // MyMetadata.MaxAperture.Hex = "9205"; // MyMetadata.SubjectDist.Hex = "9206"; // MyMetadata.LightSource.Hex = "9208"; // MyMetadata.FocalLength.Hex = "920a"; // MyMetadata.FPXVer.Hex = "a000"; // MyMetadata.ColorSpace.Hex = "a001"; // MyMetadata.FocalXRes.Hex = "a20e"; // MyMetadata.FocalYRes.Hex = "a20f"; // MyMetadata.FocalResUnit.Hex = "a210"; // MyMetadata.ExposureIndex.Hex = "a215"; // MyMetadata.SensingMethod.Hex = "a217"; // MyMetadata.SceneType.Hex = "a301"; MyMetadata.CfaPattern.Hex = "a302"; #endregion
// ASCII編碼 System.Text.ASCIIEncoding Value = new System.Text.ASCIIEncoding(); int index = 0; int MyPropertyIdListCount=MyPropertyIdList.Length; if(MyPropertyIdListCount!=0) { foreach (int MyPropertyId in MyPropertyIdList) { string hexVal = ""; MyPropertyItemList[index] = MyImage.GetPropertyItem(MyPropertyId);
#region 初始化各屬性值 string myPropertyIdString=MyImage.GetPropertyItem(MyPropertyId).Id.ToString("x"); switch(myPropertyIdString) { case "10f": { MyMetadata.EquipmentMake.RawValueAsString =BitConverter.ToString(MyImage.GetPropertyItem (MyPropertyId).Value); MyMetadata.EquipmentMake.DisplayValue = Value.GetString(MyPropertyItemList[index].Value); break; }
case "110": { MyMetadata.CameraModel.RawValueAsString =BitConverter.ToString(MyImage.GetPropertyItem(MyPropertyId).Value); MyMetadata.CameraModel.DisplayValue =Value.GetString(MyPropertyItemList[index].Value); break;
}
case "9003": { MyMetadata.DatePictureTaken.RawValueAsString =BitConverter.ToString(MyImage.GetPropertyItem(MyPropertyId).Value); MyMetadata.DatePictureTaken.DisplayValue =Value.GetString(MyPropertyItemList[index].Value); break; } //省略N行相似代碼 } #endregion index++; } }
MyMetadata.XResolution.DisplayValue = MyImage.HorizontalResolution.ToString(); MyMetadata.YResolution.DisplayValue = MyImage.VerticalResolution.ToString(); MyMetadata.ImageHeight.DisplayValue = MyImage.Height.ToString(); MyMetadata.ImageWidth.DisplayValue = MyImage.Width.ToString(); MyImage.Dispose(); return MyMetadata; } #endregion } }
然后就是個調用的問題,有了這個類,我如何讀取圖片的EXIF信息呢?代碼如下: EXIFMetaData em = new EXIFMetaData(); string filePath=Server.MapPath("Test.jpg");//這里可以動態傳遞圖片路徑的 EXIFMetaData.Metadata m = em.GetEXIFMetaData(filePath);//這里就是調用,傳圖片絕對路徑 string exif = m.Ver.DisplayValue; string camera = m.CameraModel.DisplayValue; string model = m.CameraModel.DisplayValue; string aperture = m.Aperture.DisplayValue; string shutter = m.ShutterSpeed.DisplayValue; string sensitive = m.ExposureIndex.DisplayValue;
有什么不明白的,歡迎提出來,此代碼經過測試,功能正常。
|