public XimgGPSRational(byte[] bytes)
        {
            byte[] h = new byte[8]; byte[] m = new byte[8]; byte[] s = new byte[8];

            Array.Copy(bytes, 0, h, 0, 8); Array.Copy(bytes, 8, m, 0, 8); Array.Copy(bytes, 16, s, 0, 8);

            _hours   = new XimgRational(h);
            _minutes = new XimgRational(m);
            _seconds = new XimgRational(s);
            _degrees = _hours.ToDouble() + (_minutes.ToDouble() / 60) + (_seconds.ToDouble() / 3600);
        }
        public XimgParse(System.Drawing.Image image)
        {
            Encoding ascii = Encoding.ASCII;

            _parseTags = new Dictionary <int, XimgTag>();
            foreach (System.Drawing.Imaging.PropertyItem pitem in image.PropertyItems)
            {
                if (!ParseTags.ContainsKey(pitem.Id))
                {
                    continue;
                }
                XimgTag xTag     = ParseTags[pitem.Id].Clone();
                string  strValue = "";
                object  value    = null;
                switch (pitem.Type)
                {
                case 0x1:
                {
                    #region BYTE (8-bit unsigned int)
                    value = pitem.Value[0];
                    if (pitem.Value.Length == 4)
                    {
                        strValue = "Version " + pitem.Value[0].ToString() + "." + pitem.Value[1].ToString();
                    }
                    else if (pitem.Id == 0x5 && pitem.Value[0] == 0)
                    {
                        strValue = "Sea level";
                    }
                    else
                    {
                        strValue = pitem.Value[0].ToString();
                    }
                    #endregion
                }
                break;

                case 0x2:
                {
                    #region ASCII (8 bit ASCII code)

                    strValue = ascii.GetString(pitem.Value).Trim('\0');
                    value    = strValue;
                    if (pitem.Id == 0x1 || pitem.Id == 0x13)
                    {
                        if (strValue == "N")
                        {
                            strValue = "North latitude";
                        }
                        else if (strValue == "S")
                        {
                            strValue = "South latitude";
                        }
                        else
                        {
                            strValue = "n/a";
                        }
                    }

                    if (pitem.Id == 0x3 || pitem.Id == 0x15)
                    {
                        if (strValue == "E")
                        {
                            strValue = "East longitude";
                        }
                        else if (strValue == "W")
                        {
                            strValue = "West longitude";
                        }
                        else
                        {
                            strValue = "n/a";
                        }
                    }

                    if (pitem.Id == 0x9)
                    {
                        if (strValue == "A")
                        {
                            strValue = "Measurement in progress";
                        }
                        else if (strValue == "V")
                        {
                            strValue = "Measurement Interoperability";
                        }
                        else
                        {
                            strValue = "n/a";
                        }
                    }

                    if (pitem.Id == 0xA)
                    {
                        if (strValue == "2")
                        {
                            strValue = "2-dimensional measurement";
                        }
                        else if (strValue == "3")
                        {
                            strValue = "3-dimensional measurement";
                        }
                        else
                        {
                            strValue = "n/a";
                        }
                    }

                    if (pitem.Id == 0xC || pitem.Id == 0x19)
                    {
                        if (strValue == "K")
                        {
                            strValue = "Kilometers per hour";
                        }
                        else if (strValue == "M")
                        {
                            strValue = "Miles per hour";
                        }
                        else if (strValue == "N")
                        {
                            strValue = "Knots";
                        }
                        else
                        {
                            strValue = "n/a";
                        }
                    }

                    if (pitem.Id == 0xE || pitem.Id == 0x10 || pitem.Id == 0x17)
                    {
                        if (strValue == "T")
                        {
                            strValue = "True direction";
                        }
                        else if (strValue == "M")
                        {
                            strValue = "Magnetic direction";
                        }
                        else
                        {
                            strValue = "n/a";
                        }
                    }
                    #endregion
                }
                break;

                case 0x3:
                {
                    #region 3 = SHORT (16-bit unsigned int)
                    UInt16 uintval = BitConverter.ToUInt16(pitem.Value, 0);
                    value = uintval;

                    // orientation // lookup table
                    switch (pitem.Id)
                    {
                    case 0x8827:             // ISO speed rating
                        strValue = "ISO-" + uintval.ToString();
                        break;

                    case 0xA217:             // sensing method
                    {
                        switch (uintval)
                        {
                        case 1: strValue = "Not defined"; break;

                        case 2: strValue = "One-chip color area sensor"; break;

                        case 3: strValue = "Two-chip color area sensor"; break;

                        case 4: strValue = "Three-chip color area sensor"; break;

                        case 5: strValue = "Color sequential area sensor"; break;

                        case 7: strValue = "Trilinear sensor"; break;

                        case 8: strValue = "Color sequential linear sensor"; break;

                        default: strValue = " reserved"; break;
                        }
                    }
                    break;

                    case 0x8822:             // Exposure program
                        switch (uintval)
                        {
                        case 0: strValue = "Not defined"; break;

                        case 1: strValue = "Manual"; break;

                        case 2: strValue = "Normal program"; break;

                        case 3: strValue = "Aperture priority"; break;

                        case 4: strValue = "Shutter priority"; break;

                        case 5: strValue = "Creative program (biased toward depth of field)"; break;

                        case 6: strValue = "Action program (biased toward fast shutter speed)"; break;

                        case 7: strValue = "Portrait mode (for closeup photos with the background out of focus)"; break;

                        case 8: strValue = "Landscape mode (for landscape photos with the background in focus)"; break;

                        default: strValue = "n/a"; break;
                        }
                        break;

                    case 0x9207:             // metering mode
                        switch (uintval)
                        {
                        case 0: strValue = "unknown"; break;

                        case 1: strValue = "Average"; break;

                        case 2: strValue = "Center Weighted Average"; break;

                        case 3: strValue = "Spot"; break;

                        case 4: strValue = "MultiSpot"; break;

                        case 5: strValue = "Pattern"; break;

                        case 6: strValue = "Partial"; break;

                        case 255: strValue = "Other"; break;

                        default: strValue = "n/a"; break;
                        }
                        break;

                    case 0x9208:             // Light source
                    {
                        switch (uintval)
                        {
                        case 0: strValue = "unknown"; break;

                        case 1: strValue = "Daylight"; break;

                        case 2: strValue = "Fluorescent"; break;

                        case 3: strValue = "Tungsten (incandescent light)"; break;

                        case 4: strValue = "Flash"; break;

                        case 9: strValue = "Fine weather"; break;

                        case 10: strValue = "Cloudy weather"; break;

                        case 11: strValue = "Shade"; break;

                        case 12: strValue = "Daylight fluorescent (D 5700 – 7100K)"; break;

                        case 13: strValue = "Day white fluorescent (N 4600 – 5400K)"; break;

                        case 14: strValue = "Cool white fluorescent (W 3900 – 4500K)"; break;

                        case 15: strValue = "White fluorescent (WW 3200 – 3700K)"; break;

                        case 17: strValue = "Standard light A"; break;

                        case 18: strValue = "Standard light B"; break;

                        case 19: strValue = "Standard light C"; break;

                        case 20: strValue = "D55"; break;

                        case 21: strValue = "D65"; break;

                        case 22: strValue = "D75"; break;

                        case 23: strValue = "D50"; break;

                        case 24: strValue = "ISO studio tungsten"; break;

                        case 255: strValue = "ISO studio tungsten"; break;

                        default: strValue = "other light source"; break;
                        }
                    }
                    break;

                    case 0x9209:             // Flash
                    {
                        switch (uintval)
                        {
                        case 0x0: strValue = "Flash did not fire"; break;

                        case 0x1: strValue = "Flash fired"; break;

                        case 0x5: strValue = "Strobe return light not detected"; break;

                        case 0x7: strValue = "Strobe return light detected"; break;

                        case 0x9: strValue = "Flash fired, compulsory flash mode"; break;

                        case 0xD: strValue = "Flash fired, compulsory flash mode, return light not detected"; break;

                        case 0xF: strValue = "Flash fired, compulsory flash mode, return light detected"; break;

                        case 0x10: strValue = "Flash did not fire, compulsory flash mode"; break;

                        case 0x18: strValue = "Flash did not fire, auto mode"; break;

                        case 0x19: strValue = "Flash fired, auto mode"; break;

                        case 0x1D: strValue = "Flash fired, auto mode, return light not detected"; break;

                        case 0x1F: strValue = "Flash fired, auto mode, return light detected"; break;

                        case 0x20: strValue = "No flash function"; break;

                        case 0x41: strValue = "Flash fired, red-eye reduction mode"; break;

                        case 0x45: strValue = "Flash fired, red-eye reduction mode, return light not detected"; break;

                        case 0x47: strValue = "Flash fired, red-eye reduction mode, return light detected"; break;

                        case 0x49: strValue = "Flash fired, compulsory flash mode, red-eye reduction mode"; break;

                        case 0x4D: strValue = "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected"; break;

                        case 0x4F: strValue = "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected"; break;

                        case 0x59: strValue = "Flash fired, auto mode, red-eye reduction mode"; break;

                        case 0x5D: strValue = "Flash fired, auto mode, return light not detected, red-eye reduction mode"; break;

                        case 0x5F: strValue = "Flash fired, auto mode, return light detected, red-eye reduction mode"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0x0128:             //ResolutionUnit
                    {
                        switch (uintval)
                        {
                        case 2: strValue = "Inch"; break;

                        case 3: strValue = "Centimeter"; break;

                        default: strValue = "No Unit"; break;
                        }
                    }
                    break;

                    case 0xA409:             // Saturation
                    {
                        switch (uintval)
                        {
                        case 0: strValue = "Normal"; break;

                        case 1: strValue = "Low saturation"; break;

                        case 2: strValue = "High saturation"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0xA40A:             // Sharpness
                    {
                        switch (uintval)
                        {
                        case 0: strValue = "Normal"; break;

                        case 1: strValue = "Soft"; break;

                        case 2: strValue = "Hard"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0xA408:             // Contrast
                    {
                        switch (uintval)
                        {
                        case 0: strValue = "Normal"; break;

                        case 1: strValue = "Soft"; break;

                        case 2: strValue = "Hard"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0x103:             // Compression
                    {
                        switch (uintval)
                        {
                        case 1: strValue = "Uncompressed"; break;

                        case 6: strValue = "JPEG compression (thumbnails only)"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0x106:             // PhotometricInterpretation
                    {
                        switch (uintval)
                        {
                        case 2: strValue = "RGB"; break;

                        case 6: strValue = "YCbCr"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0x112:             // Orientation
                    {
                        switch (uintval)
                        {
                        case 1: strValue = "The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side."; break;

                        case 2: strValue = "The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side."; break;

                        case 3: strValue = "The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side."; break;

                        case 4: strValue = "The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side."; break;

                        case 5: strValue = "The 0th row is the visual left-hand side of the image, and the 0th column is the visual top."; break;

                        case 6: strValue = "The 0th row is the visual right-hand side of the image, and the 0th column is the visual top."; break;

                        case 7: strValue = "The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom."; break;

                        case 8: strValue = "The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom."; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0x213:             // YCbCrPositioning
                    {
                        switch (uintval)
                        {
                        case 1: strValue = "centered"; break;

                        case 6: strValue = "co-sited"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0xA001:             // ColorSpace
                    {
                        switch (uintval)
                        {
                        case 1: strValue = "sRGB"; break;

                        case 0xFFFF: strValue = "Uncalibrated"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0xA401:             // CustomRendered
                    {
                        switch (uintval)
                        {
                        case 0: strValue = "Normal process"; break;

                        case 1: strValue = "Custom process"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0xA402:             // ExposureMode
                    {
                        switch (uintval)
                        {
                        case 0: strValue = "Auto exposure"; break;

                        case 1: strValue = "Manual exposure"; break;

                        case 2: strValue = "Auto bracket"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0xA403:             // WhiteBalance
                    {
                        switch (uintval)
                        {
                        case 0: strValue = "Auto white balance"; break;

                        case 1: strValue = "Manual white balance"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0xA406:             // SceneCaptureType
                    {
                        switch (uintval)
                        {
                        case 0: strValue = "Standard"; break;

                        case 1: strValue = "Landscape"; break;

                        case 2: strValue = "Portrait"; break;

                        case 3: strValue = "Night scene"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0xA40C:             // SubjectDistanceRange
                    {
                        switch (uintval)
                        {
                        case 0: strValue = "unknown"; break;

                        case 1: strValue = "Macro"; break;

                        case 2: strValue = "Close view"; break;

                        case 3: strValue = "Distant view"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0x1E:             // GPSDifferential
                    {
                        switch (uintval)
                        {
                        case 0: strValue = "Measurement without differential correction"; break;

                        case 1: strValue = "Differential correction applied"; break;

                        default: strValue = "n/a"; break;
                        }
                    }
                    break;

                    case 0xA405:             // FocalLengthIn35mmFilm
                        strValue = uintval.ToString() + " mm";
                        break;

                    default:            //
                        strValue = uintval.ToString();
                        break;
                    }
                    #endregion
                }
                break;

                case 0x4:
                {
                    #region 4 = LONG (32-bit unsigned int)
                    value    = BitConverter.ToUInt32(pitem.Value, 0);
                    strValue = value.ToString();
                    #endregion
                }
                break;

                case 0x5:
                {
                    #region 5 = RATIONAL (Two LONGs, unsigned)

                    XimgURational rat = new XimgURational(pitem.Value);
                    value = rat;
                    switch (pitem.Id)
                    {
                    case 0x9202:             // ApertureValue
                        strValue = "F/" + Math.Round(Math.Pow(Math.Sqrt(2), rat.ToDouble()), 2).ToString();
                        break;

                    case 0x9205:             // MaxApertureValue
                        strValue = "F/" + Math.Round(Math.Pow(Math.Sqrt(2), rat.ToDouble()), 2).ToString();
                        break;

                    case 0x920A:             // FocalLength
                        strValue = rat.ToDouble().ToString() + " mm";
                        break;

                    case 0x829D:             // F-number
                        strValue = "F/" + rat.ToDouble().ToString();
                        break;

                    case 0x11A:             // Xresolution
                        strValue = rat.ToDouble().ToString();
                        break;

                    case 0x11B:             // Yresolution
                        strValue = rat.ToDouble().ToString();
                        break;

                    case 0x829A:             // ExposureTime
                        strValue = rat.ToString() + " sec";
                        break;

                    case 0x2:             // GPSLatitude
                        value    = new XimgGPSRational(pitem.Value);
                        strValue = value.ToString();
                        break;

                    case 0x4:             // GPSLongitude
                        value    = new XimgGPSRational(pitem.Value);
                        strValue = value.ToString();
                        break;

                    case 0x6:             // GPSAltitude
                        strValue = rat.ToDouble() + " meters";
                        break;

                    case 0xA404:             // Digital Zoom Ratio
                        strValue = rat.ToDouble().ToString();
                        if (strValue == "0")
                        {
                            strValue = "none";
                        }
                        break;

                    case 0xB:             // GPSDOP
                        strValue = rat.ToDouble().ToString();
                        break;

                    case 0xD:             // GPSSpeed
                        strValue = rat.ToDouble().ToString();
                        break;

                    case 0xF:             // GPSTrack
                        strValue = rat.ToDouble().ToString();
                        break;

                    case 0x11:             // GPSImgDir
                        strValue = rat.ToDouble().ToString();
                        break;

                    case 0x14:             // GPSDestLatitude
                        value    = new XimgGPSRational(pitem.Value);
                        strValue = value.ToString();
                        break;

                    case 0x16:             // GPSDestLongitude
                        value    = new XimgGPSRational(pitem.Value);
                        strValue = value.ToString();
                        break;

                    case 0x18:             // GPSDestBearing
                        strValue = rat.ToDouble().ToString();
                        break;

                    case 0x1A:             // GPSDestDistance
                        strValue = rat.ToDouble().ToString();
                        break;

                    case 0x7:             // GPSTimeStamp
                        value    = new XimgGPSRational(pitem.Value);
                        strValue = (value as XimgGPSRational).ToString(":");
                        break;

                    default:
                        strValue = rat.ToString();
                        break;
                    }

                    #endregion
                }
                break;

                case 0x7:
                {
                    #region UNDEFINED (8-bit)
                    value = pitem.Value[0];
                    switch (pitem.Id)
                    {
                    case 0xA300:             //FileSource
                    {
                        if (pitem.Value[0] == 3)
                        {
                            strValue = "DSC";
                        }
                        else
                        {
                            strValue = "n/a";
                        }
                        break;
                    }

                    case 0xA301:             //SceneType
                        if (pitem.Value[0] == 1)
                        {
                            strValue = "A directly photographed image";
                        }
                        else
                        {
                            strValue = "n/a";
                        }
                        break;

                    case 0x9000:            // Exif Version
                        strValue = ascii.GetString(pitem.Value).Trim('\0');
                        break;

                    case 0xA000:             // Flashpix Version
                        strValue = ascii.GetString(pitem.Value).Trim('\0');
                        if (strValue == "0100")
                        {
                            strValue = "Flashpix Format Version 1.0";
                        }
                        else
                        {
                            strValue = "n/a";
                        }
                        break;

                    case 0x9101:             //ComponentsConfiguration
                        strValue = GetComponentsConfig(pitem.Value);
                        break;

                    case 0x927C:             //MakerNote
                        strValue = ascii.GetString(pitem.Value).Trim('\0');
                        break;

                    case 0x9286:             //UserComment
                        strValue = ascii.GetString(pitem.Value).Trim('\0');
                        break;

                    case 0x1B:             //GPS Processing Method
                        strValue = ascii.GetString(pitem.Value).Trim('\0');
                        break;

                    case 0x1C:             //GPS Area Info
                        strValue = ascii.GetString(pitem.Value).Trim('\0');
                        break;

                    default:
                        strValue = "-";
                        break;
                    }
                    #endregion
                }
                break;

                case 0x9:
                {
                    #region 9 = SLONG (32-bit int)
                    value    = BitConverter.ToInt32(pitem.Value, 0);
                    strValue = value.ToString();
                    #endregion
                }
                break;

                case 0xA:
                {
                    #region 10 = SRATIONAL (Two SLONGs, signed)

                    XimgRational rat = new XimgRational(pitem.Value);
                    value = rat;
                    switch (pitem.Id)
                    {
                    case 0x9201:             // ShutterSpeedValue
                        strValue = "1/" + Math.Round(Math.Pow(2, rat.ToDouble()), 2).ToString();
                        break;

                    case 0x9203:             // BrightnessValue
                        strValue = Math.Round(rat.ToDouble(), 4).ToString();
                        break;

                    case 0x9204:             // ExposureBiasValue
                        strValue = Math.Round(rat.ToDouble(), 2).ToString() + " eV";
                        break;

                    default:
                        strValue = rat.ToString();
                        break;
                    }
                    #endregion
                }
                break;
                }
                xTag.Value    = value;
                xTag.StrValue = strValue;
                xTag.ItemType = pitem.Type;
                _parseTags.Add(xTag.Id, xTag);
            }
        }