private void ExifGpsView_Format(object sender, ConvertEventArgs e) { GpsCoordinate c = e.Value as GpsCoordinate; if (c != null) { e.Value = c.ToString(); } else { e.Value = ""; } }
/// <summary> /// /// </summary> /// <returns></returns> /// <remarks> /// References: /// http://www.media.mit.edu/pia/Research/deepview/exif.html /// http://en.wikipedia.org/wiki/APEX_system /// http://en.wikipedia.org/wiki/Exposure_value /// </remarks> protected string FormatValue() { object rawValue = this.Value; switch (this.Tag) { case ExifTag.ISOSpeed: { if (rawValue is Array) { Array array = (Array)rawValue; if (array.Length < 1 || !(array.GetValue(0) is IConvertible)) { goto default; } rawValue = array.GetValue(0); } if (!(rawValue is IConvertible)) { goto default; } return(String.Format("ISO-{0:###0}", Convert.ToDecimal(rawValue))); } case ExifTag.Aperture: case ExifTag.MaxAperture: { // The actual aperture value of lens when the image was taken. // To convert this value to ordinary F-number(F-stop), // calculate this value's power of root 2 (=1.4142). // For example, if value is '5', F-number is 1.4142^5 = F5.6. double fStop = Math.Pow(2.0, Convert.ToDouble(rawValue) / 2.0); return(String.Format("f/{0:#0.0}", fStop)); } case ExifTag.FNumber: { // The actual F-number (F-stop) of lens when the image was taken. return(String.Format("f/{0:#0.0}", Convert.ToDecimal(rawValue))); } case ExifTag.FocalLength: case ExifTag.FocalLengthIn35mmFilm: { return(String.Format("{0:#0.#} mm", Convert.ToDecimal(rawValue))); } case ExifTag.ShutterSpeed: { if (!(rawValue is Rational <int>)) { goto default; } // To convert this value to ordinary 'Shutter Speed'; // calculate this value's power of 2, then reciprocal. // For example, if value is '4', shutter speed is 1/(2^4)=1/16 second. Rational <int> shutter = (Rational <int>)rawValue; if (shutter.Numerator > 0) { double speed = Math.Pow(2.0, Convert.ToDouble(shutter)); return(String.Format("1/{0:####0} sec", speed)); } else { double speed = Math.Pow(2.0, -Convert.ToDouble(shutter)); return(String.Format("{0:####0.##} sec", speed)); } } case ExifTag.ExposureTime: { if (!(rawValue is Rational <uint>)) { goto default; } // Exposure time (reciprocal of shutter speed). Unit is second. Rational <uint> exposure = (Rational <uint>)rawValue; if (exposure.Numerator < exposure.Denominator) { exposure.Reduce(); return(String.Format("{0} sec", exposure)); } else { return(String.Format("{0:####0.##} sec", Convert.ToDecimal(rawValue))); } } case ExifTag.XResolution: case ExifTag.YResolution: case ExifTag.ThumbnailXResolution: case ExifTag.ThumbnailYResolution: case ExifTag.FocalPlaneXResolution: case ExifTag.FocalPlaneYResolution: { return(String.Format("{0:###0} dpi", Convert.ToDecimal(rawValue))); } case ExifTag.ImageHeight: case ExifTag.ImageWidth: case ExifTag.CompressedImageHeight: case ExifTag.CompressedImageWidth: case ExifTag.ThumbnailHeight: case ExifTag.ThumbnailWidth: { return(String.Format("{0:###0} pixels", Convert.ToDecimal(rawValue))); } case ExifTag.SubjectDistance: { return(String.Format("{0:###0.#} m", Convert.ToDecimal(rawValue))); } case ExifTag.ExposureBias: case ExifTag.Brightness: { string val; if (rawValue is Rational <int> ) { val = ((Rational <int>)rawValue).Numerator != 0 ? rawValue.ToString() : "0"; } else { val = Convert.ToDecimal(rawValue).ToString(); } return(String.Format("{0} EV", val)); } case ExifTag.CompressedBitsPerPixel: { return(String.Format("{0:###0.0} bits", Convert.ToDecimal(rawValue))); } case ExifTag.DigitalZoomRatio: { return(Convert.ToString(rawValue).Replace('/', ':')); } case ExifTag.GpsLatitude: case ExifTag.GpsLongitude: case ExifTag.GpsDestLatitude: case ExifTag.GpsDestLongitude: { if (!(rawValue is Array)) { goto default; } Array array = (Array)rawValue; if (array.Length < 1) { return(String.Empty); } else if (array.Length != 3) { goto default; } // attempt to use the GPSCoordinate XMP formatting guidelines GpsCoordinate gps = new GpsCoordinate(); if (array.GetValue(0) is Rational <uint> ) { gps.Degrees = (Rational <uint>)array.GetValue(0); } else { gps.SetDegrees(Convert.ToDecimal(array.GetValue(0))); } if (array.GetValue(1) is Rational <uint> ) { gps.Minutes = (Rational <uint>)array.GetValue(1); } else { gps.SetMinutes(Convert.ToDecimal(array.GetValue(1))); } if (array.GetValue(2) is Rational <uint> ) { gps.Seconds = (Rational <uint>)array.GetValue(2); } else { gps.SetSeconds(Convert.ToDecimal(array.GetValue(2))); } return(gps.ToString()); } case ExifTag.GpsTimeStamp: { Array array = (Array)rawValue; if (array.Length < 1) { return(String.Empty); } string[] time = new string[array.Length]; for (int i = 0; i < array.Length; i++) { time[i] = Convert.ToDecimal(array.GetValue(i)).ToString(); } return(String.Join(":", time)); } default: { if (rawValue is Enum) { string description = Utility.GetDescription((Enum)rawValue); if (!String.IsNullOrEmpty(description)) { return(description); } } else if (rawValue is Array) { Array array = (Array)rawValue; if (array.Length < 1) { return(String.Empty); } Type type = array.GetValue(0).GetType(); if (!type.IsPrimitive || type == typeof(char) || type == typeof(float) || type == typeof(double)) { return(Convert.ToString(rawValue)); } //const int ElemsPerRow = 40; int charSize = 2 * System.Runtime.InteropServices.Marshal.SizeOf(type); string format = "{0:X" + (charSize) + "}"; StringBuilder builder = new StringBuilder(((charSize + 1) * array.Length) /*+(2*array.Length/ElemsPerRow)*/); for (int i = 0; i < array.Length; i++) { if (i > 0) { //if ((i+1)%ElemsPerRow == 0) //{ // builder.AppendLine(); //} //else { builder.Append(" "); } } builder.AppendFormat(format, array.GetValue(i)); } return(builder.ToString()); } return(Convert.ToString(rawValue)); } } }
/// <summary> /// Consolidates EXIF GPS values into XMP style /// </summary> /// <param name="gps"></param> /// <param name="priority"></param> /// <returns></returns> private IEnumerable <XmpProperty> ProcessGps(IEnumerable <XmpProperty> gps, decimal priority) { GpsCoordinate latitude = null, longitude = null, destLatitude = null, destLongitude = null; string latitudeRef = null, longitudeRef = null, destLatitudeRef = null, destLongitudeRef = null; foreach (XmpProperty property in gps) { if (!(property.Schema is ExifSchema)) { yield return(property); continue; } switch ((ExifSchema)property.Schema) { case ExifSchema.GPSLatitude: { GpsCoordinate.TryParse(Convert.ToString(property.Value), out latitude); break; } case ExifSchema.GPSLatitudeRef: { latitudeRef = Convert.ToString(property.Value); break; } case ExifSchema.GPSLongitude: { GpsCoordinate.TryParse(Convert.ToString(property.Value), out longitude); break; } case ExifSchema.GPSLongitudeRef: { longitudeRef = Convert.ToString(property.Value); break; } case ExifSchema.GPSDestLatitude: { GpsCoordinate.TryParse(Convert.ToString(property.Value), out destLatitude); break; } case ExifSchema.GPSDestLatitudeRef: { destLatitudeRef = Convert.ToString(property.Value); break; } case ExifSchema.GPSDestLongitude: { GpsCoordinate.TryParse(Convert.ToString(property.Value), out destLongitude); break; } case ExifSchema.GPSDestLongitudeRef: { destLongitudeRef = Convert.ToString(property.Value); break; } case ExifSchema.GPSDateStamp: case ExifSchema.GPSTimeStamp: case ExifSchema.GPSAltitude: case ExifSchema.GPSAltitudeRef: case ExifSchema.GPSDestBearing: case ExifSchema.GPSDestBearingRef: case ExifSchema.GPSDestDistance: case ExifSchema.GPSDestDistanceRef: case ExifSchema.GPSImgDirection: case ExifSchema.GPSImgDirectionRef: case ExifSchema.GPSSpeed: case ExifSchema.GPSSpeedRef: case ExifSchema.GPSTrack: case ExifSchema.GPSTrackRef: default: { // TODO: process other dual properties yield return(property); break; } } } if (latitude != null) { if (!String.IsNullOrEmpty(latitudeRef)) { latitude.Direction = latitudeRef; } yield return(new XmpProperty { Schema = ExifSchema.GPSLatitude, Value = latitude.ToString("X"), Priority = priority }); } if (longitude != null) { if (!String.IsNullOrEmpty(longitudeRef)) { longitude.Direction = longitudeRef; } yield return(new XmpProperty { Schema = ExifSchema.GPSLongitude, Value = longitude.ToString("X"), Priority = priority }); } if (destLatitude != null) { if (!String.IsNullOrEmpty(destLatitudeRef)) { destLatitude.Direction = destLatitudeRef; } yield return(new XmpProperty { Schema = ExifSchema.GPSDestLatitude, Value = destLatitude.ToString("X"), Priority = priority }); } if (destLongitude != null) { if (!String.IsNullOrEmpty(destLongitudeRef)) { destLongitude.Direction = destLongitudeRef; } yield return(new XmpProperty { Schema = ExifSchema.GPSDestLongitude, Value = destLongitude.ToString("X"), Priority = priority }); } }
/// <summary> /// Converts EXIF / TIFF values into XMP style /// </summary> /// <param name="property"></param> /// <param name="value"></param> /// <returns></returns> private object ProcessValue(XmpProperty property, object value) { if (value == null) { return(value); } if (property.ValueType is XmpBasicType) { switch ((XmpBasicType)property.ValueType) { case XmpBasicType.Date: { DateTime date; Array array = value as Array; if (array != null && array.Length == 3) { try { var seconds = 60m * (60m * Convert.ToDecimal(this.ProcessRational(property, array.GetValue(0))) + Convert.ToDecimal(this.ProcessRational(property, array.GetValue(1)))) + Convert.ToDecimal(this.ProcessRational(property, array.GetValue(2))); date = DateTime.MinValue.AddSeconds(Convert.ToDouble(seconds)); value = date.ToString(XmpDateFormat); } catch { } } else if (DateTime.TryParseExact( Convert.ToString(value), ExifDateFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeLocal, out date)) { // clean up to ISO-8601 value = date.ToString(XmpDateFormat); } break; } case XmpBasicType.LangAlt: case XmpBasicType.Text: case XmpBasicType.ProperName: { if (value is byte[]) { if (property.Schema is ExifSchema && ((ExifSchema)property.Schema) == ExifSchema.GPSVersionID) { // GPSVersionID represents version as byte[] value = String.Join(".", ((byte[])value).Select(b => b.ToString()).ToArray()); } else { value = new String(Encoding.UTF8.GetChars((byte[])value)); } value = this.TrimNullTerm((string)value); } else if (!(value is string) && value is IEnumerable) { var strList = ((IEnumerable)value).OfType <string>().Select(str => this.TrimNullTerm(str)).Where(str => !String.IsNullOrEmpty(str)); if (property.Quantity == XmpQuantity.Single) { value = strList.FirstOrDefault(); } else { value = strList; } } else if (value is string) { value = this.TrimNullTerm((string)value); } break; } } } else if (property.ValueType is ExifType) { switch ((ExifType)property.ValueType) { case ExifType.GpsCoordinate: { Array array = value as Array; if (array != null && array.Length == 3) { try { GpsCoordinate gps = new GpsCoordinate(); gps.Degrees = (Rational <uint>) this.ProcessRational(property, array.GetValue(0)); gps.Minutes = (Rational <uint>) this.ProcessRational(property, array.GetValue(1)); gps.Seconds = (Rational <uint>) this.ProcessRational(property, array.GetValue(2)); value = gps.ToString("X"); } catch { } } break; } case ExifType.Rational: { Array array = value as Array; if (array == null) { value = Convert.ToString(this.ProcessRational(property, value)); } else { string[] strArray = new string[array.Length]; for (int i = 0; i < array.Length; i++) { strArray[i] = Convert.ToString(this.ProcessRational(property, array.GetValue(i))); } value = array; } break; } case ExifType.Flash: { ExifTagFlash flash; if (value is ushort) { flash = (ExifTagFlash)value; } else if (value is string) { try { flash = (ExifTagFlash)Enum.Parse(typeof(ExifTagFlash), Convert.ToString(value)); } catch { break; } } else { break; } value = new Dictionary <string, object> { { "Fired", Convert.ToString((flash & ExifTagFlash.FlashFired) == ExifTagFlash.FlashFired) }, { "Return", (int)(flash & (ExifTagFlash.ReturnNotDetected | ExifTagFlash.ReturnDetected)) >> 1 }, { "Mode", (int)(flash & (ExifTagFlash.ModeOn | ExifTagFlash.ModeOff | ExifTagFlash.ModeAuto)) >> 3 }, { "Function", Convert.ToString((flash & ExifTagFlash.NoFlashFunction) == ExifTagFlash.NoFlashFunction) }, { "RedEyeMode", Convert.ToString((flash & ExifTagFlash.RedEyeReduction) == ExifTagFlash.RedEyeReduction) } }; break; } } } return(value); }