JpegDocument.cs
上传用户:huiyue
上传日期:2022-04-08
资源大小:1429k
文件大小:54k
源码类别:

搜索引擎

开发平台:

ASP/ASPX

  1. using System;
  2. using System.Collections; // DictionaryEntry
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using System.Drawing.Imaging;
  6. using System.IO;
  7. using System.Xml;
  8. using System.Xml.XPath;
  9. namespace Searcharoo.Common
  10. {
  11.     /// <summary>
  12.     /// Extract a handful of Exif/Xmp fields for indexing... 
  13.     /// </summary>
  14.     /// <remarks>
  15.     /// 
  16.     /// EXIFextractor by Asim Goheer
  17.     /// http://www.codeproject.com/KB/graphics/exifextractor.aspx
  18.     /// 
  19.     /// XMP Metadata (2.0)
  20.     /// http://www.shahine.com/omar/ReadingXMPMetadataFromAJPEGUsingC.aspx
  21.     /// 
  22.     /// Gallery Server Pro
  23.     /// http://www.codeproject.com/KB/web-image/Gallery_Server_Pro.aspx
  24.     /// 
  25.     /// Another library
  26.     /// http://www.codeproject.com/KB/GDI-plus/ImageInfo.aspx
  27.     /// 
  28.     /// Yet another (VB.NET)
  29.     /// http://www.codeproject.com/KB/vb/exif_reader.aspx
  30.     /// </remarks>
  31.     public class JpegDocument : DownloadDocument
  32.     {
  33.         private string _All;
  34.         private string _WordsOnly;
  35.         public JpegDocument(Uri location):base(location)
  36.         {
  37.             Extension = "jpg";
  38.         }
  39.         /// <summary>
  40.         /// Set 'all' and 'words only' to the same value (no parsing)
  41.         /// </summary>
  42.         public override string All
  43.         {
  44.             get { return _All; }
  45.             set { 
  46.                 _All = value;
  47.                 _WordsOnly = _All;
  48.             }
  49.         }
  50.         
  51.         public override string WordsOnly
  52.         {
  53.             get { return _WordsOnly; }
  54.         }
  55.         public override string[] WordsArray
  56.         {
  57.             get { return this.WordsStringToArray(WordsOnly); }
  58.         }
  59.        
  60.         /// <summary>
  61.         /// no-op
  62.         /// </summary>
  63.         public override void Parse()
  64.         {
  65.             // no parsing 
  66.         }
  67.         /// <summary>
  68.         /// Extract Title, Description, Keywords (tags), Make, Model from image
  69.         /// </summary>
  70.         /// <remarks>
  71.         /// TODO: GPS coords to be searchable/retrievable
  72.         /// Gps LatitudeRef : N
  73.         /// Gps Latitude : 14.1136388888889
  74.         /// Gps LongitudeRef : E
  75.         /// Gps Longitude : 99.2318611111111
  76.         /// Gps GpsTime : 0/0
  77.         /// Gps GpsStatus : A
  78.         /// Gps MapDatum : WGS-84
  79.         /// </remarks>
  80.         public override bool GetResponse(System.Net.HttpWebResponse webresponse)
  81.         {
  82.             string filename = System.IO.Path.Combine(Preferences.DownloadedTempFilePath, (System.IO.Path.GetFileName(this.Uri.LocalPath)));
  83.             this.Title = System.IO.Path.GetFileNameWithoutExtension(filename);
  84.             GpsData gl = new GpsData();
  85.             SaveDownloadedFile(webresponse, filename);
  86.             try
  87.             {
  88.                 Goheer.EXIF.EXIFextractor er2 = new Goheer.EXIF.EXIFextractor(filename, "","");
  89.                 foreach (DictionaryEntry de in er2)
  90.                 {
  91.                     //Console.WriteLine(de.Value); //s.First + " : " + s.Second);
  92.                     switch (de.Key.ToString())
  93.                     {
  94.                         case "Equip Make"://: SONY
  95.                             _WordsOnly += " " + de.Value.ToString().Trim(new char[] { '' });
  96.                             break;
  97.                         case "Equip Model": // : DSC-H9
  98.                             _WordsOnly += " " + de.Value.ToString().Trim(new char[] { '' });
  99.                             break;
  100.                         case "Gps LatitudeRef": // : N
  101.                             gl.LatitudeRef = de.Value.ToString().Trim(new char[]{''});
  102.                             break;
  103.                         case "Gps Latitude": // : 14.1136388888889
  104.                             gl.Latitude = de.Value.ToString().Trim(new char[] { '' });
  105.                             break;
  106.                         case "Gps LongitudeRef": // : E
  107.                             gl.LongitudeRef = de.Value.ToString().Trim(new char[] { '' });
  108.                             break;
  109.                         case "Gps Longitude": // :
  110.                             gl.Longitude = de.Value.ToString().Trim(new char[] { '' });
  111.                             break;
  112.                         default:
  113.                             //_WordsOnly = _WordsOnly + de.Key + " : " + de.Value + Environment.NewLine;
  114.                             break;
  115.                     }
  116.                 }
  117.                 string xmp = GetXmpXmlDocFromImage(filename);
  118.                 LoadDoc(xmp);
  119.                 _WordsOnly += " " + Title;
  120.                 _WordsOnly += " " + Description;
  121.                 foreach (string k in Keywords)
  122.                 {
  123.                     _WordsOnly += " " + k; // so they're indexed!
  124.                 }
  125.                 this.GpsLocation = gl.ToLocation();
  126.                 this.All = _WordsOnly;
  127.                 System.IO.File.Delete(filename);    // clean up
  128.             }
  129.             catch (Exception)
  130.             {
  131. //                ProgressEvent(this, new ProgressEventArgs(2, "IFilter failed on " + this.Uri + " " + e.Message + ""));
  132.             }
  133.             if (this.All != string.Empty)
  134.             {
  135.                 if (this.Description == string.Empty)
  136.                 {   // if no description was set, use the rest of the text
  137.                     this.Description = base.GetDescriptionFromWordsOnly(WordsOnly);
  138.                 }
  139.                 return true;
  140.             }
  141.             else
  142.             {
  143.                 return false;
  144.             }
  145.         }
  146.         /// <summary>
  147.         /// Gps LatitudeRef : N
  148.         /// Gps Latitude : 14.1136388888889
  149.         /// Gps LongitudeRef : E
  150.         /// Gps Longitude : 99.2318611111111
  151.         /// </summary>
  152.         private class GpsData
  153.         {
  154.             public string LatitudeRef = string.Empty;
  155.             public string Latitude = string.Empty;
  156.             public string LongitudeRef = string.Empty;
  157.             public string Longitude = string.Empty;
  158.             public override string ToString()
  159.             {
  160.                 string location = string.Empty;
  161.                 if ((Latitude != string.Empty) && (Longitude != string.Empty))
  162.                 {   // lat & lon supplied
  163.                     if (LatitudeRef.ToUpper() == "S") location += "-";
  164.                     location += Latitude;
  165.                     location += ',';
  166.                     if (LongitudeRef.ToUpper() == "W") location += "-";
  167.                     location += Longitude;
  168.                 }
  169.                 return location;
  170.             }
  171.             public Location ToLocation()
  172.             {
  173.                 return Location.FromString(this.ToString());
  174.             }
  175.         }
  176. #region XMP
  177.         //private List<string> Keywords = new List<string>();
  178.         private Int32 Rating;
  179.         // http://www.shahine.com/omar/ReadingXMPMetadataFromAJPEGUsingC.aspx
  180.         public static string GetXmpXmlDocFromImage(string filename)
  181.         {
  182.             string contents;
  183.             string xmlPart;
  184.             string beginCapture = "<rdf:RDF";
  185.             string endCapture = "</rdf:RDF>";
  186.             int beginPos;
  187.             int endPos;
  188.             using (System.IO.StreamReader sr = new System.IO.StreamReader(filename))
  189.             {
  190.                 contents = sr.ReadToEnd();
  191.                 System.Diagnostics.Debug.Write(contents.Length + " chars" + Environment.NewLine);
  192.                 sr.Close();
  193.             }
  194.             beginPos = contents.IndexOf(beginCapture, 0);
  195.             endPos = contents.IndexOf(endCapture, 0);
  196.             System.Diagnostics.Debug.Write("xml found at pos: " + beginPos.ToString() + " - " + endPos.ToString());
  197.             xmlPart = contents.Substring(beginPos, (endPos - beginPos) + endCapture.Length);
  198.             System.Diagnostics.Debug.Write("Xml len: " + xmlPart.Length.ToString());
  199.             return xmlPart;
  200.         }
  201.         // http://www.shahine.com/omar/ReadingXMPMetadataFromAJPEGUsingC.aspx
  202.         private void LoadDoc(string xmpXmlDoc)
  203.         {
  204.             XmlDocument doc = new XmlDocument();
  205.             XmlNamespaceManager NamespaceManager;
  206.             try
  207.             {
  208.                 doc.LoadXml(xmpXmlDoc);
  209.             }
  210.             catch (Exception ex)
  211.             {
  212.                 throw new ApplicationException("An error occured while loading XML metadata from image. The error was: " + ex.Message);
  213.             }
  214.             try
  215.             {
  216.                 doc.LoadXml(xmpXmlDoc);
  217.                 NamespaceManager = new XmlNamespaceManager(doc.NameTable);
  218.                 NamespaceManager.AddNamespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
  219.                 NamespaceManager.AddNamespace("exif", "http://ns.adobe.com/exif/1.0/");
  220.                 NamespaceManager.AddNamespace("x", "adobe:ns:meta/");
  221.                 NamespaceManager.AddNamespace("xap", "http://ns.adobe.com/xap/1.0/");
  222.                 NamespaceManager.AddNamespace("tiff", "http://ns.adobe.com/tiff/1.0/");
  223.                 NamespaceManager.AddNamespace("dc", "http://purl.org/dc/elements/1.1/");
  224.                 // get ratings
  225.                 XmlNode xmlNode = doc.SelectSingleNode("/rdf:RDF/rdf:Description/xap:Rating", NamespaceManager);
  226.                 // Alternatively, there is a common form of RDF shorthand that writes simple properties as
  227.                 // attributes of the rdf:Description element.
  228.                 if (xmlNode == null)
  229.                 {
  230.                     xmlNode = doc.SelectSingleNode("/rdf:RDF/rdf:Description", NamespaceManager);
  231.                     xmlNode = xmlNode.Attributes["xap:Rating"];
  232.                 }
  233.                 if (xmlNode != null)
  234.                 {
  235.                     this.Rating = Convert.ToInt32(xmlNode.InnerText);
  236.                 }
  237.                 // get keywords
  238.                 xmlNode = doc.SelectSingleNode("/rdf:RDF/rdf:Description/dc:subject/rdf:Bag", NamespaceManager);
  239.                 if (xmlNode != null)
  240.                 {
  241.                     foreach (XmlNode li in xmlNode)
  242.                     {
  243.                         Keywords.Add(li.InnerText);
  244.                     }
  245.                 }
  246.                 // get description
  247.                 xmlNode = doc.SelectSingleNode("/rdf:RDF/rdf:Description/dc:description/rdf:Alt", NamespaceManager);
  248.                 if (xmlNode != null)
  249.                 {
  250.                     this.Description = xmlNode.ChildNodes[0].InnerText;
  251.                 }
  252.                 // get title
  253.                 xmlNode = doc.SelectSingleNode("/rdf:RDF/rdf:Description/dc:title/rdf:Alt", NamespaceManager);
  254.                 if (xmlNode != null)
  255.                 {
  256.                     this.Title = xmlNode.ChildNodes[0].InnerText;
  257.                 }
  258.             }
  259.             catch (Exception ex)
  260.             {
  261.                 throw new ApplicationException("Error occured while readning meta-data from image. The error was: " + ex.Message);
  262.             }
  263.             finally
  264.             {
  265.                 doc = null;
  266.             }
  267.         }
  268. #endregion
  269.     }
  270. }
  271. /* EXIFextract code from
  272.  * http://www.codeproject.com/KB/graphics/exifextractor.aspx
  273.  * 
  274.  * includes updated GPS coordinate extraction by blackmanticore
  275.  * http://www.codeproject.com/KB/graphics/exifextractor.aspx?fid=207371&select=2516453#xx2516453xx
  276.  * http://www.codeproject.com/script/Membership/Profiles.aspx?mid=2045089
  277.  */
  278. namespace Goheer
  279. {
  280.     namespace EXIF
  281.     {
  282.         /// <summary>
  283.         /// EXIFextractor Class
  284.         /// </summary>
  285.         /// <remarks>
  286.         /// Code source:
  287.         /// http://www.codeproject.com/KB/graphics/exifextractor.aspx
  288.         /// </remarks>
  289.         public class EXIFextractor : IEnumerable
  290.         {
  291.             /// <summary>
  292.             /// Get the individual property value by supplying property name
  293.             /// These are the valid property names :
  294.             /// </summary>
  295.             /// <remarks>
  296.             /// "Exif IFD"
  297.             /// "Gps IFD"
  298.             /// "New Subfile Type"
  299.             /// "Subfile Type"
  300.             /// "Image Width"
  301.             /// "Image Height"
  302.             /// "Bits Per Sample"
  303.             /// "Compression"
  304.             /// "Photometric Interp"
  305.             /// "Thresh Holding"
  306.             /// "Cell Width"
  307.             /// "Cell Height"
  308.             /// "Fill Order"
  309.             /// "Document Name"
  310.             /// "Image Description"
  311.             /// "Equip Make"
  312.             /// "Equip Model"
  313.             /// "Strip Offsets"
  314.             /// "Orientation"
  315.             /// "Samples PerPixel"
  316.             /// "Rows Per Strip"
  317.             /// "Strip Bytes Count"
  318.             /// "Min Sample Value"
  319.             /// "Max Sample Value"
  320.             /// "X Resolution"
  321.             /// "Y Resolution"
  322.             /// "Planar Config"
  323.             /// "Page Name"
  324.             /// "X Position"
  325.             /// "Y Position"
  326.             /// "Free Offset"
  327.             /// "Free Byte Counts"
  328.             /// "Gray Response Unit"
  329.             /// "Gray Response Curve"
  330.             /// "T4 Option"
  331.             /// "T6 Option"
  332.             /// "Resolution Unit"
  333.             /// "Page Number"
  334.             /// "Transfer Funcition"
  335.             /// "Software Used"
  336.             /// "Date Time"
  337.             /// "Artist"
  338.             /// "Host Computer"
  339.             /// "Predictor"
  340.             /// "White Point"
  341.             /// "Primary Chromaticities"
  342.             /// "ColorMap"
  343.             /// "Halftone Hints"
  344.             /// "Tile Width"
  345.             /// "Tile Length"
  346.             /// "Tile Offset"
  347.             /// "Tile ByteCounts"
  348.             /// "InkSet"
  349.             /// "Ink Names"
  350.             /// "Number Of Inks"
  351.             /// "Dot Range"
  352.             /// "Target Printer"
  353.             /// "Extra Samples"
  354.             /// "Sample Format"
  355.             /// "S Min Sample Value"
  356.             /// "S Max Sample Value"
  357.             /// "Transfer Range"
  358.             /// "JPEG Proc"
  359.             /// "JPEG InterFormat"
  360.             /// "JPEG InterLength"
  361.             /// "JPEG RestartInterval"
  362.             /// "JPEG LosslessPredictors"
  363.             /// "JPEG PointTransforms"
  364.             /// "JPEG QTables"
  365.             /// "JPEG DCTables"
  366.             /// "JPEG ACTables"
  367.             /// "YCbCr Coefficients"
  368.             /// "YCbCr Subsampling"
  369.             /// "YCbCr Positioning"
  370.             /// "REF Black White"
  371.             /// "ICC Profile"
  372.             /// "Gamma"
  373.             /// "ICC Profile Descriptor"
  374.             /// "SRGB RenderingIntent"
  375.             /// "Image Title"
  376.             /// "Copyright"
  377.             /// "Resolution X Unit"
  378.             /// "Resolution Y Unit"
  379.             /// "Resolution X LengthUnit"
  380.             /// "Resolution Y LengthUnit"
  381.             /// "Print Flags"
  382.             /// "Print Flags Version"
  383.             /// "Print Flags Crop"
  384.             /// "Print Flags Bleed Width"
  385.             /// "Print Flags Bleed Width Scale"
  386.             /// "Halftone LPI"
  387.             /// "Halftone LPIUnit"
  388.             /// "Halftone Degree"
  389.             /// "Halftone Shape"
  390.             /// "Halftone Misc"
  391.             /// "Halftone Screen"
  392.             /// "JPEG Quality"
  393.             /// "Grid Size"
  394.             /// "Thumbnail Format"
  395.             /// "Thumbnail Width"
  396.             /// "Thumbnail Height"
  397.             /// "Thumbnail ColorDepth"
  398.             /// "Thumbnail Planes"
  399.             /// "Thumbnail RawBytes"
  400.             /// "Thumbnail Size"
  401.             /// "Thumbnail CompressedSize"
  402.             /// "Color Transfer Function"
  403.             /// "Thumbnail Data"
  404.             /// "Thumbnail ImageWidth"
  405.             /// "Thumbnail ImageHeight"
  406.             /// "Thumbnail BitsPerSample"
  407.             /// "Thumbnail Compression"
  408.             /// "Thumbnail PhotometricInterp"
  409.             /// "Thumbnail ImageDescription"
  410.             /// "Thumbnail EquipMake"
  411.             /// "Thumbnail EquipModel"
  412.             /// "Thumbnail StripOffsets"
  413.             /// "Thumbnail Orientation"
  414.             /// "Thumbnail SamplesPerPixel"
  415.             /// "Thumbnail RowsPerStrip"
  416.             /// "Thumbnail StripBytesCount"
  417.             /// "Thumbnail ResolutionX"
  418.             /// "Thumbnail ResolutionY"
  419.             /// "Thumbnail PlanarConfig"
  420.             /// "Thumbnail ResolutionUnit"
  421.             /// "Thumbnail TransferFunction"
  422.             /// "Thumbnail SoftwareUsed"
  423.             /// "Thumbnail DateTime"
  424.             /// "Thumbnail Artist"
  425.             /// "Thumbnail WhitePoint"
  426.             /// "Thumbnail PrimaryChromaticities"
  427.             /// "Thumbnail YCbCrCoefficients"
  428.             /// "Thumbnail YCbCrSubsampling"
  429.             /// "Thumbnail YCbCrPositioning"
  430.             /// "Thumbnail RefBlackWhite"
  431.             /// "Thumbnail CopyRight"
  432.             /// "Luminance Table"
  433.             /// "Chrominance Table"
  434.             /// "Frame Delay"
  435.             /// "Loop Count"
  436.             /// "Pixel Unit"
  437.             /// "Pixel PerUnit X"
  438.             /// "Pixel PerUnit Y"
  439.             /// "Palette Histogram"
  440.             /// "Exposure Time"
  441.             /// "F-Number"
  442.             /// "Exposure Prog"
  443.             /// "Spectral Sense"
  444.             /// "ISO Speed"
  445.             /// "OECF"
  446.             /// "Ver"
  447.             /// "DTOrig"
  448.             /// "DTDigitized"
  449.             /// "CompConfig"
  450.             /// "CompBPP"
  451.             /// "Shutter Speed"
  452.             /// "Aperture"
  453.             /// "Brightness"
  454.             /// "Exposure Bias"
  455.             /// "MaxAperture"
  456.             /// "SubjectDist"
  457.             /// "Metering Mode"
  458.             /// "LightSource"
  459.             /// "Flash"
  460.             /// "FocalLength"
  461.             /// "Maker Note"
  462.             /// "User Comment"
  463.             /// "DTSubsec"
  464.             /// "DTOrigSS"
  465.             /// "DTDigSS"
  466.             /// "FPXVer"
  467.             /// "ColorSpace"
  468.             /// "PixXDim"
  469.             /// "PixYDim"
  470.             /// "RelatedWav"
  471.             /// "Interop"
  472.             /// "FlashEnergy"
  473.             /// "SpatialFR"
  474.             /// "FocalXRes"
  475.             /// "FocalYRes"
  476.             /// "FocalResUnit"
  477.             /// "Subject Loc"
  478.             /// "Exposure Index"
  479.             /// "Sensing Method"
  480.             /// "FileSource"
  481.             /// "SceneType"
  482.             /// "CfaPattern"
  483.             /// "Gps Ver"
  484.             /// "Gps LatitudeRef"
  485.             /// "Gps Latitude"
  486.             /// "Gps LongitudeRef"
  487.             /// "Gps Longitude"
  488.             /// "Gps AltitudeRef"
  489.             /// "Gps Altitude"
  490.             /// "Gps GpsTime"
  491.             /// "Gps GpsSatellites"
  492.             /// "Gps GpsStatus"
  493.             /// "Gps GpsMeasureMode"
  494.             /// "Gps GpsDop"
  495.             /// "Gps SpeedRef"
  496.             /// "Gps Speed"
  497.             /// "Gps TrackRef"
  498.             /// "Gps Track"
  499.             /// "Gps ImgDirRef"
  500.             /// "Gps ImgDir"
  501.             /// "Gps MapDatum"
  502.             /// "Gps DestLatRef"
  503.             /// "Gps DestLat"
  504.             /// "Gps DestLongRef"
  505.             /// "Gps DestLong"
  506.             /// "Gps DestBearRef"
  507.             /// "Gps DestBear"
  508.             /// "Gps DestDistRef"
  509.             /// "Gps DestDist"
  510.             /// </remarks>
  511.             public object this[string index]
  512.             {
  513.                 get
  514.                 {
  515.                     return properties[index];
  516.                 }
  517.             }
  518.             //
  519.             private System.Drawing.Bitmap bmp;
  520.             //
  521.             private string data;
  522.             //
  523.             private translation myHash;
  524.             //
  525.             //private Hashtable properties;
  526.             private Dictionary<string, string> properties;
  527.             //
  528.             internal int Count
  529.             {
  530.                 get
  531.                 {
  532.                     return this.properties.Count;
  533.                 }
  534.             }
  535.             //
  536.             string sp;
  537.             
  538.             //[Obsolete()]
  539.             //public void setTag(int id, string data)
  540.             //{
  541.             //    Encoding ascii = Encoding.ASCII;
  542.             //    this.setTag(id, data.Length, 0x2, ascii.GetBytes(data));
  543.             //}
  544.             
  545.             //[Obsolete()]
  546.             //public void setTag(int id, int len, short type, byte[] data)
  547.             //{
  548.             //    PropertyItem p = CreatePropertyItem(type, id, len, data);
  549.             //    this.bmp.SetPropertyItem(p);
  550.             //    buildDB(this.bmp.PropertyItems);
  551.             //}
  552.             
  553.             //[Obsolete()]
  554.             //private static PropertyItem CreatePropertyItem(short type, int tag, int len, byte[] value)
  555.             //{
  556.             //    PropertyItem item;
  557.             //    // Loads a PropertyItem from a Jpeg image stored in the assembly as a resource.
  558.             //    Assembly assembly = Assembly.GetExecutingAssembly();
  559.             //    Stream emptyBitmapStream = assembly.GetManifestResourceStream("EXIFextractor.decoy.jpg");
  560.             //    System.Drawing.Image empty = System.Drawing.Image.FromStream(emptyBitmapStream);
  561.             //    item = empty.PropertyItems[0];
  562.             //    // Copies the data to the property item.
  563.             //    item.Type = type;
  564.             //    item.Len = len;
  565.             //    item.Id = tag;
  566.             //    item.Value = new byte[value.Length];
  567.             //    value.CopyTo(item.Value, 0);
  568.             //    return item;
  569.             //}
  570.             /// <summary>
  571.             /// 
  572.             /// </summary>
  573.             /// <param name="bmp"></param>
  574.             /// <param name="sp"></param>
  575.             public EXIFextractor(ref System.Drawing.Bitmap bmp, string sp)
  576.             {
  577.                 properties = new Dictionary<string,string>();
  578.                 //
  579.                 this.bmp = bmp;
  580.                 this.sp = sp;
  581.                 //
  582.                 myHash = new translation();
  583.                 buildDB(this.bmp.PropertyItems);
  584.             }
  585.             string msp = "";
  586.             public EXIFextractor(ref System.Drawing.Bitmap bmp, string sp, string msp)
  587.             {
  588.                 properties = new Dictionary<string, string>();
  589.                 this.sp = sp;
  590.                 this.msp = msp;
  591.                 this.bmp = bmp;
  592.                 //
  593.                 myHash = new translation();
  594.                 this.buildDB(bmp.PropertyItems);
  595.             }
  596.             /// <summary>
  597.             /// Fixes locked image
  598.             /// </summary>            
  599.             public static PropertyItem[] GetExifProperties(string fileName)
  600.             {
  601.                 using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
  602.                 {
  603.                     using (System.Drawing.Image image = System.Drawing.Image.FromStream(stream,
  604.                         /* useEmbeddedColorManagement = */ true,
  605.                         /* validateImageData = */ false))
  606.                     {
  607.                         return image.PropertyItems;
  608.                     }
  609.                 }
  610.             }
  611.             /// <summary>
  612.             /// Fixes locked image
  613.             /// </summary>
  614.             public static PropertyItem[] GetExifProperties(string fileName, out long size)
  615.             {
  616.                 using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
  617.                 {
  618.                     size = stream.Length;
  619.                     using (System.Drawing.Image image = System.Drawing.Image.FromStream(stream,
  620.                         /* useEmbeddedColorManagement = */ true,
  621.                         /* validateImageData = */ false))
  622.                     {
  623.                         return image.PropertyItems;
  624.                     }
  625.                 }
  626.                 return null;
  627.             }
  628.             public EXIFextractor(string file, string sp, string msp)
  629.             {
  630.                 properties = new Dictionary<string,string>();
  631.                 this.sp = sp;
  632.                 this.msp = msp;
  633.                 myHash = new translation();
  634.                 //
  635.                 this.buildDB(GetExifProperties(file));
  636.             }
  637.             /// <summary>
  638.             /// 
  639.             /// </summary>
  640.             private void buildDB(System.Drawing.Imaging.PropertyItem[] parr)
  641.             {
  642.                 properties.Clear();
  643.                 //
  644.                 data = "";
  645.                 //
  646.                 Encoding ascii = Encoding.ASCII;
  647.                 //
  648.                 foreach (System.Drawing.Imaging.PropertyItem p in parr)
  649.                 {
  650.                     string v = "";
  651.                     string name = (string)myHash[p.Id];
  652.                     // tag not found. skip it
  653.                     if (name == null) continue;
  654.                     //
  655.                     data += name + ": ";
  656.                     //
  657.                     //1 = BYTE An 8-bit unsigned integer.,
  658.                     if (p.Type == 0x1)
  659.                     {
  660.                         v = p.Value[0].ToString();
  661.                     }
  662.                     //2 = ASCII An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated with NULL.,
  663.                     else if (p.Type == 0x2)
  664.                     {
  665.                         // string
  666.                         v = ascii.GetString(p.Value);
  667.                     }
  668.                     //3 = SHORT A 16-bit (2 -byte) unsigned integer,
  669.                     else if (p.Type == 0x3)
  670.                     {
  671.                         // orientation // lookup table
  672.                         switch (p.Id)
  673.                         {
  674.                             case 0x8827: // ISO
  675.                                 v = "ISO-" + convertToInt16U(p.Value).ToString();
  676.                                 break;
  677.                             case 0xA217: // sensing method
  678.                                 {
  679.                                     switch (convertToInt16U(p.Value))
  680.                                     {
  681.                                         case 1: v = "Not defined"; break;
  682.                                         case 2: v = "One-chip color area sensor"; break;
  683.                                         case 3: v = "Two-chip color area sensor"; break;
  684.                                         case 4: v = "Three-chip color area sensor"; break;
  685.                                         case 5: v = "Color sequential area sensor"; break;
  686.                                         case 7: v = "Trilinear sensor"; break;
  687.                                         case 8: v = "Color sequential linear sensor"; break;
  688.                                         default: v = " reserved"; break;
  689.                                     }
  690.                                 }
  691.                                 break;
  692.                             case 0x8822: // aperture 
  693.                                 switch (convertToInt16U(p.Value))
  694.                                 {
  695.                                     case 0: v = "Not defined"; break;
  696.                                     case 1: v = "Manual"; break;
  697.                                     case 2: v = "Normal program"; break;
  698.                                     case 3: v = "Aperture priority"; break;
  699.                                     case 4: v = "Shutter priority"; break;
  700.                                     case 5: v = "Creative program (biased toward depth of field)"; break;
  701.                                     case 6: v = "Action program (biased toward fast shutter speed)"; break;
  702.                                     case 7: v = "Portrait mode (for closeup photos with the background out of focus)"; break;
  703.                                     case 8: v = "Landscape mode (for landscape photos with the background in focus)"; break;
  704.                                     default: v = "reserved"; break;
  705.                                 }
  706.                                 break;
  707.                             case 0x9207: // metering mode
  708.                                 switch (convertToInt16U(p.Value))
  709.                                 {
  710.                                     case 0: v = "unknown"; break;
  711.                                     case 1: v = "Average"; break;
  712.                                     case 2: v = "CenterWeightedAverage"; break;
  713.                                     case 3: v = "Spot"; break;
  714.                                     case 4: v = "MultiSpot"; break;
  715.                                     case 5: v = "Pattern"; break;
  716.                                     case 6: v = "Partial"; break;
  717.                                     case 255: v = "Other"; break;
  718.                                     default: v = "reserved"; break;
  719.                                 }
  720.                                 break;
  721.                             case 0x9208: // light source
  722.                                 {
  723.                                     switch (convertToInt16U(p.Value))
  724.                                     {
  725.                                         case 0: v = "unknown"; break;
  726.                                         case 1: v = "Daylight"; break;
  727.                                         case 2: v = "Fluorescent"; break;
  728.                                         case 3: v = "Tungsten"; break;
  729.                                         case 17: v = "Standard light A"; break;
  730.                                         case 18: v = "Standard light B"; break;
  731.                                         case 19: v = "Standard light C"; break;
  732.                                         case 20: v = "D55"; break;
  733.                                         case 21: v = "D65"; break;
  734.                                         case 22: v = "D75"; break;
  735.                                         case 255: v = "other"; break;
  736.                                         default: v = "reserved"; break;
  737.                                     }
  738.                                 }
  739.                                 break;
  740.                             case 0x9209:
  741.                                 {
  742.                                     switch (convertToInt16U(p.Value))
  743.                                     {
  744.                                         case 0: v = "Flash did not fire"; break;
  745.                                         case 1: v = "Flash fired"; break;
  746.                                         case 5: v = "Strobe return light not detected"; break;
  747.                                         case 7: v = "Strobe return light detected"; break;
  748.                                         default: v = "reserved"; break;
  749.                                     }
  750.                                 }
  751.                                 break;
  752.                             default:
  753.                                 v = convertToInt16U(p.Value).ToString();
  754.                                 break;
  755.                         }
  756.                     }
  757.                     //4 = LONG A 32-bit (4 -byte) unsigned integer,
  758.                     else if (p.Type == 0x4)
  759.                     {
  760.                         // orientation // lookup table
  761.                         v = convertToInt32U(p.Value).ToString();
  762.                     }
  763.                     //5 = RATIONAL Two LONGs. The first LONG is the numerator and the second LONG expresses the//denominator.,
  764.                      else if( p.Type == 0x5 )
  765.                     { // modifications by http://www.codeproject.com/script/Membership/Profiles.aspx?mid=2045089
  766.                     //My code starts here
  767.                     if (p.Id == 0x0004)
  768.                     {
  769.                     //lat
  770.                     // rational
  771.                     byte[] deg = new byte[4];
  772.                     byte[] degdiv = new byte[4];
  773.                     byte[] min = new byte[4];
  774.                     byte[] mindiv = new byte[4];
  775.                     byte[] sec = new byte[4];
  776.                     byte[] secdiv = new byte[4];
  777.                     Array.Copy(p.Value, 0, deg, 0, 4);
  778.                     Array.Copy(p.Value, 4, degdiv, 0, 4);
  779.                     Array.Copy(p.Value, 8, min, 0, 4);
  780.                     Array.Copy(p.Value, 12, mindiv, 0, 4);
  781.                     Array.Copy(p.Value, 16, sec, 0, 4);
  782.                     Array.Copy(p.Value, 20, secdiv, 0, 4);
  783.                     double a = convertToInt32U(deg);
  784.                     double b = convertToInt32U(degdiv);
  785.                     double c = convertToInt32U(min);
  786.                     double d = convertToInt32U(mindiv);
  787.                     double e = convertToInt32U(sec);
  788.                     double f = convertToInt32U(secdiv);
  789.                     double o =((a/b) + ((c/b)/60) + ((e/f)/3600));
  790.                     v = o.ToString();
  791.                     // Rational r = new Rational(a, b);
  792.                     }
  793.                     else if (p.Id == 0x0002)
  794.                     {
  795.                         //long
  796.                         byte[] deg = new byte[4];
  797.                         byte[] degdiv = new byte[4];
  798.                         byte[] min = new byte[4];
  799.                         byte[] mindiv = new byte[4];
  800.                         byte[] sec = new byte[4];
  801.                         byte[] secdiv = new byte[4];
  802.                         Array.Copy(p.Value, 0, deg, 0, 4);
  803.                         Array.Copy(p.Value, 4, degdiv, 0, 4);
  804.                         Array.Copy(p.Value, 8, min, 0, 4);
  805.                         Array.Copy(p.Value, 12, mindiv, 0, 4);
  806.                         Array.Copy(p.Value, 16, sec, 0, 4);
  807.                         Array.Copy(p.Value, 20, secdiv, 0, 4);
  808.                         double a = convertToInt32U(deg);
  809.                         double b = convertToInt32U(degdiv);
  810.                         double c = convertToInt32U(min);
  811.                         double d = convertToInt32U(mindiv);
  812.                         double e = convertToInt32U(sec);
  813.                         double f = convertToInt32U(secdiv);
  814.                         double o = ((a / b) + ((c / b) / 60) + ((e / f) / 3600));
  815.                         v = o.ToString();
  816.                     }
  817.                     //My Code ends here
  818.                     else
  819.                     {
  820.                         // rational
  821.                         byte[] n = new byte[p.Len / 2];
  822.                         byte[] d = new byte[p.Len / 2];
  823.                         Array.Copy(p.Value, 0, n, 0, p.Len / 2);
  824.                         Array.Copy(p.Value, p.Len / 2, d, 0, p.Len / 2);
  825.                         uint a = convertToInt32U(n);
  826.                         uint b = convertToInt32U(d);
  827.                         Rational r = new Rational(a, b);
  828.                         //
  829.                         //convert here
  830.                         //
  831.                         switch (p.Id)
  832.                         {
  833.                             case 0x9202: // aperture
  834.                                 v = "F/" + Math.Round(Math.Pow(Math.Sqrt(2), r.ToDouble()), 2).ToString();
  835.                                 break;
  836.                             case 0x920A:
  837.                                 v = r.ToDouble().ToString();
  838.                                 break;
  839.                             case 0x829A:
  840.                                 v = r.ToDouble().ToString();
  841.                                 break;
  842.                             case 0x829D: // F-number
  843.                                 v = "F/" + r.ToDouble().ToString();
  844.                                 break;
  845.                             default:
  846.                                 v = r.ToString("/");
  847.                                 break;
  848.                         }
  849.                     }
  850.                     }
  851.                     //7 = UNDEFINED An 8-bit byte that can take any value depending on the field definition,
  852.                     else if (p.Type == 0x7)
  853.                     {
  854.                         switch (p.Id)
  855.                         {
  856.                             case 0xA300:
  857.                                 {
  858.                                     if (p.Value[0] == 3)
  859.                                     {
  860.                                         v = "DSC";
  861.                                     }
  862.                                     else
  863.                                     {
  864.                                         v = "reserved";
  865.                                     }
  866.                                     break;
  867.                                 }
  868.                             case 0xA301:
  869.                                 if (p.Value[0] == 1)
  870.                                     v = "A directly photographed image";
  871.                                 else
  872.                                     v = "Not a directly photographed image";
  873.                                 break;
  874.                             default:
  875.                                 v = "-";
  876.                                 break;
  877.                         }
  878.                     }
  879.                     //9 = SLONG A 32-bit (4 -byte) signed integer (2's complement notation),
  880.                     else if (p.Type == 0x9)
  881.                     {
  882.                         v = convertToInt32(p.Value).ToString();
  883.                     }
  884.                     //10 = SRATIONAL Two SLONGs. The first SLONG is the numerator and the second SLONG is the
  885.                     //denominator.
  886.                     else if (p.Type == 0xA)
  887.                     {
  888.                         // rational
  889.                         byte[] n = new byte[p.Len / 2];
  890.                         byte[] d = new byte[p.Len / 2];
  891.                         Array.Copy(p.Value, 0, n, 0, p.Len / 2);
  892.                         Array.Copy(p.Value, p.Len / 2, d, 0, p.Len / 2);
  893.                         int a = convertToInt32(n);
  894.                         int b = convertToInt32(d);
  895.                         Rational r = new Rational(a, b);
  896.                         //
  897.                         // convert here
  898.                         //
  899.                         switch (p.Id)
  900.                         {
  901.                             case 0x9201: // shutter speed
  902.                                 v = "1/" + Math.Round(Math.Pow(2, r.ToDouble()), 2).ToString();
  903.                                 break;
  904.                             case 0x9203:
  905.                                 v = Math.Round(r.ToDouble(), 4).ToString();
  906.                                 break;
  907.                             default:
  908.                                 v = r.ToString("/");
  909.                                 break;
  910.                         }
  911.                     }
  912.                     // add it to the list
  913.                     if (!properties.ContainsKey(name))
  914.                         properties.Add(name, v);
  915.                     // cat it too
  916.                     data += v;
  917.                     data += this.sp;
  918.                 }
  919.             }
  920.             /// <summary>
  921.             /// 
  922.             /// </summary>
  923.             /// <returns></returns>
  924.             public override string ToString()
  925.             {
  926.                 return data;
  927.             }
  928.             /// <summary>
  929.             /// 
  930.             /// </summary>
  931.             /// <param name="arr"></param>
  932.             /// <returns></returns>
  933.             int convertToInt32(byte[] arr)
  934.             {
  935.                 if (arr.Length != 4)
  936.                     return 0;
  937.                 else
  938.                     return arr[3] << 24 | arr[2] << 16 | arr[1] << 8 | arr[0];
  939.             }
  940.             /// <summary>
  941.             /// 
  942.             /// </summary>
  943.             /// <param name="arr"></param>
  944.             /// <returns></returns>
  945.             int convertToInt16(byte[] arr)
  946.             {
  947.                 if (arr.Length != 2)
  948.                     return 0;
  949.                 else
  950.                     return arr[1] << 8 | arr[0];
  951.             }
  952.             /// <summary>
  953.             /// 
  954.             /// </summary>
  955.             /// <param name="arr"></param>
  956.             /// <returns></returns>
  957.             uint convertToInt32U(byte[] arr)
  958.             {
  959.                 if (arr.Length != 4)
  960.                     return 0;
  961.                 else
  962.                     return Convert.ToUInt32(arr[3] << 24 | arr[2] << 16 | arr[1] << 8 | arr[0]);
  963.             }
  964.             /// <summary>
  965.             /// 
  966.             /// </summary>
  967.             /// <param name="arr"></param>
  968.             /// <returns></returns>
  969.             uint convertToInt16U(byte[] arr)
  970.             {
  971.                 if (arr.Length != 2)
  972.                     return 0;
  973.                 else
  974.                     return Convert.ToUInt16(arr[1] << 8 | arr[0]);
  975.             }
  976.             #region IEnumerable Members
  977.             public IEnumerator GetEnumerator()
  978.             {
  979.                 // TODO:  Add EXIFextractor.GetEnumerator implementation
  980.                 return (new EXIFextractorEnumerator(this.properties));
  981.             }
  982.             #endregion
  983.         }
  984.         //
  985.         // dont touch this class. its for IEnumerator
  986.         // 
  987.         //
  988.         class EXIFextractorEnumerator : IEnumerator
  989.         {
  990.             Dictionary<string,string> exifTable;
  991.             IDictionaryEnumerator index;
  992.             internal EXIFextractorEnumerator(Dictionary<string,string> exif)
  993.             {
  994.                 this.exifTable = exif;
  995.                 this.Reset();
  996.                 index = exif.GetEnumerator();
  997.             }
  998.             #region IEnumerator Members
  999.             public void Reset()
  1000.             {
  1001.                 this.index = null;
  1002.             }
  1003.             public object Current
  1004.             {
  1005.                 get
  1006.                 {
  1007.                     return (new DictionaryEntry(this.index.Key, this.index.Value));
  1008.                 }
  1009.             }
  1010.             public bool MoveNext()
  1011.             {
  1012.                 if (index != null && index.MoveNext())
  1013.                     return true;
  1014.                 else
  1015.                     return false;
  1016.             }
  1017.             #endregion
  1018.         }
  1019.         /// <summary>
  1020.         /// Summary description for translation.
  1021.         /// </summary>
  1022.         public class translation : Hashtable
  1023.         {
  1024.             /// <summary>
  1025.             /// 
  1026.             /// </summary>
  1027.             public translation()
  1028.             {
  1029.                 this.Add(0x8769, "Exif IFD");
  1030.                 this.Add(0x8825, "Gps IFD");
  1031.                 this.Add(0xFE, "New Subfile Type");
  1032.                 this.Add(0xFF, "Subfile Type");
  1033.                 this.Add(0x100, "Image Width");
  1034.                 this.Add(0x101, "Image Height");
  1035.                 this.Add(0x102, "Bits Per Sample");
  1036.                 this.Add(0x103, "Compression");
  1037.                 this.Add(0x106, "Photometric Interp");
  1038.                 this.Add(0x107, "Thresh Holding");
  1039.                 this.Add(0x108, "Cell Width");
  1040.                 this.Add(0x109, "Cell Height");
  1041.                 this.Add(0x10A, "Fill Order");
  1042.                 this.Add(0x10D, "Document Name");
  1043.                 this.Add(0x10E, "Image Description");
  1044.                 this.Add(0x10F, "Equip Make");
  1045.                 this.Add(0x110, "Equip Model");
  1046.                 this.Add(0x111, "Strip Offsets");
  1047.                 this.Add(0x112, "Orientation");
  1048.                 this.Add(0x115, "Samples PerPixel");
  1049.                 this.Add(0x116, "Rows Per Strip");
  1050.                 this.Add(0x117, "Strip Bytes Count");
  1051.                 this.Add(0x118, "Min Sample Value");
  1052.                 this.Add(0x119, "Max Sample Value");
  1053.                 this.Add(0x11A, "X Resolution");
  1054.                 this.Add(0x11B, "Y Resolution");
  1055.                 this.Add(0x11C, "Planar Config");
  1056.                 this.Add(0x11D, "Page Name");
  1057.                 this.Add(0x11E, "X Position");
  1058.                 this.Add(0x11F, "Y Position");
  1059.                 this.Add(0x120, "Free Offset");
  1060.                 this.Add(0x121, "Free Byte Counts");
  1061.                 this.Add(0x122, "Gray Response Unit");
  1062.                 this.Add(0x123, "Gray Response Curve");
  1063.                 this.Add(0x124, "T4 Option");
  1064.                 this.Add(0x125, "T6 Option");
  1065.                 this.Add(0x128, "Resolution Unit");
  1066.                 this.Add(0x129, "Page Number");
  1067.                 this.Add(0x12D, "Transfer Funcition");
  1068.                 this.Add(0x131, "Software Used");
  1069.                 this.Add(0x132, "Date Time");
  1070.                 this.Add(0x13B, "Artist");
  1071.                 this.Add(0x13C, "Host Computer");
  1072.                 this.Add(0x13D, "Predictor");
  1073.                 this.Add(0x13E, "White Point");
  1074.                 this.Add(0x13F, "Primary Chromaticities");
  1075.                 this.Add(0x140, "ColorMap");
  1076.                 this.Add(0x141, "Halftone Hints");
  1077.                 this.Add(0x142, "Tile Width");
  1078.                 this.Add(0x143, "Tile Length");
  1079.                 this.Add(0x144, "Tile Offset");
  1080.                 this.Add(0x145, "Tile ByteCounts");
  1081.                 this.Add(0x14C, "InkSet");
  1082.                 this.Add(0x14D, "Ink Names");
  1083.                 this.Add(0x14E, "Number Of Inks");
  1084.                 this.Add(0x150, "Dot Range");
  1085.                 this.Add(0x151, "Target Printer");
  1086.                 this.Add(0x152, "Extra Samples");
  1087.                 this.Add(0x153, "Sample Format");
  1088.                 this.Add(0x154, "S Min Sample Value");
  1089.                 this.Add(0x155, "S Max Sample Value");
  1090.                 this.Add(0x156, "Transfer Range");
  1091.                 this.Add(0x200, "JPEG Proc");
  1092.                 this.Add(0x201, "JPEG InterFormat");
  1093.                 this.Add(0x202, "JPEG InterLength");
  1094.                 this.Add(0x203, "JPEG RestartInterval");
  1095.                 this.Add(0x205, "JPEG LosslessPredictors");
  1096.                 this.Add(0x206, "JPEG PointTransforms");
  1097.                 this.Add(0x207, "JPEG QTables");
  1098.                 this.Add(0x208, "JPEG DCTables");
  1099.                 this.Add(0x209, "JPEG ACTables");
  1100.                 this.Add(0x211, "YCbCr Coefficients");
  1101.                 this.Add(0x212, "YCbCr Subsampling");
  1102.                 this.Add(0x213, "YCbCr Positioning");
  1103.                 this.Add(0x214, "REF Black White");
  1104.                 this.Add(0x8773, "ICC Profile");
  1105.                 this.Add(0x301, "Gamma");
  1106.                 this.Add(0x302, "ICC Profile Descriptor");
  1107.                 this.Add(0x303, "SRGB RenderingIntent");
  1108.                 this.Add(0x320, "Image Title");
  1109.                 this.Add(0x8298, "Copyright");
  1110.                 this.Add(0x5001, "Resolution X Unit");
  1111.                 this.Add(0x5002, "Resolution Y Unit");
  1112.                 this.Add(0x5003, "Resolution X LengthUnit");
  1113.                 this.Add(0x5004, "Resolution Y LengthUnit");
  1114.                 this.Add(0x5005, "Print Flags");
  1115.                 this.Add(0x5006, "Print Flags Version");
  1116.                 this.Add(0x5007, "Print Flags Crop");
  1117.                 this.Add(0x5008, "Print Flags Bleed Width");
  1118.                 this.Add(0x5009, "Print Flags Bleed Width Scale");
  1119.                 this.Add(0x500A, "Halftone LPI");
  1120.                 this.Add(0x500B, "Halftone LPIUnit");
  1121.                 this.Add(0x500C, "Halftone Degree");
  1122.                 this.Add(0x500D, "Halftone Shape");
  1123.                 this.Add(0x500E, "Halftone Misc");
  1124.                 this.Add(0x500F, "Halftone Screen");
  1125.                 this.Add(0x5010, "JPEG Quality");
  1126.                 this.Add(0x5011, "Grid Size");
  1127.                 this.Add(0x5012, "Thumbnail Format");
  1128.                 this.Add(0x5013, "Thumbnail Width");
  1129.                 this.Add(0x5014, "Thumbnail Height");
  1130.                 this.Add(0x5015, "Thumbnail ColorDepth");
  1131.                 this.Add(0x5016, "Thumbnail Planes");
  1132.                 this.Add(0x5017, "Thumbnail RawBytes");
  1133.                 this.Add(0x5018, "Thumbnail Size");
  1134.                 this.Add(0x5019, "Thumbnail CompressedSize");
  1135.                 this.Add(0x501A, "Color Transfer Function");
  1136.                 this.Add(0x501B, "Thumbnail Data");
  1137.                 this.Add(0x5020, "Thumbnail ImageWidth");
  1138.                 this.Add(0x502, "Thumbnail ImageHeight");
  1139.                 this.Add(0x5022, "Thumbnail BitsPerSample");
  1140.                 this.Add(0x5023, "Thumbnail Compression");
  1141.                 this.Add(0x5024, "Thumbnail PhotometricInterp");
  1142.                 this.Add(0x5025, "Thumbnail ImageDescription");
  1143.                 this.Add(0x5026, "Thumbnail EquipMake");
  1144.                 this.Add(0x5027, "Thumbnail EquipModel");
  1145.                 this.Add(0x5028, "Thumbnail StripOffsets");
  1146.                 this.Add(0x5029, "Thumbnail Orientation");
  1147.                 this.Add(0x502A, "Thumbnail SamplesPerPixel");
  1148.                 this.Add(0x502B, "Thumbnail RowsPerStrip");
  1149.                 this.Add(0x502C, "Thumbnail StripBytesCount");
  1150.                 this.Add(0x502D, "Thumbnail ResolutionX");
  1151.                 this.Add(0x502E, "Thumbnail ResolutionY");
  1152.                 this.Add(0x502F, "Thumbnail PlanarConfig");
  1153.                 this.Add(0x5030, "Thumbnail ResolutionUnit");
  1154.                 this.Add(0x5031, "Thumbnail TransferFunction");
  1155.                 this.Add(0x5032, "Thumbnail SoftwareUsed");
  1156.                 this.Add(0x5033, "Thumbnail DateTime");
  1157.                 this.Add(0x5034, "Thumbnail Artist");
  1158.                 this.Add(0x5035, "Thumbnail WhitePoint");
  1159.                 this.Add(0x5036, "Thumbnail PrimaryChromaticities");
  1160.                 this.Add(0x5037, "Thumbnail YCbCrCoefficients");
  1161.                 this.Add(0x5038, "Thumbnail YCbCrSubsampling");
  1162.                 this.Add(0x5039, "Thumbnail YCbCrPositioning");
  1163.                 this.Add(0x503A, "Thumbnail RefBlackWhite");
  1164.                 this.Add(0x503B, "Thumbnail CopyRight");
  1165.                 this.Add(0x5090, "Luminance Table");
  1166.                 this.Add(0x5091, "Chrominance Table");
  1167.                 this.Add(0x5100, "Frame Delay");
  1168.                 this.Add(0x5101, "Loop Count");
  1169.                 this.Add(0x5110, "Pixel Unit");
  1170.                 this.Add(0x5111, "Pixel PerUnit X");
  1171.                 this.Add(0x5112, "Pixel PerUnit Y");
  1172.                 this.Add(0x5113, "Palette Histogram");
  1173.                 this.Add(0x829A, "Exposure Time");
  1174.                 this.Add(0x829D, "F-Number");
  1175.                 this.Add(0x8822, "Exposure Prog");
  1176.                 this.Add(0x8824, "Spectral Sense");
  1177.                 this.Add(0x8827, "ISO Speed");
  1178.                 this.Add(0x8828, "OECF");
  1179.                 this.Add(0x9000, "Ver");
  1180.                 this.Add(0x9003, "DTOrig");
  1181.                 this.Add(0x9004, "DTDigitized");
  1182.                 this.Add(0x9101, "CompConfig");
  1183.                 this.Add(0x9102, "CompBPP");
  1184.                 this.Add(0x9201, "Shutter Speed");
  1185.                 this.Add(0x9202, "Aperture");
  1186.                 this.Add(0x9203, "Brightness");
  1187.                 this.Add(0x9204, "Exposure Bias");
  1188.                 this.Add(0x9205, "MaxAperture");
  1189.                 this.Add(0x9206, "SubjectDist");
  1190.                 this.Add(0x9207, "Metering Mode");
  1191.                 this.Add(0x9208, "LightSource");
  1192.                 this.Add(0x9209, "Flash");
  1193.                 this.Add(0x920A, "FocalLength");
  1194.                 this.Add(0x927C, "Maker Note");
  1195.                 this.Add(0x9286, "User Comment");
  1196.                 this.Add(0x9290, "DTSubsec");
  1197.                 this.Add(0x9291, "DTOrigSS");
  1198.                 this.Add(0x9292, "DTDigSS");
  1199.                 this.Add(0xA000, "FPXVer");
  1200.                 this.Add(0xA001, "ColorSpace");
  1201.                 this.Add(0xA002, "PixXDim");
  1202.                 this.Add(0xA003, "PixYDim");
  1203.                 this.Add(0xA004, "RelatedWav");
  1204.                 this.Add(0xA005, "Interop");
  1205.                 this.Add(0xA20B, "FlashEnergy");
  1206.                 this.Add(0xA20C, "SpatialFR");
  1207.                 this.Add(0xA20E, "FocalXRes");
  1208.                 this.Add(0xA20F, "FocalYRes");
  1209.                 this.Add(0xA210, "FocalResUnit");
  1210.                 this.Add(0xA214, "Subject Loc");
  1211.                 this.Add(0xA215, "Exposure Index");
  1212.                 this.Add(0xA217, "Sensing Method");
  1213.                 this.Add(0xA300, "FileSource");
  1214.                 this.Add(0xA301, "SceneType");
  1215.                 this.Add(0xA302, "CfaPattern");
  1216.                 this.Add(0x0, "Gps Ver");
  1217.                 this.Add(0x1, "Gps LatitudeRef");
  1218.                 this.Add(0x2, "Gps Latitude");
  1219.                 this.Add(0x3, "Gps LongitudeRef");
  1220.                 this.Add(0x4, "Gps Longitude");
  1221.                 this.Add(0x5, "Gps AltitudeRef");
  1222.                 this.Add(0x6, "Gps Altitude");
  1223.                 this.Add(0x7, "Gps GpsTime");
  1224.                 this.Add(0x8, "Gps GpsSatellites");
  1225.                 this.Add(0x9, "Gps GpsStatus");
  1226.                 this.Add(0xA, "Gps GpsMeasureMode");
  1227.                 this.Add(0xB, "Gps GpsDop");
  1228.                 this.Add(0xC, "Gps SpeedRef");
  1229.                 this.Add(0xD, "Gps Speed");
  1230.                 this.Add(0xE, "Gps TrackRef");
  1231.                 this.Add(0xF, "Gps Track");
  1232.                 this.Add(0x10, "Gps ImgDirRef");
  1233.                 this.Add(0x11, "Gps ImgDir");
  1234.                 this.Add(0x12, "Gps MapDatum");
  1235.                 this.Add(0x13, "Gps DestLatRef");
  1236.                 this.Add(0x14, "Gps DestLat");
  1237.                 this.Add(0x15, "Gps DestLongRef");
  1238.                 this.Add(0x16, "Gps DestLong");
  1239.                 this.Add(0x17, "Gps DestBearRef");
  1240.                 this.Add(0x18, "Gps DestBear");
  1241.                 this.Add(0x19, "Gps DestDistRef");
  1242.                 this.Add(0x1A, "Gps DestDist");
  1243.             }
  1244.         }
  1245.         /// <summary>
  1246.         /// private class
  1247.         /// </summary>
  1248.         internal class Rational
  1249.         {
  1250.             private int n;
  1251.             private int d;
  1252.             public Rational(int n, int d)
  1253.             {
  1254.                 this.n = n;
  1255.                 this.d = d;
  1256.                 simplify(ref this.n, ref this.d);
  1257.             }
  1258.             public Rational(uint n, uint d)
  1259.             {
  1260.                 this.n = Convert.ToInt32(n);
  1261.                 this.d = Convert.ToInt32(d);
  1262.                 simplify(ref this.n, ref this.d);
  1263.             }
  1264.             public Rational()
  1265.             {
  1266.                 this.n = this.d = 0;
  1267.             }
  1268.             public string ToString(string sp)
  1269.             {
  1270.                 if (sp == null) sp = "/";
  1271.                 return n.ToString() + sp + d.ToString();
  1272.             }
  1273.             public double ToDouble()
  1274.             {
  1275.                 if (d == 0)
  1276.                     return 0.0;
  1277.                 return Math.Round(Convert.ToDouble(n) / Convert.ToDouble(d), 2);
  1278.             }
  1279.             private void simplify(ref int a, ref int b)
  1280.             {
  1281.                 if (a == 0 || b == 0)
  1282.                     return;
  1283.                 int gcd = euclid(a, b);
  1284.                 a /= gcd;
  1285.                 b /= gcd;
  1286.             }
  1287.             private int euclid(int a, int b)
  1288.             {
  1289.                 if (b == 0)
  1290.                     return a;
  1291.                 else
  1292.                     return euclid(b, a % b);
  1293.             }
  1294.         }
  1295.     }
  1296. }