Advertisement
phommel

Exif Classes

May 5th, 2015
439
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 42.59 KB | None | 0 0
  1. public sealed class ExifTagCollection : IEnumerable<ExifTag>
  2. {
  3.     private Dictionary<int, ExifTag> _tags;
  4.  
  5.     #region Constructors
  6.     public ExifTagCollection(string fileName)
  7.         : this(fileName, true, false)
  8.     {
  9.     }
  10.  
  11.     public ExifTagCollection(string fileName, bool useEmbeddedColorManagement, bool validateImageData)
  12.     {
  13.         using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
  14.         {
  15.             Image image = System.Drawing.Image.FromStream(stream,
  16.                 useEmbeddedColorManagement,
  17.                 validateImageData);
  18.  
  19.             ReadTags(image.PropertyItems);
  20.             image.Dispose();
  21.         }
  22.     }
  23.  
  24.     public ExifTagCollection(Image image)
  25.     {
  26.         ReadTags(image.PropertyItems);
  27.     }
  28.     #endregion
  29.  
  30.     #region Private Methods
  31.     private void ReadTags(PropertyItem[] pitems)
  32.     {
  33.         Encoding ascii = Encoding.ASCII;
  34.         SupportedTags supportedTags = new SupportedTags();
  35.         _tags = new Dictionary<int, ExifTag>();
  36.  
  37.         foreach (PropertyItem pitem in pitems)
  38.         {
  39.             ExifTag tag = (ExifTag)supportedTags[pitem.Id];
  40.  
  41.             if (tag == null) continue;
  42.  
  43.             string value = "";
  44.             if (pitem.Value == null) continue;
  45.             if (pitem.Type == 0x1)
  46.             {
  47.                 #region BYTE (8-bit unsigned int)
  48.                 if (pitem.Value.Length == 4)
  49.                     value = "Version " + pitem.Value[0].ToString() + "." + pitem.Value[1].ToString();
  50.                 else if (pitem.Id == 0x5 && pitem.Value[0] == 0)
  51.                     value = "Sea level";
  52.                 else
  53.                     value = pitem.Value[0].ToString();
  54.                 #endregion
  55.             }
  56.             else if (pitem.Type == 0x2)
  57.             {
  58.                 #region ASCII (8 bit ASCII code)
  59.  
  60.                 value = ascii.GetString(pitem.Value).Trim('\0');
  61.  
  62.                 if (pitem.Id == 0x1 || pitem.Id == 0x13)
  63.                     if (value == "N") value = "North latitude";
  64.                     else if (value == "S") value = "South latitude";
  65.                     else value = "reserved";
  66.  
  67.                 if (pitem.Id == 0x3 || pitem.Id == 0x15)
  68.                     if (value == "E") value = "East longitude";
  69.                     else if (value == "W") value = "West longitude";
  70.                     else value = "reserved";
  71.  
  72.                 if (pitem.Id == 0x9)
  73.                     if (value == "A") value = "Measurement in progress";
  74.                     else if (value == "V") value = "Measurement Interoperability";
  75.                     else value = "reserved";
  76.  
  77.                 if (pitem.Id == 0xA)
  78.                     if (value == "2") value = "2-dimensional measurement";
  79.                     else if (value == "3") value = "3-dimensional measurement";
  80.                     else value = "reserved";
  81.  
  82.                 if (pitem.Id == 0xC || pitem.Id == 0x19)
  83.                     if (value == "K") value = "Kilometers per hour";
  84.                     else if (value == "M") value = "Miles per hour";
  85.                     else if (value == "N") value = "Knots";
  86.                     else value = "reserved";
  87.  
  88.                 if (pitem.Id == 0xE || pitem.Id == 0x10 || pitem.Id == 0x17)
  89.                     if (value == "T") value = "True direction";
  90.                     else if (value == "M") value = "Magnetic direction";
  91.                     else value = "reserved";
  92.                 #endregion
  93.             }
  94.             else if (pitem.Type == 0x3)
  95.             {
  96.                 #region 3 = SHORT (16-bit unsigned int)
  97.  
  98.                 UInt16 uintval = BitConverter.ToUInt16(pitem.Value, 0);
  99.  
  100.                 // orientation // lookup table                  
  101.                 switch (pitem.Id)
  102.                 {
  103.                     case 0x8827: // ISO speed rating
  104.                         value = "ISO-" + uintval.ToString();
  105.                         break;
  106.                     case 0xA217: // sensing method
  107.                         {
  108.                             switch (uintval)
  109.                             {
  110.                                 case 1: value = "Not defined"; break;
  111.                                 case 2: value = "One-chip color area sensor"; break;
  112.                                 case 3: value = "Two-chip color area sensor"; break;
  113.                                 case 4: value = "Three-chip color area sensor"; break;
  114.                                 case 5: value = "Color sequential area sensor"; break;
  115.                                 case 7: value = "Trilinear sensor"; break;
  116.                                 case 8: value = "Color sequential linear sensor"; break;
  117.                                 default: value = " reserved"; break;
  118.                             }
  119.                         }
  120.                         break;
  121.                     case 0x8822: // Exposure program
  122.                         switch (uintval)
  123.                         {
  124.                             case 0: value = "Not defined"; break;
  125.                             case 1: value = "Manual"; break;
  126.                             case 2: value = "Normal program"; break;
  127.                             case 3: value = "Aperture priority"; break;
  128.                             case 4: value = "Shutter priority"; break;
  129.                             case 5: value = "Creative program (biased toward depth of field)"; break;
  130.                             case 6: value = "Action program (biased toward fast shutter speed)"; break;
  131.                             case 7: value = "Portrait mode (for closeup photos with the background out of focus)"; break;
  132.                             case 8: value = "Landscape mode (for landscape photos with the background in focus)"; break;
  133.                             default: value = "reserved"; break;
  134.                         }
  135.                         break;
  136.                     case 0x9207: // metering mode
  137.                         switch (uintval)
  138.                         {
  139.                             case 0: value = "unknown"; break;
  140.                             case 1: value = "Average"; break;
  141.                             case 2: value = "Center Weighted Average"; break;
  142.                             case 3: value = "Spot"; break;
  143.                             case 4: value = "MultiSpot"; break;
  144.                             case 5: value = "Pattern"; break;
  145.                             case 6: value = "Partial"; break;
  146.                             case 255: value = "Other"; break;
  147.                             default: value = "reserved"; break;
  148.                         }
  149.                         break;
  150.                     case 0x9208: // Light source
  151.                         {
  152.                             switch (uintval)
  153.                             {
  154.                                 case 0: value = "unknown"; break;
  155.                                 case 1: value = "Daylight"; break;
  156.                                 case 2: value = "Fluorescent"; break;
  157.                                 case 3: value = "Tungsten (incandescent light)"; break;
  158.                                 case 4: value = "Flash"; break;
  159.                                 case 9: value = "Fine weather"; break;
  160.                                 case 10: value = "Cloudy weather"; break;
  161.                                 case 11: value = "Shade"; break;
  162.                                 case 12: value = "Daylight fluorescent (D 5700 – 7100K)"; break;
  163.                                 case 13: value = "Day white fluorescent (N 4600 – 5400K)"; break;
  164.                                 case 14: value = "Cool white fluorescent (W 3900 – 4500K)"; break;
  165.                                 case 15: value = "White fluorescent (WW 3200 – 3700K)"; break;
  166.                                 case 17: value = "Standard light A"; break;
  167.                                 case 18: value = "Standard light B"; break;
  168.                                 case 19: value = "Standard light C"; break;
  169.                                 case 20: value = "D55"; break;
  170.                                 case 21: value = "D65"; break;
  171.                                 case 22: value = "D75"; break;
  172.                                 case 23: value = "D50"; break;
  173.                                 case 24: value = "ISO studio tungsten"; break;
  174.                                 case 255: value = "ISO studio tungsten"; break;
  175.                                 default: value = "other light source"; break;
  176.                             }
  177.                         }
  178.                         break;
  179.                     case 0x9209: // Flash
  180.                         {
  181.                             switch (uintval)
  182.                             {
  183.                                 case 0x0: value = "Flash did not fire"; break;
  184.                                 case 0x1: value = "Flash fired"; break;
  185.                                 case 0x5: value = "Strobe return light not detected"; break;
  186.                                 case 0x7: value = "Strobe return light detected"; break;
  187.                                 case 0x9: value = "Flash fired, compulsory flash mode"; break;
  188.                                 case 0xD: value = "Flash fired, compulsory flash mode, return light not detected"; break;
  189.                                 case 0xF: value = "Flash fired, compulsory flash mode, return light detected"; break;
  190.                                 case 0x10: value = "Flash did not fire, compulsory flash mode"; break;
  191.                                 case 0x18: value = "Flash did not fire, auto mode"; break;
  192.                                 case 0x19: value = "Flash fired, auto mode"; break;
  193.                                 case 0x1D: value = "Flash fired, auto mode, return light not detected"; break;
  194.                                 case 0x1F: value = "Flash fired, auto mode, return light detected"; break;
  195.                                 case 0x20: value = "No flash function"; break;
  196.                                 case 0x41: value = "Flash fired, red-eye reduction mode"; break;
  197.                                 case 0x45: value = "Flash fired, red-eye reduction mode, return light not detected"; break;
  198.                                 case 0x47: value = "Flash fired, red-eye reduction mode, return light detected"; break;
  199.                                 case 0x49: value = "Flash fired, compulsory flash mode, red-eye reduction mode"; break;
  200.                                 case 0x4D: value = "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected"; break;
  201.                                 case 0x4F: value = "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected"; break;
  202.                                 case 0x59: value = "Flash fired, auto mode, red-eye reduction mode"; break;
  203.                                 case 0x5D: value = "Flash fired, auto mode, return light not detected, red-eye reduction mode"; break;
  204.                                 case 0x5F: value = "Flash fired, auto mode, return light detected, red-eye reduction mode"; break;
  205.                                 default: value = "reserved"; break;
  206.                             }
  207.                         }
  208.                         break;
  209.                     case 0x0128: //ResolutionUnit
  210.                         {
  211.                             switch (uintval)
  212.                             {
  213.                                 case 2: value = "Inch"; break;
  214.                                 case 3: value = "Centimeter"; break;
  215.                                 default: value = "No Unit"; break;
  216.                             }
  217.                         }
  218.                         break;
  219.                     case 0xA409: // Saturation
  220.                         {
  221.                             switch (uintval)
  222.                             {
  223.                                 case 0: value = "Normal"; break;
  224.                                 case 1: value = "Low saturation"; break;
  225.                                 case 2: value = "High saturation"; break;
  226.                                 default: value = "Reserved"; break;
  227.                             }
  228.                         }
  229.                         break;
  230.  
  231.                     case 0xA40A: // Sharpness
  232.                         {
  233.                             switch (uintval)
  234.                             {
  235.                                 case 0: value = "Normal"; break;
  236.                                 case 1: value = "Soft"; break;
  237.                                 case 2: value = "Hard"; break;
  238.                                 default: value = "Reserved"; break;
  239.                             }
  240.                         }
  241.                         break;
  242.                     case 0xA408: // Contrast
  243.                         {
  244.                             switch (uintval)
  245.                             {
  246.                                 case 0: value = "Normal"; break;
  247.                                 case 1: value = "Soft"; break;
  248.                                 case 2: value = "Hard"; break;
  249.                                 default: value = "Reserved"; break;
  250.                             }
  251.                         }
  252.                         break;
  253.                     case 0x103: // Compression
  254.                         {
  255.                             switch (uintval)
  256.                             {
  257.                                 case 1: value = "Uncompressed"; break;
  258.                                 case 6: value = "JPEG compression (thumbnails only)"; break;
  259.                                 default: value = "Reserved"; break;
  260.                             }
  261.                         }
  262.                         break;
  263.                     case 0x106: // PhotometricInterpretation
  264.                         {
  265.                             switch (uintval)
  266.                             {
  267.                                 case 2: value = "RGB"; break;
  268.                                 case 6: value = "YCbCr"; break;
  269.                                 default: value = "Reserved"; break;
  270.                             }
  271.                         }
  272.                         break;
  273.                     case 0x112: // Orientation
  274.                         {
  275.                             switch (uintval)
  276.                             {
  277.                                 case 1: value = "The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side."; break;
  278.                                 case 2: value = "The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side."; break;
  279.                                 case 3: value = "The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side."; break;
  280.                                 case 4: value = "The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side."; break;
  281.                                 case 5: value = "The 0th row is the visual left-hand side of the image, and the 0th column is the visual top."; break;
  282.                                 case 6: value = "The 0th row is the visual right-hand side of the image, and the 0th column is the visual top."; break;
  283.                                 case 7: value = "The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom."; break;
  284.                                 case 8: value = "The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom."; break;
  285.                                 default: value = "Reserved"; break;
  286.                             }
  287.                         }
  288.                         break;
  289.                     case 0x213: // YCbCrPositioning
  290.                         {
  291.                             switch (uintval)
  292.                             {
  293.                                 case 1: value = "centered"; break;
  294.                                 case 6: value = "co-sited"; break;
  295.                                 default: value = "Reserved"; break;
  296.                             }
  297.                         }
  298.                         break;
  299.                     case 0xA001: // ColorSpace
  300.                         {
  301.                             switch (uintval)
  302.                             {
  303.                                 case 1: value = "sRGB"; break;
  304.                                 case 0xFFFF: value = "Uncalibrated"; break;
  305.                                 default: value = "Reserved"; break;
  306.                             }
  307.                         }
  308.                         break;
  309.                     case 0xA401: // CustomRendered
  310.                         {
  311.                             switch (uintval)
  312.                             {
  313.                                 case 0: value = "Normal process"; break;
  314.                                 case 1: value = "Custom process"; break;
  315.                                 default: value = "Reserved"; break;
  316.                             }
  317.                         }
  318.                         break;
  319.                     case 0xA402: // ExposureMode
  320.                         {
  321.                             switch (uintval)
  322.                             {
  323.                                 case 0: value = "Auto exposure"; break;
  324.                                 case 1: value = "Manual exposure"; break;
  325.                                 case 2: value = "Auto bracket"; break;
  326.                                 default: value = "Reserved"; break;
  327.                             }
  328.                         }
  329.                         break;
  330.                     case 0xA403: // WhiteBalance
  331.                         {
  332.                             switch (uintval)
  333.                             {
  334.                                 case 0: value = "Auto white balance"; break;
  335.                                 case 1: value = "Manual white balance"; break;
  336.                                 default: value = "Reserved"; break;
  337.                             }
  338.                         }
  339.                         break;
  340.                     case 0xA406: // SceneCaptureType
  341.                         {
  342.                             switch (uintval)
  343.                             {
  344.                                 case 0: value = "Standard"; break;
  345.                                 case 1: value = "Landscape"; break;
  346.                                 case 2: value = "Portrait"; break;
  347.                                 case 3: value = "Night scene"; break;
  348.                                 default: value = "Reserved"; break;
  349.                             }
  350.                         }
  351.                         break;
  352.  
  353.                     case 0xA40C: // SubjectDistanceRange
  354.                         {
  355.                             switch (uintval)
  356.                             {
  357.                                 case 0: value = "unknown"; break;
  358.                                 case 1: value = "Macro"; break;
  359.                                 case 2: value = "Close view"; break;
  360.                                 case 3: value = "Distant view"; break;
  361.                                 default: value = "Reserved"; break;
  362.                             }
  363.                         }
  364.                         break;
  365.                     case 0x1E: // GPSDifferential
  366.                         {
  367.                             switch (uintval)
  368.                             {
  369.                                 case 0: value = "Measurement without differential correction"; break;
  370.                                 case 1: value = "Differential correction applied"; break;
  371.                                 default: value = "Reserved"; break;
  372.                             }
  373.                         }
  374.                         break;
  375.                     case 0xA405: // FocalLengthIn35mmFilm
  376.                         value = uintval.ToString() + " mm";
  377.                         break;
  378.                     default://
  379.                         value = uintval.ToString();
  380.                         break;
  381.                 }
  382.                 #endregion
  383.             }
  384.             else if (pitem.Type == 0x4)
  385.             {
  386.                 #region 4 = LONG (32-bit unsigned int)
  387.                 value = BitConverter.ToUInt32(pitem.Value, 0).ToString();
  388.                 #endregion
  389.             }
  390.             else if (pitem.Type == 0x5)
  391.             {
  392.                 #region 5 = RATIONAL (Two LONGs, unsigned)
  393.  
  394.                 URational rat = new URational(pitem.Value);
  395.  
  396.                 switch (pitem.Id)
  397.                 {
  398.                     case 0x9202: // ApertureValue
  399.                         value = "F/" + Math.Round(Math.Pow(Math.Sqrt(2), rat.ToDouble()), 2).ToString();
  400.                         break;
  401.                     case 0x9205: // MaxApertureValue
  402.                         value = "F/" + Math.Round(Math.Pow(Math.Sqrt(2), rat.ToDouble()), 2).ToString();
  403.                         break;
  404.                     case 0x920A: // FocalLength
  405.                         value = rat.ToDouble().ToString() + " mm";
  406.                         break;
  407.                     case 0x829D: // F-number
  408.                         value = "F/" + rat.ToDouble().ToString();
  409.                         break;
  410.                     case 0x11A: // Xresolution
  411.                         value = rat.ToDouble().ToString();
  412.                         break;
  413.                     case 0x11B: // Yresolution
  414.                         value = rat.ToDouble().ToString();
  415.                         break;
  416.                     case 0x829A: // ExposureTime
  417.                         value = rat.ToString() + " sec";
  418.                         break;
  419.                     case 0x2: // GPSLatitude                                
  420.                         value = new GPSRational(pitem.Value).ToString();
  421.                         break;
  422.                     case 0x4: // GPSLongitude
  423.                         value = new GPSRational(pitem.Value).ToString();
  424.                         break;
  425.                     case 0x6: // GPSAltitude
  426.                         value = rat.ToDouble() + " meters";
  427.                         break;
  428.                     case 0xA404: // Digital Zoom Ratio
  429.                         value = rat.ToDouble().ToString();
  430.                         if (value == "0") value = "none";
  431.                         break;
  432.                     case 0xB: // GPSDOP
  433.                         value = rat.ToDouble().ToString();
  434.                         break;
  435.                     case 0xD: // GPSSpeed
  436.                         value = rat.ToDouble().ToString();
  437.                         break;
  438.                     case 0xF: // GPSTrack
  439.                         value = rat.ToDouble().ToString();
  440.                         break;
  441.                     case 0x11: // GPSImgDir
  442.                         value = rat.ToDouble().ToString();
  443.                         break;
  444.                     case 0x14: // GPSDestLatitude
  445.                         value = new GPSRational(pitem.Value).ToString();
  446.                         break;
  447.                     case 0x16: // GPSDestLongitude
  448.                         value = new GPSRational(pitem.Value).ToString();
  449.                         break;
  450.                     case 0x18: // GPSDestBearing
  451.                         value = rat.ToDouble().ToString();
  452.                         break;
  453.                     case 0x1A: // GPSDestDistance
  454.                         value = rat.ToDouble().ToString();
  455.                         break;
  456.                     case 0x7: // GPSTimeStamp                                
  457.                         value = new GPSRational(pitem.Value).ToString(":");
  458.                         break;
  459.  
  460.                     default:
  461.                         value = rat.ToString();
  462.                         break;
  463.                 }
  464.  
  465.                 #endregion
  466.             }
  467.             else if (pitem.Type == 0x7)
  468.             {
  469.                 #region UNDEFINED (8-bit)
  470.                 switch (pitem.Id)
  471.                 {
  472.                     case 0xA300: //FileSource
  473.                         {
  474.                             if (pitem.Value[0] == 3)
  475.                                 value = "DSC";
  476.                             else
  477.                                 value = "reserved";
  478.                             break;
  479.                         }
  480.                     case 0xA301: //SceneType
  481.                         if (pitem.Value[0] == 1)
  482.                             value = "A directly photographed image";
  483.                         else
  484.                             value = "reserved";
  485.                         break;
  486.                     case 0x9000:// Exif Version
  487.                         value = ascii.GetString(pitem.Value).Trim('\0');
  488.                         break;
  489.                     case 0xA000: // Flashpix Version
  490.                         value = ascii.GetString(pitem.Value).Trim('\0');
  491.                         if (value == "0100")
  492.                             value = "Flashpix Format Version 1.0";
  493.                         else value = "reserved";
  494.                         break;
  495.                     case 0x9101: //ComponentsConfiguration
  496.                         value = GetComponentsConfig(pitem.Value);
  497.                         break;
  498.                     case 0x927C: //MakerNote
  499.                         value = ascii.GetString(pitem.Value).Trim('\0');
  500.                         break;
  501.                     case 0x9286: //UserComment
  502.                         value = ascii.GetString(pitem.Value).Trim('\0');
  503.                         break;
  504.                     case 0x1B: //GPS Processing Method
  505.                         value = ascii.GetString(pitem.Value).Trim('\0');
  506.                         break;
  507.                     case 0x1C: //GPS Area Info
  508.                         value = ascii.GetString(pitem.Value).Trim('\0');
  509.                         break;
  510.                     default:
  511.                         value = "-";
  512.                         break;
  513.                 }
  514.                 #endregion
  515.             }
  516.             else if (pitem.Type == 0x9)
  517.             {
  518.                 #region 9 = SLONG (32-bit int)
  519.                 value = BitConverter.ToInt32(pitem.Value, 0).ToString();
  520.                 #endregion
  521.             }
  522.             else if (pitem.Type == 0xA)
  523.             {
  524.                 #region 10 = SRATIONAL (Two SLONGs, signed)
  525.  
  526.                 Rational rat = new Rational(pitem.Value);
  527.  
  528.                 switch (pitem.Id)
  529.                 {
  530.                     case 0x9201: // ShutterSpeedValue
  531.                         value = "1/" + Math.Round(Math.Pow(2, rat.ToDouble()), 2).ToString();
  532.                         break;
  533.                     case 0x9203: // BrightnessValue
  534.                         value = Math.Round(rat.ToDouble(), 4).ToString();
  535.                         break;
  536.                     case 0x9204: // ExposureBiasValue
  537.                         value = Math.Round(rat.ToDouble(), 2).ToString() + " eV";
  538.                         break;
  539.                     default:
  540.                         value = rat.ToString();
  541.                         break;
  542.                 }
  543.                 #endregion
  544.             }
  545.  
  546.             tag.Value = value;
  547.  
  548.             _tags.Add(tag.Id, tag);
  549.         }
  550.     }
  551.  
  552.     private static string GetComponentsConfig(byte[] bytes)
  553.     {
  554.         string s = "";
  555.         string[] vals = new string[] { "", "Y", "Cb", "Cr", "R", "G", "B" };
  556.  
  557.         foreach (byte b in bytes)
  558.             s += vals[b];
  559.  
  560.         return s;
  561.     }
  562.     #endregion
  563.  
  564.     #region IEnumerable<ExifTag> Members
  565.  
  566.     public IEnumerator<ExifTag> GetEnumerator()
  567.     {
  568.         return _tags.Values.GetEnumerator();
  569.     }
  570.  
  571.     #endregion
  572.  
  573.     #region IEnumerable Members
  574.  
  575.     IEnumerator IEnumerable.GetEnumerator()
  576.     {
  577.         return _tags.Values.GetEnumerator();
  578.     }
  579.  
  580.     #endregion
  581.  
  582.     #region Indexers
  583.     public ExifTag this[int id]
  584.     {
  585.         get
  586.         {
  587.             return _tags[id];
  588.         }
  589.     }
  590.  
  591.     public ExifTag this[string in_TagName]
  592.     {
  593.         get
  594.         {
  595.             ExifTag Result = null;
  596.             foreach (ExifTag etag in this)
  597.             {
  598.                 if (etag.FieldName == in_TagName)
  599.                 {
  600.                     Result = etag;
  601.                     break;
  602.                 }
  603.             }
  604.             return Result;
  605.         }
  606.     }
  607.     #endregion
  608.  
  609.     #region public methods
  610.     public string GetValueString(string in_TagName, string in_NotFoundValue)
  611.     {
  612.         ExifTag etag = this[in_TagName];
  613.         if (etag != null)
  614.             return etag.Value;
  615.         else
  616.             return in_NotFoundValue;
  617.     }
  618.  
  619.     public override string ToString()
  620.     {
  621.         StringBuilder Result = new StringBuilder();
  622.         foreach (ExifTag etag in this)
  623.         {
  624.             if (Result.Length == 0)
  625.                 Result.Append(etag.FieldName + ": " + etag.Value);
  626.             else
  627.             {
  628.                 Result.Append("\r\n");
  629.                 Result.Append(etag.FieldName);
  630.                 Result.Append(": ");
  631.                 Result.Append(etag.Value);
  632.             }
  633.         }
  634.  
  635.         return Result.ToString();
  636.     }
  637.     #endregion
  638. }
  639.  
  640. internal sealed class SupportedTags : Hashtable
  641. {
  642.     public SupportedTags()
  643.     {
  644.         this.Add(0x100, new ExifTag(0x100, "ImageWidth", "Image width"));
  645.         this.Add(0x101, new ExifTag(0x101, "ImageHeight", "Image height"));
  646.         this.Add(0x0, new ExifTag(0x0, "GPSVersionID", "GPS tag version"));
  647.         this.Add(0x5, new ExifTag(0x5, "GPSAltitudeRef", "Altitude reference"));
  648.         this.Add(0x111, new ExifTag(0x111, "StripOffsets", "Image data location"));
  649.         this.Add(0x116, new ExifTag(0x116, "RowsPerStrip", "Number of rows per strip"));
  650.         this.Add(0x117, new ExifTag(0x117, "StripByteCounts", "Bytes per compressed strip"));
  651.         this.Add(0xA002, new ExifTag(0xA002, "PixelXDimension", "Valid image width"));
  652.         this.Add(0xA003, new ExifTag(0xA003, "PixelYDimension", "Valid image height"));
  653.         this.Add(0x102, new ExifTag(0x102, "BitsPerSample", "Number of bits per component"));
  654.         this.Add(0x103, new ExifTag(0x103, "Compression", "Compression scheme"));
  655.         this.Add(0x106, new ExifTag(0x106, "PhotometricInterpretation", "Pixel composition"));
  656.         this.Add(0x112, new ExifTag(0x112, "Orientation", "Orientation of image"));
  657.         this.Add(0x115, new ExifTag(0x115, "SamplesPerPixel", "Number of components"));
  658.         this.Add(0x11C, new ExifTag(0x11C, "PlanarConfiguration", "Image data arrangement"));
  659.         this.Add(0x212, new ExifTag(0x212, "YCbCrSubSampling", "Subsampling ratio of Y to C"));
  660.         this.Add(0x213, new ExifTag(0x213, "YCbCrPositioning", "Y and C positioning"));
  661.         this.Add(0x128, new ExifTag(0x128, "ResolutionUnit", "Unit of X and Y resolution"));
  662.         this.Add(0x12D, new ExifTag(0x12D, "TransferFunction", "Transfer function"));
  663.         this.Add(0xA001, new ExifTag(0xA001, "ColorSpace", "Color space information"));
  664.         this.Add(0x8822, new ExifTag(0x8822, "ExposureProgram", "Exposure program"));
  665.         this.Add(0x8827, new ExifTag(0x8827, "ISOSpeedRatings", "ISO speed rating"));
  666.         this.Add(0x9207, new ExifTag(0x9207, "MeteringMode", "Metering mode"));
  667.         this.Add(0x9208, new ExifTag(0x9208, "LightSource", "Light source"));
  668.         this.Add(0x9209, new ExifTag(0x9209, "Flash", "Flash"));
  669.         this.Add(0x9214, new ExifTag(0x9214, "SubjectArea", "Subject area"));
  670.         this.Add(0xA210, new ExifTag(0xA210, "FocalPlaneResolutionUnit", "Focal plane resolution unit"));
  671.         this.Add(0xA214, new ExifTag(0xA214, "SubjectLocation", "Subject location"));
  672.         this.Add(0xA217, new ExifTag(0xA217, "SensingMethod", "Sensing method"));
  673.         this.Add(0xA401, new ExifTag(0xA401, "CustomRendered", "Custom image processing"));
  674.         this.Add(0xA402, new ExifTag(0xA402, "ExposureMode", "Exposure mode"));
  675.         this.Add(0xA403, new ExifTag(0xA403, "WhiteBalance", "White balance"));
  676.         this.Add(0xA405, new ExifTag(0xA405, "FocalLengthIn35mmFilm", "Focal length in 35 mm film"));
  677.         this.Add(0xA406, new ExifTag(0xA406, "SceneCaptureType", "Scene capture type"));
  678.         this.Add(0xA408, new ExifTag(0xA408, "Contrast", "Contrast"));
  679.         this.Add(0xA409, new ExifTag(0xA409, "Saturation", "Saturation"));
  680.         this.Add(0xA40A, new ExifTag(0xA40A, "Sharpness", "Sharpness"));
  681.         this.Add(0xA40C, new ExifTag(0xA40C, "SubjectDistanceRange", "Subject distance range"));
  682.         this.Add(0x1E, new ExifTag(0x1E, "GPSDifferential", "GPS differential correction"));
  683.         this.Add(0x9201, new ExifTag(0x9201, "ShutterSpeedValue", "Shutter speed"));
  684.         this.Add(0x9203, new ExifTag(0x9203, "BrightnessValue", "Brightness"));
  685.         this.Add(0x9204, new ExifTag(0x9204, "ExposureBiasValue", "Exposure bias"));
  686.         this.Add(0x201, new ExifTag(0x201, "JPEGInterchangeFormat", "Offset to JPEG SOI"));
  687.         this.Add(0x202, new ExifTag(0x202, "JPEGInterchangeFormatLength", "Bytes of JPEG data"));
  688.         this.Add(0x11A, new ExifTag(0x11A, "XResolution", "Image resolution in width direction"));
  689.         this.Add(0x11B, new ExifTag(0x11B, "YResolution", "Image resolution in height direction"));
  690.         this.Add(0x13E, new ExifTag(0x13E, "WhitePoint", "White point chromaticity"));
  691.         this.Add(0x13F, new ExifTag(0x13F, "PrimaryChromaticities", "Chromaticities of primaries"));
  692.         this.Add(0x211, new ExifTag(0x211, "YCbCrCoefficients", "Color space transformation matrix coefficients"));
  693.         this.Add(0x214, new ExifTag(0x214, "ReferenceBlackWhite", "Pair of black and white reference values"));
  694.         this.Add(0x9102, new ExifTag(0x9102, "CompressedBitsPerPixel", "Image compression mode"));
  695.         this.Add(0x829A, new ExifTag(0x829A, "ExposureTime", "Exposure time"));
  696.         this.Add(0x829D, new ExifTag(0x829D, "FNumber", "F number"));
  697.         this.Add(0x9202, new ExifTag(0x9202, "ApertureValue", "Aperture"));
  698.         this.Add(0x9205, new ExifTag(0x9205, "MaxApertureValue", "Maximum lens aperture"));
  699.         this.Add(0x9206, new ExifTag(0x9206, "SubjectDistance", "Subject distance"));
  700.         this.Add(0x920A, new ExifTag(0x920A, "FocalLength", "Lens focal length"));
  701.         this.Add(0xA20B, new ExifTag(0xA20B, "FlashEnergy", "Flash energy"));
  702.         this.Add(0xA20E, new ExifTag(0xA20E, "FocalPlaneXResolution", "Focal plane X resolution"));
  703.         this.Add(0xA20F, new ExifTag(0xA20F, "FocalPlaneYResolution", "Focal plane Y resolution"));
  704.         this.Add(0xA215, new ExifTag(0xA215, "ExposureIndex", "Exposure index"));
  705.         this.Add(0xA404, new ExifTag(0xA404, "DigitalZoomRatio", "Digital zoom ratio"));
  706.         this.Add(0xA407, new ExifTag(0xA407, "GainControl", "Gain control"));
  707.         this.Add(0x2, new ExifTag(0x2, "GPSLatitude", "Latitude"));
  708.         this.Add(0x4, new ExifTag(0x4, "GPSLongitude", "Longitude"));
  709.         this.Add(0x6, new ExifTag(0x6, "GPSAltitude", "Altitude"));
  710.         this.Add(0x7, new ExifTag(0x7, "GPSTimeStamp", "GPS time (atomic clock)"));
  711.         this.Add(0xB, new ExifTag(0xB, "GPSDOP", "Measurement precision"));
  712.         this.Add(0xD, new ExifTag(0xD, "GPSSpeed", "Speed of GPS receiver"));
  713.         this.Add(0xF, new ExifTag(0xF, "GPSTrack", "Direction of movement"));
  714.         this.Add(0x11, new ExifTag(0x11, "GPSImgDirection", "Direction of image"));
  715.         this.Add(0x14, new ExifTag(0x14, "GPSDestLatitude", "Latitude of destination"));
  716.         this.Add(0x16, new ExifTag(0x16, "GPSDestLongitude", "Longitude of destination"));
  717.         this.Add(0x18, new ExifTag(0x18, "GPSDestBearing", "Bearing of destination"));
  718.         this.Add(0x1A, new ExifTag(0x1A, "GPSDestDistance", "Distance to destination"));
  719.         this.Add(0x132, new ExifTag(0x132, "DateTime", "File change date and time"));
  720.         this.Add(0x10E, new ExifTag(0x10E, "ImageDescription", "Image title"));
  721.         this.Add(0x10F, new ExifTag(0x10F, "Make", "Image input equipment manufacturer"));
  722.         this.Add(0x110, new ExifTag(0x110, "Model", "Image input equipment model"));
  723.         this.Add(0x131, new ExifTag(0x131, "Software", "Software used"));
  724.         this.Add(0x13B, new ExifTag(0x13B, "Artist", "Person who created the image"));
  725.         this.Add(0x8298, new ExifTag(0x8298, "Copyright", "Copyright holder"));
  726.         this.Add(0xA004, new ExifTag(0xA004, "RelatedSoundFile", "Related audio file"));
  727.         this.Add(0x9003, new ExifTag(0x9003, "DateTimeOriginal", "Date and time of original data generation"));
  728.         this.Add(0x9004, new ExifTag(0x9004, "DateTimeDigitized", "Date and time of digital data generation"));
  729.         this.Add(0x9290, new ExifTag(0x9290, "SubSecTime", "DateTime subseconds"));
  730.         this.Add(0x9291, new ExifTag(0x9291, "SubSecTimeOriginal", "DateTimeOriginal subseconds"));
  731.         this.Add(0x9292, new ExifTag(0x9292, "SubSecTimeDigitized", "DateTimeDigitized subseconds"));
  732.         this.Add(0xA420, new ExifTag(0xA420, "ImageUniqueID", "Unique image ID"));
  733.         this.Add(0x8824, new ExifTag(0x8824, "SpectralSensitivity", "Spectral sensitivity"));
  734.         this.Add(0x1, new ExifTag(0x1, "GPSLatitudeRef", "North or South Latitude"));
  735.         this.Add(0x3, new ExifTag(0x3, "GPSLongitudeRef", "East or West Longitude"));
  736.         this.Add(0x8, new ExifTag(0x8, "GPSSatellites", "GPS satellites used for measurement"));
  737.         this.Add(0x9, new ExifTag(0x9, "GPSStatus", "GPS receiver status"));
  738.         this.Add(0xA, new ExifTag(0xA, "GPSMeasureMode", "GPS measurement mode"));
  739.         this.Add(0xC, new ExifTag(0xC, "GPSSpeedRef", "Speed unit"));
  740.         this.Add(0xE, new ExifTag(0xE, "GPSTrackRef", "Reference for direction of movement"));
  741.         this.Add(0x10, new ExifTag(0x10, "GPSImgDirectionRef", "Reference for direction of image"));
  742.         this.Add(0x12, new ExifTag(0x12, "GPSMapDatum", "Geodetic survey data used"));
  743.         this.Add(0x13, new ExifTag(0x13, "GPSDestLatitudeRef", "Reference for latitude of destination"));
  744.         this.Add(0x15, new ExifTag(0x15, "GPSDestLongitudeRef", "Reference for longitude of destination"));
  745.         this.Add(0x17, new ExifTag(0x17, "GPSDestBearingRef", "Reference for bearing of destination"));
  746.         this.Add(0x19, new ExifTag(0x19, "GPSDestDistanceRef", "Reference for distance to destination"));
  747.         this.Add(0x1D, new ExifTag(0x1D, "GPSDateStamp", "GPS date"));
  748.         this.Add(0x8828, new ExifTag(0x8828, "OECF", "Optoelectric conversion factor"));
  749.         this.Add(0xA20C, new ExifTag(0xA20C, "SpatialFrequencyResponse", "Spatial frequency response"));
  750.         this.Add(0xA300, new ExifTag(0xA300, "FileSource", "File source"));
  751.         this.Add(0xA301, new ExifTag(0xA301, "SceneType", "Scene type"));
  752.         this.Add(0xA302, new ExifTag(0xA302, "CFAPattern", "CFA pattern"));
  753.         this.Add(0xA40B, new ExifTag(0xA40B, "DeviceSettingDescription", "Device settings description"));
  754.         this.Add(0x9000, new ExifTag(0x9000, "ExifVersion", "Exif version"));
  755.         this.Add(0xA000, new ExifTag(0xA000, "FlashpixVersion", "Supported Flashpix version"));
  756.         this.Add(0x9101, new ExifTag(0x9101, "ComponentsConfiguration", "Meaning of each component"));
  757.         this.Add(0x927C, new ExifTag(0x927C, "MakerNote", "Manufacturer notes"));
  758.         this.Add(0x9286, new ExifTag(0x9286, "UserComment", "User comments"));
  759.         this.Add(0x1B, new ExifTag(0x1B, "GPSProcessingMethod", "Name of GPS processing method"));
  760.         this.Add(0x1C, new ExifTag(0x1C, "GPSAreaInformation", "Name of GPS area"));
  761.     }
  762. }
  763.  
  764. public sealed class ExifTag
  765. {
  766.     private int _id;
  767.     private string _description;
  768.     private string _fieldName;
  769.     private string _value;
  770.  
  771.     public int Id
  772.     {
  773.         get
  774.         {
  775.             return _id;
  776.         }
  777.     }
  778.     public string Description
  779.     {
  780.         get
  781.         {
  782.             return _description;
  783.         }
  784.     }
  785.     public string FieldName
  786.     {
  787.         get
  788.         {
  789.             return _fieldName;
  790.         }
  791.     }
  792.     public string Value
  793.     {
  794.         get
  795.         {
  796.             return _value;
  797.         }
  798.         set
  799.         {
  800.             this._value = value;
  801.         }
  802.     }
  803.  
  804.     public ExifTag(int id, string fieldName, string description)
  805.     {
  806.         this._id = id;
  807.         this._description = description;
  808.         this._fieldName = fieldName;
  809.     }
  810.  
  811.     public override string ToString()
  812.     {
  813.         return string.Format("{0} ({1}) = {2}", Description, FieldName, Value);
  814.     }
  815.  
  816. }
  817.  
  818. internal sealed class Rational
  819. {
  820.     private Int32 _num;
  821.     private Int32 _denom;
  822.  
  823.     public Rational(byte[] bytes)
  824.     {
  825.         byte[] n = new byte[4];
  826.         byte[] d = new byte[4];
  827.         Array.Copy(bytes, 0, n, 0, 4);
  828.         Array.Copy(bytes, 4, d, 0, 4);
  829.         _num = BitConverter.ToInt32(n, 0);
  830.         _denom = BitConverter.ToInt32(d, 0);
  831.     }
  832.  
  833.     public double ToDouble()
  834.     {
  835.         return Math.Round(Convert.ToDouble(_num) / Convert.ToDouble(_denom), 2);
  836.     }
  837.  
  838.     public string ToString(string separator)
  839.     {
  840.         return _num.ToString() + separator + _denom.ToString();
  841.     }
  842.  
  843.     public override string ToString()
  844.     {
  845.         return this.ToString("/");
  846.     }
  847. }
  848.  
  849. internal sealed class URational
  850. {
  851.     private UInt32 _num;
  852.     private UInt32 _denom;
  853.  
  854.     public URational(byte[] bytes)
  855.     {
  856.         byte[] n = new byte[4];
  857.         byte[] d = new byte[4];
  858.         Array.Copy(bytes, 0, n, 0, 4);
  859.         Array.Copy(bytes, 4, d, 0, 4);
  860.         _num = BitConverter.ToUInt32(n, 0);
  861.         _denom = BitConverter.ToUInt32(d, 0);
  862.     }
  863.  
  864.     public double ToDouble()
  865.     {
  866.         return Math.Round(Convert.ToDouble(_num) / Convert.ToDouble(_denom), 2);
  867.     }
  868.  
  869.     public override string ToString()
  870.     {
  871.         return this.ToString("/");
  872.     }
  873.  
  874.     public string ToString(string separator)
  875.     {
  876.         return _num.ToString() + separator + _denom.ToString();
  877.     }
  878. }
  879.  
  880. internal sealed class GPSRational
  881. {
  882.     private Rational _hours;
  883.     private Rational _minutes;
  884.     private Rational _seconds;
  885.  
  886.     public Rational Hours
  887.     {
  888.         get
  889.         {
  890.             return _hours;
  891.         }
  892.         set
  893.         {
  894.             _hours = value;
  895.         }
  896.     }
  897.     public Rational Minutes
  898.     {
  899.         get
  900.         {
  901.             return _minutes;
  902.         }
  903.         set
  904.         {
  905.             _minutes = value;
  906.         }
  907.     }
  908.     public Rational Seconds
  909.     {
  910.         get
  911.         {
  912.             return _seconds;
  913.         }
  914.         set
  915.         {
  916.             _seconds = value;
  917.         }
  918.     }
  919.  
  920.     public GPSRational(byte[] bytes)
  921.     {
  922.         byte[] h = new byte[8]; byte[] m = new byte[8]; byte[] s = new byte[8];
  923.  
  924.         Array.Copy(bytes, 0, h, 0, 8); Array.Copy(bytes, 8, m, 0, 8); Array.Copy(bytes, 16, s, 0, 8);
  925.  
  926.         _hours = new Rational(h);
  927.         _minutes = new Rational(m);
  928.         _seconds = new Rational(s);
  929.     }
  930.  
  931.     public override string ToString()
  932.     {
  933.         return _hours.ToDouble() + "° "
  934.             + _minutes.ToDouble() + "\' "
  935.             + _seconds.ToDouble() + "\"";
  936.     }
  937.  
  938.     public string ToString(string separator)
  939.     {
  940.         return _hours.ToDouble() + separator
  941.             + _minutes.ToDouble() + separator +
  942.             _seconds.ToDouble();
  943.     }
  944. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement