Index: Filters/FilterJpeg.cs =================================================================== RCS file: /cvs/gnome/beagle/Filters/FilterJpeg.cs,v retrieving revision 1.9 diff -u -B -p -r1.9 FilterJpeg.cs --- Filters/FilterJpeg.cs 17 Feb 2005 23:05:34 -0000 1.9 +++ Filters/FilterJpeg.cs 31 Mar 2005 23:34:13 -0000 @@ -51,62 +51,62 @@ namespace Beagle.Filters { string str; - str = exif.LookupString (ExifTag.UserComment); + str = exif.LookupFirstValue (ExifTag.UserComment); if (str != null && str != "") AddProperty (Beagle.Property.New ("exif:UserComment", str)); - str = exif.LookupString (ExifTag.ImageDescription); + str = exif.LookupFirstValue (ExifTag.ImageDescription); if (str != null && str != "") AddProperty (Beagle.Property.New ("exif:ImageDescription", str)); - str = exif.LookupString (ExifTag.PixelXDimension); + str = exif.LookupFirstValue (ExifTag.PixelXDimension); if (str != null && str != "") AddProperty (Beagle.Property.NewKeyword ("exif:PixelXDimension", str)); - str = exif.LookupString (ExifTag.PixelYDimension); + str = exif.LookupFirstValue (ExifTag.PixelYDimension); if (str != null && str != "") AddProperty (Beagle.Property.NewKeyword ("exif:PixelYDimension", str)); - str = exif.LookupString (ExifTag.ISOSpeedRatings); + str = exif.LookupFirstValue (ExifTag.ISOSpeedRatings); if (str != null && str != "") AddProperty (Beagle.Property.NewKeyword ("exif:ISOSpeedRatings", str)); - str = exif.LookupString (ExifTag.ShutterSpeedValue); + str = exif.LookupFirstValue (ExifTag.ShutterSpeedValue); if (str != null && str != "") AddProperty (Beagle.Property.NewKeyword ("exif:ShutterSpeedValue", str)); - str = exif.LookupString (ExifTag.ExposureTime); + str = exif.LookupFirstValue (ExifTag.ExposureTime); if (str != null && str != "") AddProperty (Beagle.Property.NewKeyword ("exif:ExposureTime", str)); - str = exif.LookupString (ExifTag.FNumber); + str = exif.LookupFirstValue (ExifTag.FNumber); if (str != null && str != "") AddProperty (Beagle.Property.NewKeyword ("exif:FNumber", str)); - str = exif.LookupString (ExifTag.ApertureValue); + str = exif.LookupFirstValue (ExifTag.ApertureValue); if (str != null && str != "") AddProperty (Beagle.Property.NewKeyword ("exif:ApertureValue", str)); - str = exif.LookupString (ExifTag.FocalLength); + str = exif.LookupFirstValue (ExifTag.FocalLength); if (str != null && str != "") AddProperty (Beagle.Property.NewKeyword ("exif:FocalLength", str)); - str = exif.LookupString (ExifTag.Flash); + str = exif.LookupFirstValue (ExifTag.Flash); if (str != null && str != "") AddProperty (Beagle.Property.NewKeyword ("exif:Flash", str)); - str = exif.LookupString (ExifTag.Model); + str = exif.LookupFirstValue (ExifTag.Model); if (str != null && str != "") AddProperty (Beagle.Property.NewKeyword ("exif:Model", str)); - str = exif.LookupString (ExifTag.Copyright); + str = exif.LookupFirstValue (ExifTag.Copyright); if (str != null && str != "") AddProperty (Beagle.Property.New ("exif:Copyright", str)); - str = exif.LookupString (ExifTag.DateTime); + str = exif.LookupFirstValue (ExifTag.DateTime); if (str != null && str != "") { try { - DateTime dt = ExifData.DateTimeFromString (str); + DateTime dt = ExifUtil.DateTimeFromString (str); AddProperty (Beagle.Property.NewDate ("exif:DateTime", dt)); } catch (ArgumentOutOfRangeException e) { Logger.Log.Debug("EXIF DateTime '{0}' is invalid.", str); Index: Util/ExifData.cs =================================================================== RCS file: /cvs/gnome/beagle/Util/ExifData.cs,v retrieving revision 1.2 diff -u -B -p -r1.2 ExifData.cs --- Util/ExifData.cs 24 Feb 2005 16:37:54 -0000 1.2 +++ Util/ExifData.cs 31 Mar 2005 23:34:16 -0000 @@ -1,11 +1,12 @@ // -// libexif-wrapper.cs : LibExif wrapper for Mphoto to use +// Exif.cs : LibExif wrapper for FSpot // // Author: +// Larry Ewing (lewing@novell.com) // Ravi Pratap (ravi@ximian.com) // Miguel de Icaza (miguel@ximian.com) // -// (C) 2002 Ximian, Inc. +// (C) 2002, 2004, 2005 Novell, Inc. // using System; @@ -13,449 +14,889 @@ using System.Collections; using System.Runtime.InteropServices; namespace Beagle.Util { - -public enum ExifTag { - InteroperabilityIndex = 0x0001, - InteroperabilityVersion = 0x0002, - ImageWidth = 0x0100, - ImageLength = 0x0101, - BitsPersample = 0x0102, - Compression = 0x0103, - PhotometricInterpretation = 0x0106, - FillOrder = 0x010a, - DocumentName = 0x010d, - ImageDescription = 0x010e, - Make = 0x010f, - Model = 0x0110, - StripOffsets = 0x0111, - Orientation = 0x0112, - SamplesPerPixel = 0x0115, - RowsPerStrip = 0x0116, - StripByteCounts = 0x0117, - XResolution = 0x011a, - YResolution = 0x011b, - PlanarConfiguration = 0x011c, - ResolutionUnit = 0x0128, - TransferFunction = 0x012d, - Software = 0x0131, - DateTime = 0x0132, - Artist = 0x013b, - WhitePoint = 0x013e, - PrimaryChromaticities = 0x013f, - TransferRange = 0x0156, - JPEGProc = 0x0200, - JPEGInterchangeFormat = 0x0201, - JPEGInterchangeFormatLength = 0x0202, - YCBCRCoefficients = 0x0211, - YCBCRSubSampling = 0x0212, - YCBCRPositioning = 0x0213, - ReferenceBlackWhite = 0x0214, - RelatedImageFileFormat = 0x1000, - RelatedImageWidth = 0x1001, - RelatedImageLength = 0x1002, - CFARepeatPatternDim = 0x828d, - CFAPattern = 0x828e, - BatteryLevel = 0x828f, - Copyright = 0x8298, - ExposureTime = 0x829a, - FNumber = 0x829d, - IPTCNAA = 0x83bb, - IfdPointer = 0x8769, - InterColorProfile = 0x8773, - ExposureProgram = 0x8822, - SpectralSensitivity = 0x8824, - GPSInfoIfdPointer = 0x8825, - ISOSpeedRatings = 0x8827, - OECF = 0x8828, - ExifVersion = 0x9000, - DateTimeOriginal = 0x9003, - DateTimeDigitized = 0x9004, - ComponentsConfiguration = 0x9101, - CompressedBitsPerPixel = 0x9102, - ShutterSpeedValue = 0x9201, - ApertureValue = 0x9202, - BrightnessValue = 0x9203, - ExposureBiasValue = 0x9204, - MaxApertureValue = 0x9205, - SubjectDistance = 0x9206, - MeteringMode = 0x9207, - LightSource = 0x9208, - Flash = 0x9209, - FocalLength = 0x920a, - SubjectArea = 0x9214, - MakerNote = 0x927c, - UserComment = 0x9286, - SubSecTime = 0x9290, - SubSecTimeOriginal = 0x9291, - SubSecTimeDigitized = 0x9292, - FlashPixVersion = 0xa000, - ColorSpace = 0xa001, - PixelXDimension = 0xa002, - PixelYDimension = 0xa003, - RelatedSoundFile = 0xa004, - InteroperabilityIfdPointer = 0xa005, - FlashEnergy = 0xa20b, - SpatialFrequencyResponse = 0xa20c, - FocalPlaneXResolution = 0xa20e, - FocalPlaneYResolution = 0xa20f, - FocalPlaneResolutionUnit = 0xa210, - SubjectLocation = 0xa214, - ExposureIndex = 0xa215, - SensingMethod = 0xa217, - FileSource = 0xa300, - SceneType = 0xa301, - NewCFAPattern = 0xa302, - CustomRendered = 0xa401, - ExposureMode = 0xa402, - WhiteBalance = 0xa403, - DigitalZoomRatio = 0xa404, - FocalLengthIn35mmFilm = 0xa405, - SceneCaptureType = 0xa406, - GainControl = 0xa407, - Contrast = 0xa408, - Saturation = 0xa409, - Sharpness = 0xa40a, - DeviceSettingDescription = 0xa40b, - SubjectDistanceRange = 0xa40c, - ImageUniqueId = 0xa420 -} - -public enum ExifByteOrder { - Motorola, - Intel -} - -public enum ExifFormat { - Byte = 1, - Ascii = 2, - Short = 3, - Long = 4, - Rational = 5, - Undefined = 7, - Slong = 9, - SRational = 10 -} - -public enum ExifIfd { - Zero = 0, - One, - Exif, - Gps, - InterOperability, - Count -} - - -internal class ExifUtil { - - [DllImport ("libexif.so")] - static extern IntPtr exif_tag_get_name (ExifTag tag); - - [DllImport ("libexif.so")] - static extern IntPtr exif_tag_get_title (ExifTag tag); - - [DllImport ("libexif.so")] - static extern IntPtr exif_tag_get_description (ExifTag tag); - - [DllImport ("libexif.so")] - static extern IntPtr exif_byte_order_get_name (ExifByteOrder order); - - [DllImport ("libexif.so")] - static extern IntPtr exif_format_get_name (ExifFormat format); - - [DllImport ("libexif.so")] - static extern char exif_format_get_size (ExifFormat format); - - [DllImport ("libexif.so")] - static extern IntPtr exif_ifd_get_name (ExifIfd ifd); - - - public static string GetTagName (ExifTag tag) - { - - IntPtr raw_ret = exif_tag_get_name (tag); - return Marshal.PtrToStringAnsi (raw_ret); - } - - public static string GetTagTitle (ExifTag tag) - { - IntPtr raw_ret = exif_tag_get_title (tag); - return Marshal.PtrToStringAnsi (raw_ret); - } - - public static string GetTagDescription (ExifTag tag) - { - IntPtr raw_ret = exif_tag_get_description (tag); - return Marshal.PtrToStringAnsi (raw_ret); - } - - public static string GetByteOrderName (ExifByteOrder order) - { - IntPtr raw_ret = exif_byte_order_get_name (order); - return Marshal.PtrToStringAnsi (raw_ret); - } - - public static string GetFormatName (ExifFormat format) - { - IntPtr raw_ret = exif_format_get_name (format); - return Marshal.PtrToStringAnsi (raw_ret); - } - - public static char GetFormatSize (ExifFormat format) - { - return exif_format_get_size (format); - } - - public static string GetIfdName (ExifIfd ifd) - { - IntPtr raw_ret = exif_ifd_get_name (ifd); - return Marshal.PtrToStringAnsi (raw_ret); - } - -} - -[StructLayout(LayoutKind.Sequential)] -internal unsafe struct _ExifContent { - _ExifEntry *entries; - uint count; - _ExifData *parent; - - [DllImport ("libexif.so")] - internal static extern IntPtr exif_content_get_entry (_ExifContent *ptr, ExifTag tag); - - [DllImport ("libexif.so")] - internal static unsafe extern IntPtr exif_content_foreach_entry (_ExifContent *ptr, - ExifContentForeachEntryFunc func, - void *data); - - internal delegate void ExifContentForeachEntryFunc (_ExifEntry *e, void *data); -} - -[StructLayout(LayoutKind.Sequential)] -internal unsafe struct _ExifEntry { - readonly public ExifTag tag; - readonly public int format; - readonly public uint components; - readonly public byte *data; - readonly public uint size; - readonly public _ExifContent *parent; - - [DllImport ("libexif.so")] -#if HAVE_OLD_LIBEXIF - internal static extern IntPtr exif_entry_get_value (_ExifEntry *entry); -#else - internal static extern IntPtr exif_entry_get_value (_ExifEntry *entry, byte [] value, int maxlen); -#endif -} - -[StructLayout(LayoutKind.Sequential)] -internal unsafe struct _ExifData { - _ExifContent *ifd0; - _ExifContent *ifd1; - _ExifContent *ifd_exif; - _ExifContent *ifd_gps; - _ExifContent *ifd_interop; - internal IntPtr data; - internal int size; - - [DllImport ("libexif.so")] - internal static extern _ExifData *exif_data_new_from_file (string path); - - [DllImport ("libexif.so")] - internal static extern _ExifData *exif_data_new_from_data (byte [] data, uint size); - - [DllImport ("libexif.so")] - internal static extern void exif_data_ref (_ExifData *data); - - [DllImport ("libexif.so")] - internal static extern void exif_data_unref (_ExifData *data); - - [DllImport ("libexif.so")] - internal static extern void exif_data_free (_ExifData _data); - - [DllImport ("libexif.so")] - static extern void exif_data_dump (_ExifData *data); - - internal delegate void ExifDataForeachContentFunc (_ExifContent *content, void *user_data); - - [DllImport ("libexif.so")] - internal unsafe static extern void exif_data_foreach_content(_ExifData *data, ExifDataForeachContentFunc func, void *ptr); -} - -public class ExifData : IDisposable { - unsafe _ExifData *obj; - - Hashtable string_values; - Hashtable data; - ExifTag [] tags; - ArrayList tag_list; - - public ExifTag [] Tags { - get { - if (tags != null) - return tags; - else - return new ExifTag [0] {}; - } - } - - public ExifData (string filename) - { - unsafe { - obj = _ExifData.exif_data_new_from_file (filename); - } - } - - public ExifData (byte [] data, uint size) - { - unsafe { - obj = _ExifData.exif_data_new_from_data (data, size); - } - } - - public void Dispose () - { - Dispose (true); - GC.SuppressFinalize (this); - } - - ~ExifData () - { - Dispose (false); - } - - _ExifContent.ExifContentForeachEntryFunc content_func; - - unsafe void Assemble (_ExifContent *content, void *user_data) - { - _ExifContent.exif_content_foreach_entry (content, content_func, null); - } - - unsafe void AssembleContent (_ExifEntry *entry, void *callback_data) - { - tag_list.Add (entry->tag); -#if HAVE_OLD_LIBEXIF - string_values [entry->tag] = Marshal.PtrToStringAnsi (_ExifEntry.exif_entry_get_value (entry)); -#else - byte [] value = new byte [1024]; - string_values [entry->tag] = Marshal.PtrToStringAnsi (_ExifEntry.exif_entry_get_value (entry, value, value.Length)); -#endif - - byte [] raw_data; - if (entry->size > 0) { - raw_data = new byte [entry->size]; - for (int i = 0; i < entry->size; i++) - raw_data [i] = *(entry->data + i); - - } else { - //Console.WriteLine ("Zero Length EXIF tag"); - raw_data = new byte [0] {}; - } - - data [entry->tag] = raw_data; + public enum ExifTag { + InteroperabilityIndex = 0x0001, + InteroperabilityVersion = 0x0002, + ImageWidth = 0x0100, + ImageLength = 0x0101, + BitsPersample = 0x0102, + Compression = 0x0103, + PhotometricInterpretation = 0x0106, + FillOrder = 0x010a, + DocumentName = 0x010d, + ImageDescription = 0x010e, + Make = 0x010f, + Model = 0x0110, + StripOffsets = 0x0111, + Orientation = 0x0112, + SamplesPerPixel = 0x0115, + RowsPerStrip = 0x0116, + StripByteCounts = 0x0117, + XResolution = 0x011a, + YResolution = 0x011b, + PlanarConfiguration = 0x011c, + ResolutionUnit = 0x0128, + TransferFunction = 0x012d, + Software = 0x0131, + DateTime = 0x0132, + Artist = 0x013b, + WhitePoint = 0x013e, + PrimaryChromaticities = 0x013f, + TransferRange = 0x0156, + JPEGProc = 0x0200, + JPEGInterchangeFormat = 0x0201, + JPEGInterchangeFormatLength = 0x0202, + YCBCRCoefficients = 0x0211, + YCBCRSubSampling = 0x0212, + YCBCRPositioning = 0x0213, + ReferenceBlackWhite = 0x0214, + RelatedImageFileFormat = 0x1000, + RelatedImageWidth = 0x1001, + RelatedImageLength = 0x1002, + CFARepeatPatternDim = 0x828d, + CFAPattern = 0x828e, + BatteryLevel = 0x828f, + Copyright = 0x8298, + ExposureTime = 0x829a, + FNumber = 0x829d, + IPTCNAA = 0x83bb, + ExifIfdPointer = 0x8769, + InterColorProfile = 0x8773, + ExposureProgram = 0x8822, + SpectralSensitivity = 0x8824, + GPSInfoIfdPointer = 0x8825, + ISOSpeedRatings = 0x8827, + OECF = 0x8828, + ExifVersion = 0x9000, + DateTimeOriginal = 0x9003, + DateTimeDigitized = 0x9004, + ComponentsConfiguration = 0x9101, + CompressedBitsPerPixel = 0x9102, + ShutterSpeedValue = 0x9201, + ApertureValue = 0x9202, + BrightnessValue = 0x9203, + ExposureBiasValue = 0x9204, + MaxApertureValue = 0x9205, + SubjectDistance = 0x9206, + MeteringMode = 0x9207, + LightSource = 0x9208, + Flash = 0x9209, + FocalLength = 0x920a, + SubjectArea = 0x9214, + MakerNote = 0x927c, + UserComment = 0x9286, + SubSecTime = 0x9290, + SubSecTimeOriginal = 0x9291, + SubSecTimeDigitized = 0x9292, + FlashPixVersion = 0xa000, + ColorSpace = 0xa001, + PixelXDimension = 0xa002, + PixelYDimension = 0xa003, + RelatedSoundFile = 0xa004, + InteroperabilityIfdPointer = 0xa005, + FlashEnergy = 0xa20b, + SpatialFrequencyResponse = 0xa20c, + FocalPlaneXResolution = 0xa20e, + FocalPlaneYResolution = 0xa20f, + FocalPlaneResolutionUnit = 0xa210, + SubjectLocation = 0xa214, + ExposureIndex = 0xa215, + SensingMethod = 0xa217, + FileSource = 0xa300, + SceneType = 0xa301, + NewCFAPattern = 0xa302, + CustomRendered = 0xa401, + ExposureMode = 0xa402, + WhiteBalance = 0xa403, + DigitalZoomRatio = 0xa404, + FocalLengthIn35mmFilm = 0xa405, + SceneCaptureType = 0xa406, + GainControl = 0xa407, + Contrast = 0xa408, + Saturation = 0xa409, + Sharpness = 0xa40a, + DeviceSettingDescription = 0xa40b, + SubjectDistanceRange = 0xa40c, + ImageUniqueId = 0xa420, + + // The Following IDs are not described the EXIF spec + + // The XMP spec declares that XMP data should live 0x2bc when + // embedded in tiff images. + XMP = 0x02bc, + + // Print Image Matching data + PimIfdPointer = 0xc4a5 + } + + public enum ExifByteOrder { + Motorola, + Intel + } + + public enum ExifFormat { + Byte = 1, + Ascii = 2, + Short = 3, + Long = 4, + Rational = 5, + Undefined = 7, + Slong = 9, + SRational = 10 } - public void Assemble () - { - unsafe { - content_func = new _ExifContent.ExifContentForeachEntryFunc (AssembleContent); + public enum ExifIfd { + Zero = 0, + One, + Exif, + Gps, + InterOperability, + Count + } + + public class ExifUtil { + + [DllImport ("libexif.dll")] + static extern IntPtr exif_tag_get_name (ExifTag tag); + + [DllImport ("libexif.dll")] + static extern IntPtr exif_tag_get_title (ExifTag tag); + + [DllImport ("libexif.dll")] + static extern IntPtr exif_tag_get_description (ExifTag tag); + + [DllImport ("libexif.dll")] + static extern IntPtr exif_byte_order_get_name (ExifByteOrder order); + + [DllImport ("libexif.dll")] + static extern IntPtr exif_format_get_name (ExifFormat format); + + [DllImport ("libexif.dll")] + static extern char exif_format_get_size (ExifFormat format); + + [DllImport ("libexif.dll")] + static extern IntPtr exif_ifd_get_name (ExifIfd ifd); + + public static string GetTagName (ExifTag tag) + { + + IntPtr raw_ret = exif_tag_get_name (tag); + return Marshal.PtrToStringAnsi (raw_ret); + } + + public static string GetTagTitle (ExifTag tag) + { + IntPtr raw_ret = exif_tag_get_title (tag); + return Marshal.PtrToStringAnsi (raw_ret); + } + + public static string GetTagDescription (ExifTag tag) + { + IntPtr raw_ret = exif_tag_get_description (tag); + return Marshal.PtrToStringAnsi (raw_ret); + } + + public static string GetByteOrderName (ExifByteOrder order) + { + IntPtr raw_ret = exif_byte_order_get_name (order); + return Marshal.PtrToStringAnsi (raw_ret); + } + + public static string GetFormatName (ExifFormat format) + { + IntPtr raw_ret = exif_format_get_name (format); + return Marshal.PtrToStringAnsi (raw_ret); + } + + public static char GetFormatSize (ExifFormat format) + { + return exif_format_get_size (format); + } + + public static string GetIfdName (ExifIfd ifd) + { + IntPtr raw_ret = exif_ifd_get_name (ifd); + return Marshal.PtrToStringAnsi (raw_ret); + } + + public static string GetIfdNameExtended (ExifIfd ifd) + { + switch (ifd) { + case ExifIfd.Zero: + return Mono.Posix.Catalog.GetString ("Image Directory"); + case ExifIfd.One: + return Mono.Posix.Catalog.GetString ("Thumbnail Directory"); + case ExifIfd.Exif: + return Mono.Posix.Catalog.GetString ("Exif Directory"); + case ExifIfd.Gps: + return Mono.Posix.Catalog.GetString ("GPS Directory"); + case ExifIfd.InterOperability: + return Mono.Posix.Catalog.GetString ("InterOperability Directory"); + default: + return Mono.Posix.Catalog.GetString ("Unknown Directory"); + } + } + + public static DateTime DateTimeFromString(string dt) + { + // Exif DateTime strings are formatted as + // "YYYY:MM:DD HH:MM:SS" + + string delimiters = " :"; + string[] dt_data = dt.Split ( delimiters.ToCharArray(), 6 ); + DateTime result; + result = new DateTime (Int32.Parse(dt_data[0]), Int32.Parse(dt_data[1]), Int32.Parse(dt_data[2]), + Int32.Parse(dt_data[3]), Int32.Parse(dt_data[4]), Int32.Parse(dt_data[5])); + + return result; + } + + } - string_values = new Hashtable (); - data = new Hashtable (); - tag_list = new ArrayList (); + public abstract class ExifObject : IDisposable { + protected HandleRef handle; + + public HandleRef Handle { + get { + return handle; + } + } + + public ExifObject () {} - _ExifData.exif_data_foreach_content (obj, new _ExifData.ExifDataForeachContentFunc (Assemble), null); - tags = (ExifTag []) tag_list.ToArray (typeof (ExifTag)); + public ExifObject (IntPtr ptr) + { + handle = new HandleRef (this, ptr); } + + protected abstract void Cleanup (); + + public void Dispose () { + Cleanup (); + System.GC.SuppressFinalize (this); + } + + ~ExifObject () + { + Cleanup (); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct _ExifContent { + IntPtr entries; + uint count; + IntPtr parent; + + IntPtr priv; } - protected virtual void Dispose (bool disposing) - { - unsafe { - if (obj != null){ - _ExifData.exif_data_unref (obj); - obj = null; + public class ExifContent : ExifObject { + ExifData parent; + public ExifData Parent { + get { + return parent; } } - string_values = null; - } - public string LookupString (ExifTag tag) - { - if (string_values == null) + System.Collections.ArrayList entries; + + internal ExifContent (ExifData parent, IntPtr handle) : base (handle) + { + this.parent = parent; + exif_content_ref (this.handle); + } + + [DllImport ("libexif.dll")] + static extern void exif_content_ref (HandleRef handle); + + [DllImport ("libexif.dll")] + static extern void exif_content_unref (HandleRef handle); + + protected override void Cleanup () + { + exif_content_unref (handle); + } + + [DllImport ("libexif.dll")] + internal static extern void exif_content_remove_entry (HandleRef content, HandleRef entry); + + [DllImport ("libexif.dll")] + internal static extern void exif_content_add_entry (HandleRef content, HandleRef entry); + + public ExifEntry Lookup (ExifTag tag) + { Assemble (); - return (string) string_values [tag]; - } + + foreach (ExifEntry entry in entries) { + if (entry.Tag == tag) { + return entry; + } + } + + return null; + } - public static DateTime DateTimeFromString(string dt) - { - // Exif DateTime strings are formatted as - // "YYYY:MM:DD HH:MM:SS" - - string delimiters = " :"; - string[] dt_data = dt.Split ( delimiters.ToCharArray(), 6 ); - DateTime result; - result = new DateTime (Int32.Parse(dt_data[0]), Int32.Parse(dt_data[1]), Int32.Parse(dt_data[2]), - Int32.Parse(dt_data[3]), Int32.Parse(dt_data[4]), Int32.Parse(dt_data[5])); + public bool Contains (ExifEntry entry) + { + Assemble (); - //Console.WriteLine ("parsed {0} as {1}", dt, result); - return result; - } + return entries.Contains (entry); + } - public byte [] LookupData (ExifTag tag) - { - if (data == null) + public ExifEntry GetEntry (ExifTag tag) + { Assemble (); - return data [tag] as byte []; - } + + ExifEntry entry = Lookup (tag); + if (entry == null) + entry = new ExifEntry (this, tag); - unsafe internal _ExifEntry * Search (ExifTag tag) - { - return null; - } + return entry; + } + + public void Add (ExifEntry entry) + { + Assemble (); + + entries.Add (entry); + // This call can recurse into this function but it protects + // itself by checking if it the content already contains the entry + entry.SetParent (this); + exif_content_add_entry (this.handle, entry.Handle); + } - byte [] empty = new byte [0]; + public void Remove (ExifEntry entry) + { + Assemble (); + + entries.Remove (entry); + // This call can recurse into this function but it protects + // itself by checking if it the content already contains the entry + entry.SetParent (null); + exif_content_remove_entry (this.handle, entry.Handle); + } + + public ExifEntry [] GetEntries () + { + Assemble (); + + return (ExifEntry [])entries.ToArray (typeof (ExifEntry)); + } + + [DllImport ("libexif.dll")] + internal static unsafe extern IntPtr exif_content_foreach_entry (HandleRef content, + ExifContentForeachEntryFunc func, + IntPtr data); + + internal delegate void ExifContentForeachEntryFunc (IntPtr entry_ptr, IntPtr data); + + void AssembleEntry (IntPtr entry, IntPtr data) + { + entries.Add (new ExifEntry (this, entry)); + } + + ExifContentForeachEntryFunc func; + + public void Assemble () + { + if (entries == null) { + entries = new System.Collections.ArrayList (); + + func = new ExifContentForeachEntryFunc (AssembleEntry); + exif_content_foreach_entry (this.Handle, func, IntPtr.Zero); + } + } + } + + + [StructLayout(LayoutKind.Sequential)] + internal struct _ExifEntry { + public ExifTag tag; + public int format; + public uint components; + public IntPtr data; + public uint size; + + public IntPtr parent; + + IntPtr priv; + } - public byte [] Data { - get { + + public class ExifEntry : ExifObject { + ExifContent parent; + public ExifContent Parent { + get { + unsafe { + if (_handle->parent != parent.Handle.Handle) + throw new Exception ("Invalid Object State"); + + return parent; + } + } + } + // Don't use this unless you know exactly what you are doing + internal void SetParent (ExifContent adoptor) { + // NOTE this api is ugly but the check prevent the parent state + // from getting confused. See ExifContent Add and Remove for the + // other half. + if (parent != null && parent.Contains (this)) + parent.Remove (this); + + if (adoptor != null && !adoptor.Contains (this)) + adoptor.Add (this); + + parent = adoptor; + } + + internal ExifEntry (ExifContent parent, IntPtr native) : base (native) + { + this.handle = new HandleRef (this, native); + this.parent = parent; + exif_entry_ref (this.handle); + } + + [DllImport ("libexif.dll")] + internal static extern IntPtr exif_entry_new (); + + [DllImport ("libexif.dll")] + internal static extern void exif_entry_initialize (HandleRef handle, ExifTag tag); + + public ExifEntry (ExifContent parent, ExifTag tag) + { + handle = new HandleRef (this, exif_entry_new ()); + parent.Add (this); + this.Reset (tag); + } + + public void Reset (ExifTag tag) + { unsafe { - byte [] result; + // Free any exsting data so that _initialize will actually set the data + if (_handle->data != IntPtr.Zero) + ExifData.free (_handle->data); + _handle->data = IntPtr.Zero; + } - if (obj == null || obj->data == (IntPtr) 0) - result = empty; - else { - result = new byte [obj->size]; - Marshal.Copy (obj->data, result, 0, obj->size); + exif_entry_initialize (handle, tag); + + //FIXME the month string in time fields in libexif ix currently broken so we do our own. + if (tag == ExifTag.DateTime + || tag == ExifTag.DateTimeOriginal + || tag == ExifTag.DateTimeDigitized) + this.SetData (System.DateTime.Now); + + } + + + public void Reset () + { + Reset (Tag); + } + + protected override void Cleanup () + { + exif_entry_unref (this.handle); + } + + private unsafe _ExifEntry *_handle { + get { + return (_ExifEntry *)handle.Handle; + } + } + + public ExifTag Tag { + get { + unsafe { + return _handle->tag; + } + } + } + + public ExifFormat Format { + get { + unsafe { + return (ExifFormat) _handle->format; + } + } + } + + public byte [] Data { + get { + unsafe { + byte [] data = new byte [_handle->size]; + Marshal.Copy (_handle->data, data, 0, (int)_handle->size); + return data; + } + } + } + + public void SetData (byte [] data, bool check_type) + { + unsafe { + if (data == null || data.Length == 0) + throw new System.Exception ("Invalid Length"); + + if (_handle->data != IntPtr.Zero) + ExifData.free (_handle->data); + + _handle->data = ExifData.malloc ((uint)data.Length); + Marshal.Copy (data, 0, _handle->data, data.Length); + + _handle->size = (uint) data.Length; + // This needs to be set per type as well but + // we do it here as well + _handle->components = (uint) data.Length; + } + } + + public void SetData (byte []data) + { + SetData (data, true); + } + + public void SetData (ushort [] data) + { + + } + + public void SetData (short [] data) + { + + } + + public void SetData (string value) + { + int len = System.Text.Encoding.UTF8.GetByteCount (value); + byte [] tmp = new byte [len + 1]; + System.Text.Encoding.UTF8.GetBytes (value, 0, value.Length, tmp, 0); + tmp[len] = 0; + System.Console.WriteLine ("value = {0} len = {1}", value, len); + SetData (tmp, false); + } + + public void SetData (System.DateTime time) + { + SetData (time.ToString ("yyyy:MM:dd HH:mm:ss")); + } + + private unsafe void PutBytes (byte *dest, byte *src, int count) + { + int i = 0; + if (System.BitConverter.IsLittleEndian == (this.ByteOrder == ExifByteOrder.Intel)) { + for (i = 0; i < count; i++) { + //System.Console.WriteLine ("Copying normal byte [{0}]= {1}", i, src[i]); + dest [i] = src [i]; + } + } else { + for (i = 0; i < count; i++) { + //System.Console.WriteLine ("Copying swapped byte [{0}]= {1}", i, src[i]); + dest [i] = src [count - i -1]; + } + } + } + + private unsafe uint ToUInt (byte *src) + { + uint value; + PutBytes ((byte *)&value, (byte *)src, 4); + return value; + } + + private unsafe ushort ToUShort (byte *src) + { + ushort value; + PutBytes ((byte *)&value, (byte *)src, 2); + return value; + } + + public uint [] GetDataUInt () { + unsafe { + uint [] result = new uint [_handle->components]; + uint *src = (uint *)_handle->data; + //System.Console.WriteLine ("copying {0} components", result.Length); + for (int i = 0; i < result.Length; i++) { + result [i] = ToUInt ((byte *)src); + //System.Console.WriteLine ("value[{0}] = {1}", i, result [i]); + src += i; + } + + return result; + } + } + public ushort [] GetDataUShort () { + unsafe { + ushort [] result = new ushort [_handle->components]; + ushort *src = (ushort *)_handle->data; + //System.Console.WriteLine ("copying {0} components", result.Length); + for (int i = 0; i < result.Length; i++) { + result [i] = ToUShort ((byte *)src); + //System.Console.WriteLine ("value[{0}] = {1}", i, result [i]); + src += i; } + return result; } } - } -} -[StructLayout(LayoutKind.Sequential)] -internal unsafe struct _ExifNote { - [DllImport ("libexif.so")] - internal static extern void exif_note_ref (_ExifNote *note); - [DllImport ("libexif.so")] - internal static extern void exif_note_unref (_ExifNote *note); + public int [] GetDataInt () { + return null; + } - [DllImport ("libexif.so")] - internal static extern void exif_note_free (_ExifNote *note); + public ExifByteOrder ByteOrder + { + get { + return parent.Parent.GetByteOrder (); + } + } - [DllImport ("libexif.so")] - internal static extern IntPtr exif_note_new_from_data (string data, uint size); + public string Description + { + get { + return ExifUtil.GetTagDescription (Tag); + } + } + + public string Name + { + get { + return ExifUtil.GetTagName (Tag); + } + } + + public string Title + { + get { + return ExifUtil.GetTagTitle (Tag); + } + } + + static int fallback = 0; + + // FIXME this version is only valid in libexif 0.5 + [DllImport ("libexif.dll")] + internal static extern IntPtr exif_entry_get_value (HandleRef handle); + [DllImport ("libexif.dll")] + internal static extern IntPtr exif_entry_get_value_brief (HandleRef handle); + + // FIXME this version is only valid in libexif 0.6 + [DllImport ("libexif.dll")] + internal static extern IntPtr exif_entry_get_value (HandleRef handle, byte [] value, int maxlen); + + public string Value + { + get { + if (fallback == 0) { + try { + exif_entry_get_value_brief (this.Handle); + fallback = 1; + } catch (System.Exception e) { + fallback = -1; + } + } + + if (fallback > 0) + return Marshal.PtrToStringAnsi (exif_entry_get_value (this.Handle)); + else { + byte [] value = new byte [1024]; + exif_entry_get_value (this.Handle, value, value.Length); + + int i; + for (i = 0; i < value.Length; i++) { + if (value [i] == 0) + break; + } + int len = System.Math.Max (i, 0); + if (len == 0) + return null; + + return System.Text.Encoding.UTF8.GetString (value, 0, len); + } + } + } + + [DllImport ("libexif.dll")] + internal static extern void exif_entry_ref (HandleRef handle); + + [DllImport ("libexif.dll")] + internal static extern void exif_entry_unref (HandleRef handle); + } - [DllImport ("libexif.so")] - internal static extern string [] exif_note_get_value (_ExifNote *note); + [StructLayout(LayoutKind.Sequential)] + internal struct _ExifData { + IntPtr ifd0; + IntPtr ifd1; + IntPtr ifd_exif; + IntPtr ifd_gps; + IntPtr ifd_interop; - [DllImport ("libexif.so")] - internal static extern void exif_note_set_byte_order (_ExifNote *note, ExifByteOrder order); + internal IntPtr data; + internal int size; + + IntPtr priv; + } + + public class ExifData : ExifObject { + System.Collections.ArrayList ifds; + + [DllImport ("libexif.dll")] + internal static extern IntPtr exif_data_new (); + + public ExifData () + { + handle = new HandleRef (this, exif_data_new ()); + } + + [DllImport ("libexif.dll")] + internal static extern IntPtr exif_data_new_from_file (string path); + + public ExifData (string filename) + { + handle = new HandleRef (this, exif_data_new_from_file (filename)); + } + + [DllImport ("libexif.dll")] + internal static extern IntPtr exif_data_new_from_data (byte [] data, uint size); + + public ExifData (byte [] data, uint size) + { + handle = new HandleRef (this, exif_data_new_from_data (data, size)); + } - [DllImport ("libexif.so")] - internal static extern ExifByteOrder exif_note_get_byte_order (_ExifNote *note); -} + [DllImport ("libc")] + internal static extern void free (IntPtr address); + + [DllImport ("libc")] + internal static extern IntPtr malloc (uint size); + + [DllImport ("libexif.dll")] + private static extern void exif_data_save_data (HandleRef handle, out IntPtr content, out uint size); + public byte [] Save () + { + Byte [] content = null; + uint size; + IntPtr data; + unsafe { + exif_data_save_data (handle, out data, out size); + + content = new byte [size]; + Marshal.Copy (data, content, 0, (int)size); + free (data); + } + + System.Console.WriteLine ("Saved {0} bytes", content.Length); + return content; + } + + [DllImport ("libexif.dll")] + internal static extern void exif_data_unref (HandleRef data); + + [DllImport ("libexif.dll")] + internal static extern void exif_data_free (HandleRef data); + + protected override void Cleanup () + { + exif_data_unref (handle); + } + + public ExifContent GetContents (ExifIfd ifd) + { + Assemble (); + return (ExifContent) ifds [(int)ifd]; + } + + public ExifContent [] GetContents () + { + Assemble (); + + return (ExifContent []) ifds.ToArray (typeof (ExifContent)); + } + + [DllImport("libexif.dll")] + internal static extern ExifByteOrder exif_data_get_byte_order (HandleRef handle); + + public ExifByteOrder GetByteOrder () + { + return exif_data_get_byte_order (handle); + } + + internal delegate void ExifDataForeachContentFunc (IntPtr content, IntPtr data); + + [DllImport ("libexif.dll")] + internal unsafe static extern void exif_data_foreach_content(HandleRef handle, ExifDataForeachContentFunc func, IntPtr data); + + unsafe void AssembleIfds (IntPtr content, IntPtr data) + { + ifds.Add (new ExifContent (this, content)); + } + + public ExifEntry LookupFirst (ExifTag tag) + { + Assemble (); + foreach (ExifContent content in ifds) { + if (content == null) + continue; + + ExifEntry entry = content.Lookup (tag); + if (entry != null) + return entry; + } + return null; + } + + public string LookupFirstValue (ExifTag tag) + { + ExifEntry entry = LookupFirst (tag); + if (entry != null) { + return entry.Value; + } + return null; + } + + public void Assemble () + { + if (ifds == null) { + ifds = new System.Collections.ArrayList (); + + if (handle.Handle != IntPtr.Zero) + exif_data_foreach_content (handle, new ExifDataForeachContentFunc (AssembleIfds), IntPtr.Zero); + } + } + + byte [] empty = new byte [0]; + public byte [] Data { + get { + unsafe { + _ExifData * obj = (_ExifData *) Handle.Handle; + byte [] result; + + if (obj == null || obj->data == (IntPtr) 0) + result = empty; + else { + result = new byte [obj->size]; + Marshal.Copy (obj->data, result, 0, obj->size); + + } + return result; + } + } + set { + unsafe { + _ExifData * obj = (_ExifData *) Handle.Handle; + if (value.Length > 65533) + throw new System.Exception ("Thumbnail too large"); + + if (obj->data != IntPtr.Zero) + free (obj->data); + + obj->data = malloc ((uint)value.Length); + Marshal.Copy (value, 0, obj->data, value.Length); + } + } + } + } } Index: Util/JpegHeader.cs =================================================================== RCS file: /cvs/gnome/beagle/Util/JpegHeader.cs,v retrieving revision 1.2 diff -u -B -p -r1.2 JpegHeader.cs --- Util/JpegHeader.cs 15 Oct 2004 13:13:16 -0000 1.2 +++ Util/JpegHeader.cs 31 Mar 2005 23:34:16 -0000 @@ -70,6 +70,18 @@ public class JpegHeader { App15 = 0xef, Jpg0 = 0xf0, + Jpg1 = 0xf1, + Jpg2 = 0xf2, + Jpg3 = 0xf3, + Jpg4 = 0xf4, + Jpg5 = 0xf5, + Jpg6 = 0xf6, + Jpg7 = 0xf7, + Jpg8 = 0xf8, + Jpg9 = 0xf9, + Jpg10 = 0xfa, + Jpg11 = 0xfb, + Jpg12 = 0xfc, Jpg13 = 0xfd, Com = 0xfe // Comment @@ -126,7 +139,7 @@ public class JpegHeader { string header = System.Text.Encoding.ASCII.GetString (m.Data, 0, j); app_marker_hash [header] = m; - //System.Console.WriteLine (header); + System.Console.WriteLine (header); } System.Collections.Hashtable app_marker_hash = new System.Collections.Hashtable (); @@ -134,17 +147,16 @@ public class JpegHeader { public JpegHeader (string filename) { - //System.Console.WriteLine ("opening {0}", filename); System.IO.FileStream stream = new System.IO.FileStream (filename, System.IO.FileMode.Open); LoadFromStream (stream); stream.Close (); } - public JpegHeader (System.IO.Stream stream) + public JpegHeader (System.IO.Stream stream) { LoadFromStream (stream); } - + private void LoadFromStream (System.IO.Stream stream) { byte [] length_data = new byte [2]; @@ -180,7 +192,7 @@ public class JpegHeader { } ushort length = System.BitConverter.ToUInt16 (length_data, 0); - //System.Console.WriteLine ("Marker {0} Length = {1}", marker.ToString (), length); + System.Console.WriteLine ("Marker {0} Length = {1}", marker.ToString (), length); if (length < 2) throw new System.Exception ("Invalid Marker length"); @@ -221,7 +233,7 @@ public class JpegHeader { case JpegMarker.Rst6: case JpegMarker.Rst7: case JpegMarker.Tem: - // These markers have no the data is in length_data + // These markers have no data it is in length_data marker_list.Add (new Marker (marker, length_data, position)); break; @@ -238,7 +250,7 @@ public class JpegHeader { at_image = true; } } - +#if false public static int Main (string [] args) { JpegHeader data = new JpegHeader (args [0]); @@ -258,13 +270,14 @@ public class JpegHeader { value = data.GetRawExif (); if (value != null) { - ExifData exif = new ExifData (value, (uint)value.Length); - System.Console.WriteLine (exif.LookupString (ExifTag.Model)); + System.IO.MemoryStream stream = new System.IO.MemoryStream (value, 6, value.Length - 6); + Tiff.Header tiff = new Tiff.Header (stream); + tiff.Dump (); } return 0; } - +#endif } }