[f-spot/taglib-metadata: 8/13] Big leap closer to Taglib# usage.



commit b0c19e68f8ad151743be73379d32d72fdfa81c9e
Author: Ruben Vermeersch <ruben savanne be>
Date:   Sat Jun 12 17:50:43 2010 +0200

    Big leap closer to Taglib# usage.
    
    WARNING: this commit causes file corruption! See below!
    
    Changes:
    * Migrated from PixbufOrientation to TagLib.Image.ImageOrientation.
    * Parse dates and descriptions directly using TagLib, instead of in
      ImageFile.
    * Move metadata writing mostly to TagLib.
    * Added (non-working) unit test for GIOTagLibFileAbstraction.
    
    There seems to be an interesting corruption happening when using the
    GIOTagLibFileAbstraction. This does not occur when using normal IO. Am
    puzzled, but I suspect it is something related to the read/write
    behavior of GIO that trips this up.
    
    Apparently GIO has atomic write support, which we should use. Needs
    fixing.

 src/Accelerometer.cs                             |    7 +-
 src/FileBrowsableItem.cs                         |   23 ++--
 src/Filters/OrientationFilter.cs                 |   15 ++-
 src/Imaging/Ciff.cs                              |   19 ++--
 src/Imaging/ImageFile.cs                         |   13 +-
 src/Imaging/JpegFile.cs                          |   65 +--------
 src/Imaging/PngFile.cs                           |   22 ---
 src/Imaging/RafFile.cs                           |   11 +-
 src/Imaging/Tiff.cs                              |   15 +--
 src/Imaging/X3fFile.cs                           |   15 +-
 src/Import/FileImportSource.cs                   |   17 ++-
 src/Jobs/SyncMetadataJob.cs                      |  165 ++++++++++------------
 src/Loaders/GdkImageLoader.cs                    |    7 +-
 src/Loaders/IImageLoader.cs                      |    3 +-
 src/MetadataStore.cs                             |    2 +-
 src/PhotoImageView.cs                            |    6 +-
 src/PixbufUtils.cs                               |   27 ++--
 src/RotateCommand.cs                             |   82 +++++------
 src/Tests/UpdaterTests.cs                        |    2 +
 src/Utils/GIOTagLibFileAbstraction.cs            |   25 +++-
 src/Utils/Makefile.am                            |    2 +-
 src/Utils/PixbufOrientation.cs                   |   37 -----
 src/Utils/PixbufUtils.cs                         |  103 +++++++-------
 src/Utils/Tests/GIOTagLibFileAbstractionTests.cs |  132 +++++++++++++++++
 src/Widgets/ImageView.cs                         |    7 +-
 tests/Makefile.am                                |    3 +-
 tests/data/taglib-sample.jpg                     |  Bin 0 -> 41921 bytes
 27 files changed, 422 insertions(+), 403 deletions(-)
---
diff --git a/src/Accelerometer.cs b/src/Accelerometer.cs
index 3978f12..f7148ea 100644
--- a/src/Accelerometer.cs
+++ b/src/Accelerometer.cs
@@ -7,6 +7,7 @@ using System.IO;
 
 using FSpot.Utils;
 using Hyena;
+using TagLib.Image;
 
 namespace FSpot {
 
@@ -33,7 +34,7 @@ namespace FSpot {
 		{
 		}
 
-		public static PixbufOrientation GetViewOrientation (PixbufOrientation po)
+		public static ImageOrientation GetViewOrientation (ImageOrientation po)
 		{
 			if (timer == 0 && available)
 				SetupAccelerometer ();
@@ -52,7 +53,7 @@ namespace FSpot {
 
 		public static void SetupAccelerometer ()
 		{
-			if (!File.Exists(SYSFS_FILE)) {
+			if (!System.IO.File.Exists (SYSFS_FILE)) {
 				available = false;
 				return;
 			}
@@ -105,7 +106,7 @@ namespace FSpot {
 		private static void GetHDAPSCoords (out int x, out int y)
 		{
 			try {
-				using (Stream file = File.OpenRead (SYSFS_FILE)) {
+				using (Stream file = System.IO.File.OpenRead (SYSFS_FILE)) {
 					StreamReader sr = new StreamReader (file);
 
 					string s = sr.ReadLine ();
diff --git a/src/FileBrowsableItem.cs b/src/FileBrowsableItem.cs
index be92366..37066f7 100644
--- a/src/FileBrowsableItem.cs
+++ b/src/FileBrowsableItem.cs
@@ -35,11 +35,12 @@ namespace FSpot {
 			if (metadata_parsed)
 				return;
 
-            var res = new GIOTagLibFileAbstraction () { Uri = DefaultVersion.Uri };
-            var metadata_file = TagLib.File.Create (res) as TagLib.Image.File;
-            var date = metadata_file.ImageTag.DateTime;
-            time = date.HasValue ? date.Value : CreateDate;
-            description = metadata_file.ImageTag.Comment;
+			var res = new GIOTagLibFileAbstraction () { Uri = DefaultVersion.Uri };
+			using (var metadata = TagLib.File.Create (res) as TagLib.Image.File) {
+				var date = metadata.ImageTag.DateTime;
+				time = date.HasValue ? date.Value : CreateDate;
+				description = metadata.ImageTag.Comment;
+			}
 
 			metadata_parsed = true;
 		}
@@ -50,13 +51,13 @@ namespace FSpot {
 			}
 		}
 
-		private DateTime time;
-		public DateTime Time {
-			get {
+        private DateTime time;
+        public System.DateTime Time {
+            get {
 				EnsureMetadataParsed ();
-				return time;
-			}
-		}
+                return time;
+            }
+        }
 
         private DateTime CreateDate {
             get {
diff --git a/src/Filters/OrientationFilter.cs b/src/Filters/OrientationFilter.cs
index fef3886..12f3fca 100644
--- a/src/Filters/OrientationFilter.cs
+++ b/src/Filters/OrientationFilter.cs
@@ -18,9 +18,11 @@ namespace FSpot.Filters {
 			string source = req.Current.LocalPath;
 			var dest_uri = req.TempUri (System.IO.Path.GetExtension (source));
 			string dest = dest_uri.LocalPath;
+            bool changed = false;
 
+            // FIXME: needs to be re-added https://bugzilla.gnome.org/show_bug.cgi?id=621369
+            /*
 			using (ImageFile img = ImageFile.Create (req.Current)) {
-				bool changed = false;
 				
 				if (img.Orientation != PixbufOrientation.TopLeft && img is JpegFile) {
 					JpegFile jimg = img as JpegFile;
@@ -58,12 +60,13 @@ namespace FSpot.Filters {
 						jimg.Dispose ();
 					}
 				}
-	
-				if (changed)
-					req.Current = dest_uri;
-	
-				return changed;
 			}
+            */
+
+            if (changed)
+                req.Current = dest_uri;
+
+            return changed;
 		}
 		
 	}
diff --git a/src/Imaging/Ciff.cs b/src/Imaging/Ciff.cs
index 97994ba..b44e548 100644
--- a/src/Imaging/Ciff.cs
+++ b/src/Imaging/Ciff.cs
@@ -1,6 +1,7 @@
 using System;
 using FSpot.Utils;
 using Hyena;
+using TagLib.Image;
 
 namespace FSpot.Ciff {
 	public enum Tag {
@@ -89,7 +90,7 @@ namespace FSpot.Ciff {
 
 	
 
-	public struct ImageSpec {
+	internal struct ImageSpec {
 		public uint ImageWidth;  // Number of horizontal pixels
 		public uint ImageHeight; // Number of vertical pixels
 		public float PixelAspectRatio;
@@ -111,19 +112,19 @@ namespace FSpot.Ciff {
 			Log.DebugFormat ("0x{0}", ColorBW.ToString ("x"));
 		}
 
-		public PixbufOrientation Orientation {
+		public ImageOrientation Orientation {
 			get {
 				int angle = RotationAngle % 360;
 				if (angle < 45)
-					return PixbufOrientation.TopLeft;
+					return ImageOrientation.TopLeft;
 				else if (angle < 135)
-					return PixbufOrientation.RightTop;
+					return ImageOrientation.RightTop;
 				else if (angle < 225)
-					return PixbufOrientation.BottomRight;
+					return ImageOrientation.BottomRight;
 				else if (angle < 315)
-					return PixbufOrientation.LeftBottom;
+					return ImageOrientation.LeftBottom;
 				else
-					return PixbufOrientation.TopLeft;
+					return ImageOrientation.TopLeft;
 			}
 		}
 
@@ -418,9 +419,9 @@ namespace FSpot.Ciff {
 			get { return version; }
 		}
 
-		public override PixbufOrientation GetOrientation ()
+		public override ImageOrientation GetOrientation ()
 		{
-			PixbufOrientation orientation = PixbufOrientation.TopLeft;
+			var orientation = ImageOrientation.TopLeft;
 			ImageDirectory props = Root.ReadDirectory (Tag.ImageProps);
 		       	byte [] data = props.ReadEntry (Tag.ImageSpec);
 			
diff --git a/src/Imaging/ImageFile.cs b/src/Imaging/ImageFile.cs
index 1e8ee4d..0ef7ebc 100644
--- a/src/Imaging/ImageFile.cs
+++ b/src/Imaging/ImageFile.cs
@@ -9,6 +9,8 @@ using Mono.Unix;
 using Mono.Unix.Native;
 using Gdk;
 
+using TagLib.Image;
+
 using GFileInfo = GLib.FileInfo;
 
 namespace FSpot {
@@ -105,15 +107,10 @@ namespace FSpot {
 			get { return this.uri; }
 		}
 
-		public PixbufOrientation Orientation {
+		public ImageOrientation Orientation {
 			get { return GetOrientation (); }
 		}
 
-		public virtual string Description
-		{
-			get { return null; }
-		}
-		
 		public virtual void Save (Gdk.Pixbuf pixbuf, System.IO.Stream stream)
 		{
 			throw new NotImplementedException (Catalog.GetString ("Writing to this file format is not supported"));
@@ -155,9 +152,9 @@ namespace FSpot {
 			}	
 		}
 	
-		public virtual PixbufOrientation GetOrientation () 
+		public virtual ImageOrientation GetOrientation ()
 		{
-			return PixbufOrientation.TopLeft;
+			return ImageOrientation.TopLeft;
 		}
 		
 		// FIXME this need to have an intent just like the loading stuff.
diff --git a/src/Imaging/JpegFile.cs b/src/Imaging/JpegFile.cs
index 5a7d8e6..c2ffb80 100644
--- a/src/Imaging/JpegFile.cs
+++ b/src/Imaging/JpegFile.cs
@@ -5,6 +5,7 @@ using FSpot.Tiff;
 using FSpot.Utils;
 using Hyena;
 using TagLib;
+using TagLib.Image;
 
 namespace FSpot {
 	public interface IThumbnailContainer {
@@ -32,62 +33,6 @@ namespace FSpot {
 			return null;
 		}
 
-		public override string Description {
-			get {
-                return metadata_file.ImageTag.Comment;
-			}
-		}
-
-		public void SetDescription (string value)
-		{
-            metadata_file.GetTag (TagTypes.XMP, true); // Ensure XMP tag
-            metadata_file.ImageTag.Comment = value;
-		}
-
-		private void UpdateMeta ()
-		{
-            metadata_file.GetTag (TagTypes.XMP, true); // Ensure XMP tag
-            metadata_file.ImageTag.Software = FSpot.Defines.PACKAGE + " version " + FSpot.Defines.VERSION;
-		}
-
-		/*private void SaveMetaData (System.IO.Stream input, System.IO.Stream output)
-		{
-			JpegHeader header = new JpegHeader (input);
-			UpdateMeta ();
-			
-			// Console.WriteLine ("updated metadata");
-			header.SetExif (this.ExifData);
-			// Console.WriteLine ("set exif");
-			if (xmp != null)
-				header.SetXmp (xmp);
-			// Console.WriteLine ("set xmp");
-			header.Save (output);
-			// Console.WriteLine ("saved");
-		}*/
-		
-		public void SaveMetaData (string path)
-		{
-            // FIXME: This currently copies the file out to a tmp file, overwrites it
-            // and restores the tmp file in case of failure. Should obviously be the
-            // other way around, but Taglib# doesn't have an interface to do this.
-            // https://bugzilla.gnome.org/show_bug.cgi?id=618768
-
-            var uri = new SafeUri (path);
-            var tmp = System.IO.Path.GetTempFileName ();
-            var tmp_uri = new SafeUri (tmp);
-
-            var orig_file = GLib.FileFactory.NewForUri (uri);
-            var tmp_file = GLib.FileFactory.NewForUri (tmp_uri);
-
-            orig_file.Copy (tmp_file, GLib.FileCopyFlags.AllMetadata, null, null);
-
-            try {
-                metadata_file.Save ();
-            } catch (Exception) {
-                tmp_file.Copy (orig_file, GLib.FileCopyFlags.AllMetadata, null, null);
-            }
-		}
-
 		public void SetThumbnail (Gdk.Pixbuf source)
 		{
 			/*// Then create the thumbnail
@@ -167,15 +112,15 @@ namespace FSpot {
 			return null;
 		}
 		
-		public override PixbufOrientation GetOrientation () 
+		public override ImageOrientation GetOrientation ()
 		{
             var orientation = metadata_file.ImageTag.Orientation;
-			return (PixbufOrientation) orientation;
+			return orientation;
 		}
 		
-		public void SetOrientation (PixbufOrientation orientation)
+		public void SetOrientation (ImageOrientation orientation)
 		{
-            metadata_file.ImageTag.Orientation = (TagLib.Image.ImageOrientation) orientation;
+            metadata_file.ImageTag.Orientation = orientation;
 		}
 		
 		public void SetDateTimeOriginal (DateTime time)
diff --git a/src/Imaging/PngFile.cs b/src/Imaging/PngFile.cs
index be87c09..ea07d9d 100644
--- a/src/Imaging/PngFile.cs
+++ b/src/Imaging/PngFile.cs
@@ -1320,28 +1320,6 @@ namespace FSpot.Png {
 			return null;
 		}
 
-		public override string Description {
-			get {
-				string description = Header.LookupText ("Description");
-
-				if (description != null)
-					return description;
-				else
-					return Header.LookupText ("Comment");
-			}
-		}
-
-		public void SetDescription (string description) 
-		{
-			TextChunk text = null;
-			text = Header.LookupTextChunk ("Description");
-			
-			if (text != null)
-				text.SetText (description);
-			else 
-				Header.Insert (new TextChunk ("Description", description));
-		}
-
 		public XmpFile GetXmp ()
 		{
 			TextChunk xmpchunk  = Header.LookupTextChunk ("XML:com.adobe.xmp");
diff --git a/src/Imaging/RafFile.cs b/src/Imaging/RafFile.cs
index cff1128..826e6e3 100644
--- a/src/Imaging/RafFile.cs
+++ b/src/Imaging/RafFile.cs
@@ -1,5 +1,6 @@
 using FSpot.Utils;
 using Hyena;
+using TagLib.Image;
 
 namespace FSpot.Raf {
 	// This is reverse engineered from looking at the sample files I have
@@ -34,17 +35,17 @@ namespace FSpot.Raf {
 			}
 		}
 		
-		public override PixbufOrientation GetOrientation (){
-			PixbufOrientation orientation = PixbufOrientation.TopLeft;
+		public override ImageOrientation GetOrientation (){
+			var orientation = ImageOrientation.TopLeft;
 
 			Exif.ExifEntry e = this.ExifData.GetContents (Exif.Ifd.Zero).Lookup (Exif.Tag.Orientation);
 			if (e != null) {
 				ushort [] value = e.GetDataUShort ();
-				orientation = (PixbufOrientation) value [0];
+				orientation = (ImageOrientation) value [0];
 			}
 
-			if (orientation < PixbufOrientation.TopLeft || orientation > PixbufOrientation.LeftBottom)
-				orientation = PixbufOrientation.TopLeft;
+			if (orientation < ImageOrientation.TopLeft || orientation > ImageOrientation.LeftBottom)
+				orientation = ImageOrientation.TopLeft;
 
 			return orientation;
 		}
diff --git a/src/Imaging/Tiff.cs b/src/Imaging/Tiff.cs
index e7df951..75816c8 100644
--- a/src/Imaging/Tiff.cs
+++ b/src/Imaging/Tiff.cs
@@ -6,6 +6,7 @@ using System;
 using System.IO;
 using System.Collections.Generic;
 using Hyena;
+using TagLib.Image;
 
 namespace FSpot.Tiff {
 
@@ -2035,13 +2036,13 @@ namespace FSpot.Tiff {
 			Header.SelectDirectory (Header.Directory, sink);
 		}
 
-		public override PixbufOrientation GetOrientation ()
+		public override ImageOrientation GetOrientation ()
 		{
 			ShortEntry e = (ShortEntry)(this.Header.Directory.Lookup (TagId.Orientation));
 			if (e != null) 
-				return (PixbufOrientation)(e.ShortValue[0]);
+				return (ImageOrientation)(e.ShortValue[0]);
 			else
-				return PixbufOrientation.TopLeft;
+				return ImageOrientation.TopLeft;
 		}
 
 		public System.IO.Stream LookupJpegSubstream (ImageDirectory directory)
@@ -2226,13 +2227,6 @@ namespace FSpot.Tiff {
 		{
 		}
 
-		/*
-		public override PixbufOrientation GetOrientation ()
-		{
-			return PixbufOrientation.TopLeft;
-		}
-		*/
-
 		public Gdk.Pixbuf GetEmbeddedThumbnail ()
 		{
 			ImageDirectory directory;
@@ -2240,7 +2234,6 @@ namespace FSpot.Tiff {
 			return TransformAndDispose (LoadJpegInterchangeFormat (directory));
 		}
 
-
 		public override System.IO.Stream PixbufStream ()
 		{
 			uint offset = Header.Directory.Lookup (TagId.StripOffsets).ValueAsLong [0];
diff --git a/src/Imaging/X3fFile.cs b/src/Imaging/X3fFile.cs
index 233b3a9..486d704 100644
--- a/src/Imaging/X3fFile.cs
+++ b/src/Imaging/X3fFile.cs
@@ -4,6 +4,7 @@ using FSpot;
 using FSpot.Utils;
 using SemWeb;
 using Hyena;
+using TagLib.Image;
 
 namespace FSpot.X3f {
 	internal class Info {
@@ -15,19 +16,19 @@ namespace FSpot.X3f {
 		uint rows;
 		uint rotation;
 
-		public PixbufOrientation Orientation {
+		public ImageOrientation Orientation {
 			get {
 				switch (rotation) {
 				case 0:
-					return PixbufOrientation.TopLeft;
+					return ImageOrientation.TopLeft;
 				case 270:
-					return PixbufOrientation.LeftBottom;
+					return ImageOrientation.LeftBottom;
 				case 180:
-					return PixbufOrientation.BottomRight;
+					return ImageOrientation.BottomRight;
 				case 90:
-					return PixbufOrientation.RightTop;
+					return ImageOrientation.RightTop;
 				default:
-					return PixbufOrientation.TopLeft;
+					return ImageOrientation.TopLeft;
 				}
 			}
 		}
@@ -101,7 +102,7 @@ namespace FSpot.X3f {
 			MetadataStore.AddLiteral (sink, "tiff:ImageLength", Info.Height.ToString ());
 		}
 
-		public override PixbufOrientation GetOrientation ()
+		public override ImageOrientation GetOrientation ()
 		{
 			return Info.Orientation;
 		}
diff --git a/src/Import/FileImportSource.cs b/src/Import/FileImportSource.cs
index 2bc051d..76a66e8 100644
--- a/src/Import/FileImportSource.cs
+++ b/src/Import/FileImportSource.cs
@@ -155,11 +155,12 @@ namespace FSpot.Import
 			if (metadata_parsed)
 				return;
 
-            var res = new GIOTagLibFileAbstraction () { Uri = DefaultVersion.Uri };
-            var metadata_file = TagLib.File.Create (res) as TagLib.Image.File;
-            var date = metadata_file.ImageTag.DateTime;
-            time = date.HasValue ? date.Value : CreateDate;
-            description = metadata_file.ImageTag.Comment;
+			var res = new GIOTagLibFileAbstraction () { Uri = DefaultVersion.Uri };
+			using (var metadata = TagLib.File.Create (res) as TagLib.Image.File) {
+				var date = metadata.ImageTag.DateTime;
+				time = date.HasValue ? date.Value : CreateDate;
+				description = metadata.ImageTag.Comment;
+			}
 
 			metadata_parsed = true;
 		}
@@ -169,10 +170,10 @@ namespace FSpot.Import
 
         private DateTime time;
         public System.DateTime Time {
-			get {
+            get {
 				EnsureMetadataParsed ();
-				return time;
-			}
+                return time;
+            }
         }
 
 		private string description;
diff --git a/src/Jobs/SyncMetadataJob.cs b/src/Jobs/SyncMetadataJob.cs
index ab0b379..04d1463 100644
--- a/src/Jobs/SyncMetadataJob.cs
+++ b/src/Jobs/SyncMetadataJob.cs
@@ -13,99 +13,86 @@ using FSpot.Utils;
 using Hyena;
 
 namespace FSpot.Jobs {
-	public class SyncMetadataJob : Job
-	{
-		public SyncMetadataJob (uint id, string job_options, int run_at, JobPriority job_priority, bool persistent) : this (id, job_options, DbUtils.DateTimeFromUnixTime (run_at), job_priority, persistent)
-		{
-		}
-
-		public SyncMetadataJob (uint id, string job_options, DateTime run_at, JobPriority job_priority, bool persistent) : base (id, job_options, job_priority, run_at, persistent)
-		{
-		}
-
-		//Use THIS static method to create a job...
-		public static SyncMetadataJob Create (JobStore job_store, Photo photo)
-		{
-			return (SyncMetadataJob) job_store.CreatePersistent (typeof (FSpot.Jobs.SyncMetadataJob), photo.Id.ToString ());
-		}
-
-		protected override bool Execute ()
-		{
-			//this will add some more reactivity to the system
-			System.Threading.Thread.Sleep (500);
-			Log.Debug ("Syncing metadata to file...");
-			try {
-				Photo photo = FSpot.App.Instance.Database.Photos.Get (Convert.ToUInt32 (JobOptions)) as Photo;
-				WriteMetadataToImage (photo);
-				return true;
-			} catch (System.Exception e) {
-				Log.ErrorFormat ("Error syncing metadata to file\n{0}", e);
-			}
-			return false;
-		}
-
-		//FIXME: Won't work on non-file uris
-		void WriteMetadataToImage (Photo photo)
-		{
-			string path = photo.DefaultVersion.Uri.LocalPath;
+    public class SyncMetadataJob : Job
+    {
+        public SyncMetadataJob (uint id, string job_options, int run_at, JobPriority job_priority, bool persistent) : this (id, job_options, DbUtils.DateTimeFromUnixTime (run_at), job_priority, persistent)
+        {
+        }
+
+        public SyncMetadataJob (uint id, string job_options, DateTime run_at, JobPriority job_priority, bool persistent) : base (id, job_options, job_priority, run_at, persistent)
+        {
+        }
+
+        //Use THIS static method to create a job...
+        public static SyncMetadataJob Create (JobStore job_store, Photo photo)
+        {
+            return (SyncMetadataJob) job_store.CreatePersistent (typeof (FSpot.Jobs.SyncMetadataJob), photo.Id.ToString ());
+        }
+
+        protected override bool Execute ()
+        {
+            //this will add some more reactivity to the system
+            System.Threading.Thread.Sleep (500);
+            Log.Debug ("Syncing metadata to file...");
+            try {
+                Photo photo = FSpot.App.Instance.Database.Photos.Get (Convert.ToUInt32 (JobOptions)) as Photo;
+                WriteMetadataToImage (photo);
+                return true;
+            } catch (System.Exception e) {
+                Log.ErrorFormat ("Error syncing metadata to file\n{0}", e);
+            }
+            return false;
+        }
+
+        public void SaveMetaData (TagLib.File image, string path)
+        {
+            // FIXME: This currently copies the file out to a tmp file, overwrites it
+            // and restores the tmp file in case of failure. Should obviously be the
+            // other way around, but Taglib# doesn't have an interface to do this.
+            // https://bugzilla.gnome.org/show_bug.cgi?id=618768
+
+            var uri = new SafeUri (path);
+            var tmp = System.IO.Path.GetTempFileName ();
+            var tmp_uri = new SafeUri (tmp);
+
+            var orig_file = GLib.FileFactory.NewForUri (uri);
+            var tmp_file = GLib.FileFactory.NewForUri (tmp_uri);
+
+            tmp_file.Delete ();
+            orig_file.Copy (tmp_file, GLib.FileCopyFlags.AllMetadata | GLib.FileCopyFlags.Overwrite, null, null);
+
+            try {
+                image.Save ();
+            } catch (Exception e) {
+                Log.DebugException (e);
+                tmp_file.Copy (orig_file, GLib.FileCopyFlags.AllMetadata | GLib.FileCopyFlags.Overwrite, null, null);
+            }
+        }
+
+        void WriteMetadataToImage (Photo photo)
+        {
+            string path = photo.DefaultVersion.Uri.LocalPath;
 
             Tag [] tags = photo.Tags;
             string [] names = new string [tags.Length];
 
             for (int i = 0; i < tags.Length; i++)
                 names [i] = tags [i].Name;
-	
-			using (FSpot.ImageFile img = FSpot.ImageFile.Create (photo.DefaultVersion.Uri)) {
-				if (img is FSpot.JpegFile) {
-					FSpot.JpegFile jimg = img as FSpot.JpegFile;
-				
-					jimg.SetDescription (photo.Description);
-					jimg.SetDateTimeOriginal (photo.Time);
-
-                    var meta = jimg.Metadata;
-                    meta.GetTag (TagLib.TagTypes.XMP, true);
-
-                    var tag = meta.ImageTag;
-                    tag.Keywords = names;
-                    tag.Rating = photo.Rating;
-	
-					jimg.SaveMetaData (path);
-				} else if (img is FSpot.Png.PngFile) {
-					FSpot.Png.PngFile png = img as FSpot.Png.PngFile;
-				
-					if (img.Description != photo.Description)
-						png.SetDescription (photo.Description);
-				
-					png.SetXmp (UpdateXmp (photo, png.GetXmp ()));
-	
-					png.Save (path);
-				}
-			}
-		}
-		
-		private static FSpot.Xmp.XmpFile UpdateXmp (FSpot.IBrowsableItem item, FSpot.Xmp.XmpFile xmp)
-		{
-			if (xmp == null) 
-				xmp = new FSpot.Xmp.XmpFile ();
-	
-			Tag [] tags = item.Tags;
-			string [] names = new string [tags.Length];
-			
-			for (int i = 0; i < tags.Length; i++)
-				names [i] = tags [i].Name;
-			
-			xmp.Store.Update ("dc:subject", "rdf:Bag", names);
-			if ((item as Photo).Rating > 0) {
-				xmp.Store.Update ("xmp:Rating", (item as Photo).Rating.ToString());
-				// FIXME - Should we also store/overwrite the Urgency field?
-				// uint urgency_value = (item as Photo).Rating + 1; // Urgency valid values 1 - 8
-				// xmp.Store.Update ("photoshop:Urgency", urgency_value.ToString());
-			} else {
-				xmp.Store.Delete ("xmp:Rating");
-			}
-			xmp.Dump ();
-	
-			return xmp;
-		}
-	}
+
+            //var res = new GIOTagLibFileAbstraction () { Uri = photo.DefaultVersion.Uri };
+            var res = photo.DefaultVersion.Uri.AbsolutePath;
+            using (var metadata = TagLib.File.Create (res) as TagLib.Image.File) {
+                metadata.GetTag (TagLib.TagTypes.XMP, true);
+
+                var tag = metadata.ImageTag;
+                tag.DateTime = photo.Time;
+                tag.Comment = photo.Description;
+                tag.Keywords = names;
+                tag.Rating = photo.Rating;
+                tag.Software = FSpot.Defines.PACKAGE + " version " + FSpot.Defines.VERSION;
+
+                SaveMetaData (metadata, path);
+            }
+        }
+    }
 }
diff --git a/src/Loaders/GdkImageLoader.cs b/src/Loaders/GdkImageLoader.cs
index 930f6ed..e88f7bf 100644
--- a/src/Loaders/GdkImageLoader.cs
+++ b/src/Loaders/GdkImageLoader.cs
@@ -15,6 +15,7 @@ using Gdk;
 using FSpot.Utils;
 using FSpot.Platform;
 using Hyena;
+using TagLib.Image;
 
 namespace FSpot.Loaders {
 	public class GdkImageLoader : Gdk.PixbufLoader, IImageLoader
@@ -37,7 +38,7 @@ namespace FSpot.Loaders {
 
 			//First, send a thumbnail if we have one
 			if ((thumb = XdgThumbnailSpec.LoadThumbnail (uri, ThumbnailSize.Large, null)) != null) {
-				pixbuf_orientation = PixbufOrientation.TopLeft;
+				pixbuf_orientation = ImageOrientation.TopLeft;
 				EventHandler<AreaPreparedEventArgs> prep = AreaPrepared;
 				if (prep != null)
 					prep (this, new AreaPreparedEventArgs (true));
@@ -84,8 +85,8 @@ namespace FSpot.Loaders {
 			get { return prepared; }
 		}
 
-		PixbufOrientation pixbuf_orientation = PixbufOrientation.TopLeft;
-		public PixbufOrientation PixbufOrientation {
+		ImageOrientation pixbuf_orientation = ImageOrientation.TopLeft;
+		public ImageOrientation PixbufOrientation {
 			get { return pixbuf_orientation; }
 		}
 
diff --git a/src/Loaders/IImageLoader.cs b/src/Loaders/IImageLoader.cs
index 3934547..19b2d73 100644
--- a/src/Loaders/IImageLoader.cs
+++ b/src/Loaders/IImageLoader.cs
@@ -13,6 +13,7 @@ using FSpot.Utils;
 using System;
 using Gdk;
 using Hyena;
+using TagLib.Image;
 
 namespace FSpot.Loaders {
 	public interface IImageLoader : IDisposable {
@@ -25,6 +26,6 @@ namespace FSpot.Loaders {
 		void Load (SafeUri uri);
 
 		Pixbuf Pixbuf { get; }
-		PixbufOrientation PixbufOrientation { get; }
+		ImageOrientation PixbufOrientation { get; }
 	}
 }
diff --git a/src/MetadataStore.cs b/src/MetadataStore.cs
index 8b646f0..3a65705 100644
--- a/src/MetadataStore.cs
+++ b/src/MetadataStore.cs
@@ -29,7 +29,7 @@ namespace FSpot {
 				new Description ("tiff:PlanarConfiguration", Catalog.GetString ("Planar Configuration"), 
 						 typeof (FSpot.Tiff.PlanarConfiguration)),
 				new Description ("tiff:Orientation", Catalog.GetString ("Orientation"), 
-						 typeof (PixbufOrientation)),
+						 typeof (TagLib.Image.ImageOrientation)),
 				new Description ("tiff:PhotometricInterpretation", Catalog.GetString ("Photometric Interpretation"), 
 						 typeof (FSpot.Tiff.PhotometricInterpretation)),
 				new Description ("tiff:ResolutionUnit", Catalog.GetString ("Resolution Unit"),
diff --git a/src/PhotoImageView.cs b/src/PhotoImageView.cs
index 465420c..e2aa723 100644
--- a/src/PhotoImageView.cs
+++ b/src/PhotoImageView.cs
@@ -18,6 +18,8 @@ using FSpot.Loaders;
 using Hyena;
 using Gdk;
 
+using TagLib.Image;
+
 namespace FSpot.Widgets {
 	public class PhotoImageView : ImageView {
 #region public API
@@ -241,7 +243,7 @@ namespace FSpot.Widgets {
 			if (loader.Pixbuf != null) //FIXME: this test in case the photo was loaded with the direct loader
 				PixbufOrientation = Accelerometer.GetViewOrientation (loader.PixbufOrientation);
 			else
-				PixbufOrientation = PixbufOrientation.TopLeft;
+				PixbufOrientation = ImageOrientation.TopLeft;
 
 			if (Pixbuf == null)
 				LoadErrorImage (null);
@@ -281,7 +283,7 @@ namespace FSpot.Widgets {
 			if (old != null)
 				old.Dispose ();
 
-			PixbufOrientation = PixbufOrientation.TopLeft;
+			PixbufOrientation = ImageOrientation.TopLeft;
 			ZoomFit (false);
 		}
 
diff --git a/src/PixbufUtils.cs b/src/PixbufUtils.cs
index 1bd2a26..2ab1044 100644
--- a/src/PixbufUtils.cs
+++ b/src/PixbufUtils.cs
@@ -17,6 +17,7 @@ using System.IO;
 using FSpot;
 using FSpot.Utils;
 using Hyena;
+using TagLib.Image;
 
 public class PixbufUtils {
 	static Pixbuf error_pixbuf = null;
@@ -76,7 +77,7 @@ public class PixbufUtils {
 		Gdk.PixbufLoader loader = new Gdk.PixbufLoader ();
 		int max_width;
 		int max_height;
-		PixbufOrientation orientation;
+		ImageOrientation orientation;
 
 		public AspectLoader (int max_width, int max_height) 
 		{
@@ -88,10 +89,10 @@ public class PixbufUtils {
 		private void HandleSizePrepared (object obj, SizePreparedArgs args)
 		{
 			switch (orientation) {
-			case PixbufOrientation.LeftTop:
-			case PixbufOrientation.LeftBottom:
-			case PixbufOrientation.RightTop:
-			case PixbufOrientation.RightBottom:	
+			case ImageOrientation.LeftTop:
+			case ImageOrientation.LeftBottom:
+			case ImageOrientation.RightTop:
+			case ImageOrientation.RightBottom:
 				int tmp = max_width;
 				max_width = max_height;
 				max_height = tmp;
@@ -109,7 +110,7 @@ public class PixbufUtils {
 				loader.SetSize (scale_width, scale_height);
 		}
 
-		public Pixbuf Load (System.IO.Stream stream, PixbufOrientation orientation)
+		public Pixbuf Load (System.IO.Stream stream, ImageOrientation orientation)
 		{
 			int count;
 			byte [] data = new byte [8192];
@@ -131,7 +132,7 @@ public class PixbufUtils {
 		{
 			try {
 				orientation = GetOrientation (path);
-				using (FileStream fs = File.OpenRead (path)) {
+				using (FileStream fs = System.IO.File.OpenRead (path)) {
 					return Load (fs, orientation);
 				}
 			} catch (Exception) {
@@ -642,7 +643,7 @@ public class PixbufUtils {
 	{
 		byte [] thumb_data = data.Data;
 		if (thumb_data.Length > 0) {
-			PixbufOrientation orientation = GetOrientation (data);
+			ImageOrientation orientation = GetOrientation (data);
 			
 			using (MemoryStream mem = new MemoryStream (thumb_data)) {
 				Gdk.Pixbuf thumb = new Gdk.Pixbuf (mem);
@@ -657,21 +658,21 @@ public class PixbufUtils {
 		return null;
 	}
 
-	public static PixbufOrientation GetOrientation (Exif.ExifData data)
+	public static ImageOrientation GetOrientation (Exif.ExifData data)
 	{
-		PixbufOrientation orientation = PixbufOrientation.TopLeft;
+		ImageOrientation orientation = ImageOrientation.TopLeft;
 		
 		Exif.ExifEntry e = data.GetContents (Exif.Ifd.Zero).Lookup (Exif.Tag.Orientation);
 
 		if (e != null) {
 			ushort [] value = e.GetDataUShort ();
-			orientation = (PixbufOrientation) value [0];
+			orientation = (ImageOrientation) value [0];
 		}
 
 		return orientation;
 	}
 
-	public static PixbufOrientation GetOrientation (SafeUri uri)
+	public static ImageOrientation GetOrientation (SafeUri uri)
 	{
 		using (FSpot.ImageFile img = FSpot.ImageFile.Create (uri)) {
 			return img.Orientation;
@@ -679,7 +680,7 @@ public class PixbufUtils {
 	}
 	
 	[Obsolete ("Use GetOrientation (SafeUri) instead")]
-	public static PixbufOrientation GetOrientation (string path)
+	public static ImageOrientation GetOrientation (string path)
 	{
         return GetOrientation (new SafeUri (path));
 	}
diff --git a/src/RotateCommand.cs b/src/RotateCommand.cs
index 23afa4c..7a15a6d 100644
--- a/src/RotateCommand.cs
+++ b/src/RotateCommand.cs
@@ -59,50 +59,46 @@ namespace FSpot {
 
 		private static void RotateOrientation (string original_path, RotateDirection direction)
 		{
-			using (FSpot.ImageFile img = FSpot.ImageFile.Create (new SafeUri (original_path))) {
-				if (img is JpegFile) {
-					FSpot.JpegFile jimg = img as FSpot.JpegFile;
-					PixbufOrientation orientation = direction == RotateDirection.Clockwise
-						? FSpot.Utils.PixbufUtils.Rotate90 (img.Orientation)
-						: FSpot.Utils.PixbufUtils.Rotate270 (img.Orientation);
-				
-					jimg.SetOrientation (orientation);
-					jimg.SaveMetaData (original_path);
-				} else if (img is PngFile) {
-					PngFile png = img as PngFile;
-					bool supported = false;
-
-					//FIXME there isn't much png specific here except the check
-					//the pixbuf is an accurate representation of the real file
-					//by checking the depth.  The check should be abstracted and
-					//this code made generic.
-					foreach (PngFile.Chunk c in png.Chunks) {
-						PngFile.IhdrChunk ihdr = c as PngFile.IhdrChunk;
-					
-						if (ihdr != null && ihdr.Depth == 8)
-							supported = true;
-					}
-
-					if (!supported) {
-						throw new RotateException (Catalog.GetString ("Unable to rotate this type of photo"), original_path);
-					}
-
-					string backup = ImageFile.TempPath (original_path);
-					using (Stream stream = File.Open (backup, FileMode.Truncate, FileAccess.Write)) {
-						using (Pixbuf pixbuf = img.Load ()) {
-							PixbufOrientation fake = (direction == RotateDirection.Clockwise) ? PixbufOrientation.RightTop : PixbufOrientation.LeftBottom;
-							using (Pixbuf rotated = FSpot.Utils.PixbufUtils.TransformOrientation (pixbuf, fake)) {
-								img.Save (rotated, stream);
-							}
-						}
-					}
-					File.Copy (backup, original_path, true);
-					File.Delete (backup);
-				} else {
-					throw new RotateException (Catalog.GetString ("Unable to rotate this type of photo"), original_path);
-				}
-			}
+            try {
+                var res = new GIOTagLibFileAbstraction () { Uri = new SafeUri (original_path) };
+                using (var metadata = TagLib.File.Create (res) as TagLib.Image.File) {
+                    var tag = metadata.ImageTag;
+                    var orientation = direction == RotateDirection.Clockwise
+                        ? FSpot.Utils.PixbufUtils.Rotate90 (tag.Orientation)
+                        : FSpot.Utils.PixbufUtils.Rotate270 (tag.Orientation);
+
+                    tag.Orientation = orientation;
+                    SaveMetaData (metadata, original_path);
+                }
+            } catch (Exception e) {
+                throw new RotateException (Catalog.GetString ("Unable to rotate this type of photo"), original_path);
+            }
 		}
+
+        private static void SaveMetaData (TagLib.File image, string path)
+        {
+            // FIXME: This currently copies the file out to a tmp file, overwrites it
+            // and restores the tmp file in case of failure. Should obviously be the
+            // other way around, but Taglib# doesn't have an interface to do this.
+            // https://bugzilla.gnome.org/show_bug.cgi?id=618768
+
+            var uri = new SafeUri (path);
+            var tmp = System.IO.Path.GetTempFileName ();
+            var tmp_uri = new SafeUri (tmp);
+
+            var orig_file = GLib.FileFactory.NewForUri (uri);
+            var tmp_file = GLib.FileFactory.NewForUri (tmp_uri);
+
+            tmp_file.Delete ();
+            orig_file.Copy (tmp_file, GLib.FileCopyFlags.AllMetadata | GLib.FileCopyFlags.Overwrite, null, null);
+
+            try {
+                image.Save ();
+            } catch (Exception e) {
+                tmp_file.Copy (orig_file, GLib.FileCopyFlags.AllMetadata | GLib.FileCopyFlags.Overwrite, null, null);
+                throw e;
+            }
+        }
 		       
 		private void Rotate (string original_path, RotateDirection dir)
 		{
diff --git a/src/Tests/UpdaterTests.cs b/src/Tests/UpdaterTests.cs
index 193eb56..a5529b7 100644
--- a/src/Tests/UpdaterTests.cs
+++ b/src/Tests/UpdaterTests.cs
@@ -67,6 +67,8 @@ namespace FSpot.Tests
             CheckPhotosTable (db);
             CheckPhotoVersionsTable (db);
             CheckTagsTable (db);
+
+            file2.Delete ();
         }
 
         private void ValidateRevision (QueuedSqliteDatabase db, string revision)
diff --git a/src/Utils/GIOTagLibFileAbstraction.cs b/src/Utils/GIOTagLibFileAbstraction.cs
index 7d79b6d..1f559a5 100644
--- a/src/Utils/GIOTagLibFileAbstraction.cs
+++ b/src/Utils/GIOTagLibFileAbstraction.cs
@@ -7,7 +7,7 @@ namespace FSpot.Utils
 {
     public sealed class GIOTagLibFileAbstraction : TagLib.File.IFileAbstraction
     {
-        private FileInputStream gio_stream;
+        private GioStream stream;
 
         public string Name {
             get {
@@ -22,23 +22,32 @@ namespace FSpot.Utils
 
         public Stream ReadStream {
             get {
-                if (gio_stream == null) {
-                    var file = FileFactory.NewForUri(Uri);
-                    gio_stream = file.Read (null);
+                if (stream == null) {
+                    var file = FileFactory.NewForUri (Uri);
+                    stream = new GioStream (file.Read (null));
                 }
-                return new GioStream (gio_stream);
+                return stream;
             }
         }
 
         public Stream WriteStream {
-            get { throw new NotImplementedException (); }
+            get {
+                if (stream == null) {
+                    var file = FileFactory.NewForUri (Uri);
+                    stream = new GioStream (file.ReplaceReadwrite (null, true, FileCreateFlags.None, null));
+                }
+                if (!stream.CanWrite) {
+                    throw new Exception ("Stream still open in reading mode!");
+                }
+                return stream;
+            }
         }
 
         public void CloseStream (Stream stream)
         {
             stream.Close ();
-            gio_stream.Dispose ();
-            gio_stream = null;
+            if (stream == this.stream)
+                this.stream = null;
         }
     }
 }
diff --git a/src/Utils/Makefile.am b/src/Utils/Makefile.am
index facebf4..e8af1a6 100644
--- a/src/Utils/Makefile.am
+++ b/src/Utils/Makefile.am
@@ -11,7 +11,6 @@ SOURCES = \
 	GdkUtils.cs \
     GIOTagLibFileAbstraction.cs \
 	GtkUtil.cs \
-	PixbufOrientation.cs \
 	PixbufUtils.cs \
 	RecursiveFileEnumerator.cs \
 	SafeUri.cs \
@@ -20,6 +19,7 @@ SOURCES = \
 	UriExtensions.cs \
 	UriUtils.cs \
 	XdgThumbnailSpec.cs \
+	Tests/GIOTagLibFileAbstractionTests.cs \
 	Tests/SafeUriTests.cs \
 	Tests/XdgThumbnailSpecTests.cs
 
diff --git a/src/Utils/PixbufUtils.cs b/src/Utils/PixbufUtils.cs
index ad611ef..933769b 100644
--- a/src/Utils/PixbufUtils.cs
+++ b/src/Utils/PixbufUtils.cs
@@ -12,29 +12,30 @@
 using Gdk;
 using System;
 using System.Runtime.InteropServices;
+using TagLib.Image;
 
 namespace FSpot.Utils
 {
 	public static class PixbufUtils
 	{
-		static public PixbufOrientation Rotate270 (PixbufOrientation orientation)
+		static public ImageOrientation Rotate270 (ImageOrientation orientation)
 		{
-			PixbufOrientation [] rot = new PixbufOrientation [] {
-				PixbufOrientation.LeftBottom, 
-				PixbufOrientation.LeftTop,
-				PixbufOrientation.RightTop,
-				PixbufOrientation.RightBottom, 
-				PixbufOrientation.BottomLeft,
-				PixbufOrientation.TopLeft,
-				PixbufOrientation.TopRight,
-				PixbufOrientation.BottomRight
+			ImageOrientation [] rot = new ImageOrientation [] {
+				ImageOrientation.LeftBottom,
+				ImageOrientation.LeftTop,
+				ImageOrientation.RightTop,
+				ImageOrientation.RightBottom,
+				ImageOrientation.BottomLeft,
+				ImageOrientation.TopLeft,
+				ImageOrientation.TopRight,
+				ImageOrientation.BottomRight
 			};
 	
 			orientation = rot [((int)orientation) -1];
 			return orientation;
 		}
 	
-		static public PixbufOrientation Rotate90 (PixbufOrientation orientation)
+		static public ImageOrientation Rotate90 (ImageOrientation orientation)
 		{
 			orientation = Rotate270 (orientation);
 			orientation = Rotate270 (orientation);
@@ -42,45 +43,45 @@ namespace FSpot.Utils
 			return orientation;
 		}
 
-		public static Rectangle TransformOrientation (Pixbuf src, Rectangle args, PixbufOrientation orientation)
+		public static Rectangle TransformOrientation (Pixbuf src, Rectangle args, ImageOrientation orientation)
 		{
 			return TransformOrientation (src.Width, src.Height, args, orientation);
 		}
 		
-		public static Rectangle TransformOrientation (int total_width, int total_height, Rectangle args, PixbufOrientation orientation)
+		public static Rectangle TransformOrientation (int total_width, int total_height, Rectangle args, ImageOrientation orientation)
 		{
 			Rectangle area = args;
 			
 			switch (orientation) {
-			case PixbufOrientation.BottomRight:
+			case ImageOrientation.BottomRight:
 				area.X = total_width - args.X - args.Width;
 				area.Y = total_height - args.Y - args.Height;
 				break;
-			case PixbufOrientation.TopRight:
+			case ImageOrientation.TopRight:
 				area.X = total_width - args.X - args.Width;
 				break;
-			case PixbufOrientation.BottomLeft:
+			case ImageOrientation.BottomLeft:
 				area.Y = total_height - args.Y - args.Height;
 				break;
-			case PixbufOrientation.LeftTop:
+			case ImageOrientation.LeftTop:
 				area.X = args.Y;
 				area.Y = args.X;
 				area.Width = args.Height;
 				area.Height = args.Width;
 				break;
-			case PixbufOrientation.RightBottom:
+			case ImageOrientation.RightBottom:
 				area.X = total_height - args.Y - args.Height;
 				area.Y = total_width - args.X - args.Width;
 				area.Width = args.Height;
 				area.Height = args.Width;
 				break;
-			case PixbufOrientation.RightTop:
+			case ImageOrientation.RightTop:
 				area.X = total_height - args.Y - args.Height;
 				area.Y = args.X;
 				area.Width = args.Height;
 				area.Height = args.Width;
 				break;
-			case PixbufOrientation.LeftBottom:
+			case ImageOrientation.LeftBottom:
 				area.X = args.Y;
 				area.Y = total_width - args.X - args.Width;
 				area.Width = args.Height;
@@ -93,37 +94,37 @@ namespace FSpot.Utils
 			return area;
 		}
 
-		public static Point TransformOrientation (int total_width, int total_height, Point args, PixbufOrientation orientation)
+		public static Point TransformOrientation (int total_width, int total_height, Point args, ImageOrientation orientation)
 		{
 			Point p = args;
 
 			switch (orientation) {
 			default:
-			case PixbufOrientation.TopLeft:
+			case ImageOrientation.TopLeft:
 				break;
-			case PixbufOrientation.TopRight:
+			case ImageOrientation.TopRight:
 				p.X = total_width - p.X;
 				break;
-			case PixbufOrientation.BottomRight:
+			case ImageOrientation.BottomRight:
 				p.X = total_width - p.X;
 				p.Y = total_height - p.Y;
 				break;
-			case PixbufOrientation.BottomLeft:
+			case ImageOrientation.BottomLeft:
 				p.Y = total_height - p.Y;
 				break;
-			case PixbufOrientation.LeftTop:
+			case ImageOrientation.LeftTop:
 				p.X = args.Y;
 				p.Y = args.X;
 				break;
-			case PixbufOrientation.RightTop:
+			case ImageOrientation.RightTop:
 				p.X = total_height - args.Y;
 				p.Y = args.X;
 				break;
-			case PixbufOrientation.RightBottom:
+			case ImageOrientation.RightBottom:
 				p.X = total_height - args.Y;
 				p.Y = total_width - args.X;
 				break;
-			case PixbufOrientation.LeftBottom:
+			case ImageOrientation.LeftBottom:
 				p.X = args.Y;
 				p.Y = total_width - args.X;
 				break;
@@ -131,58 +132,58 @@ namespace FSpot.Utils
 			return p;
 		}
 
-		public static PixbufOrientation ReverseTransformation (PixbufOrientation orientation)
+		public static ImageOrientation ReverseTransformation (ImageOrientation orientation)
 		{
 			switch (orientation) {
 			default:
-			case PixbufOrientation.TopLeft:
-			case PixbufOrientation.TopRight:
-			case PixbufOrientation.BottomRight:
-			case PixbufOrientation.BottomLeft:
+			case ImageOrientation.TopLeft:
+			case ImageOrientation.TopRight:
+			case ImageOrientation.BottomRight:
+			case ImageOrientation.BottomLeft:
 				return orientation;
-			case PixbufOrientation.LeftTop:
-				return PixbufOrientation.RightBottom;
-			case PixbufOrientation.RightTop:
-				return PixbufOrientation.LeftBottom;
-			case PixbufOrientation.RightBottom:
-				return PixbufOrientation.LeftTop;
-			case PixbufOrientation.LeftBottom:
-				return PixbufOrientation.RightTop;
+			case ImageOrientation.LeftTop:
+				return ImageOrientation.RightBottom;
+			case ImageOrientation.RightTop:
+				return ImageOrientation.LeftBottom;
+			case ImageOrientation.RightBottom:
+				return ImageOrientation.LeftTop;
+			case ImageOrientation.LeftBottom:
+				return ImageOrientation.RightTop;
 			}
 		}
 
-		public static Pixbuf TransformOrientation (Pixbuf src, PixbufOrientation orientation)
+		public static Pixbuf TransformOrientation (Pixbuf src, ImageOrientation orientation)
 		{
 			Pixbuf dest;
 
 			switch (orientation) {
 			default:
-			case PixbufOrientation.TopLeft:
+			case ImageOrientation.TopLeft:
 				dest = PixbufUtils.ShallowCopy (src);
 				break;
-			case PixbufOrientation.TopRight:
+			case ImageOrientation.TopRight:
 				dest = src.Flip (false);
 				break;
-			case PixbufOrientation.BottomRight:
+			case ImageOrientation.BottomRight:
 				dest = src.RotateSimple (PixbufRotation.Upsidedown);
 				break;
-			case PixbufOrientation.BottomLeft:
+			case ImageOrientation.BottomLeft:
 				dest = src.Flip (true);
 				break;
-			case PixbufOrientation.LeftTop:
+			case ImageOrientation.LeftTop:
 				using (var rotated = src.RotateSimple (PixbufRotation.Clockwise)) {
 					dest = rotated.Flip (false);
 				}
 				break;
-			case PixbufOrientation.RightTop:
+			case ImageOrientation.RightTop:
 				dest = src.RotateSimple (PixbufRotation.Clockwise);
 				break;
-			case PixbufOrientation.RightBottom:
+			case ImageOrientation.RightBottom:
 				using (var rotated = src.RotateSimple (PixbufRotation.Counterclockwise)) {
 					dest = rotated.Flip (false);
 				}
 				break;
-			case PixbufOrientation.LeftBottom:
+			case ImageOrientation.LeftBottom:
 				dest = src.RotateSimple (PixbufRotation.Counterclockwise);
 				break;
 			}
diff --git a/src/Utils/Tests/GIOTagLibFileAbstractionTests.cs b/src/Utils/Tests/GIOTagLibFileAbstractionTests.cs
new file mode 100644
index 0000000..ed2d965
--- /dev/null
+++ b/src/Utils/Tests/GIOTagLibFileAbstractionTests.cs
@@ -0,0 +1,132 @@
+#if ENABLE_TESTS
+using NUnit.Framework;
+using System;
+using Hyena;
+using TagLib;
+using TagLib.IFD;
+using TagLib.IFD.Entries;
+using TagLib.IFD.Tags;
+using TagLib.Xmp;
+
+namespace FSpot.Utils.Tests
+{
+    // This is a trimmed down test case from Taglib# to test the file abstraction.
+    [TestFixture]
+    public class GIOTagLibFileAbstractionTests
+    {
+        static bool initialized = false;
+        static void Initialize () {
+            GLib.GType.Init ();
+            initialized = true;
+        }
+
+        [Test]
+        public void StraightIOTest ()
+        {
+            var uri = CreateTempFile ();
+
+            var file = File.Create (uri.AbsolutePath) as TagLib.Image.File;
+            Assert.IsTrue (file != null);
+
+            Validate (file);
+            ChangeMetadata (file);
+
+            file = File.Create (uri.AbsolutePath) as TagLib.Image.File;
+            Assert.IsTrue (file != null);
+
+            Validate (file);
+            ValidateChangedMetadata (file);
+
+            DeleteTempFile (uri);
+        }
+
+        [Test]
+        public void GIOTest ()
+        {
+            var uri = CreateTempFile ();
+
+            var res = new GIOTagLibFileAbstraction () { Uri = uri };
+
+            var file = File.Create (res) as TagLib.Image.File;
+            Assert.IsTrue (file != null);
+
+            Validate (file);
+            ChangeMetadata (file);
+
+            file = File.Create (res) as TagLib.Image.File;
+            Assert.IsTrue (file != null);
+
+            Validate (file);
+            ValidateChangedMetadata (file);
+
+            DeleteTempFile (uri);
+        }
+
+        private SafeUri CreateTempFile ()
+        {
+            if (!initialized)
+                Initialize ();
+
+            var uri = new SafeUri (Environment.CurrentDirectory + "/../tests/data/taglib-sample.jpg");
+            var file = GLib.FileFactory.NewForUri (uri);
+
+            var tmp = System.IO.Path.GetTempFileName ()+".jpg"; // hack!
+            var uri2 = new SafeUri (tmp);
+            var file2 = GLib.FileFactory.NewForUri (uri2);
+            file.Copy (file2, GLib.FileCopyFlags.Overwrite, null, null);
+            return uri2;
+        }
+
+        private void DeleteTempFile (SafeUri uri)
+        {
+            var file = GLib.FileFactory.NewForUri (uri);
+            file.Delete ();
+        }
+
+        private void Validate (TagLib.Image.File file)
+        {
+            // Note: these don't correspond to the image data, only to the metadata. We hacked the file for size.
+			Assert.AreEqual (2000, file.Properties.PhotoWidth);
+			Assert.AreEqual (3008, file.Properties.PhotoHeight);
+			Assert.AreEqual (96, file.Properties.PhotoQuality);
+
+			var tag = file.GetTag (TagTypes.TiffIFD) as IFDTag;
+			Assert.IsNotNull (tag, "IFD tag not found");
+
+			var structure = tag.Structure;
+
+			// Image.0x010F (Make/Ascii/18) "NIKON CORPORATION"
+			{
+				var entry = structure.GetEntry (0, (ushort) IFDEntryTag.Make);
+				Assert.IsNotNull (entry, "Entry 0x010F missing in IFD 0");
+				Assert.IsNotNull (entry as StringIFDEntry, "Entry is not a string!");
+				Assert.AreEqual ("NIKON CORPORATION", (entry as StringIFDEntry).Value);
+			}
+
+			XmpTag xmp = file.GetTag (TagTypes.XMP) as XmpTag;
+			// Xmp.MicrosoftPhoto_1_.DateAcquired (XmpText/20) "2009-08-04T20:42:36Z"
+			{
+				var node = xmp.NodeTree;
+				node = node.GetChild (XmpTag.MS_PHOTO_NS, "DateAcquired");
+				Assert.IsNotNull (node);
+				Assert.AreEqual ("2009-08-04T20:42:36Z", node.Value);
+				Assert.AreEqual (XmpNodeType.Simple, node.Type);
+				Assert.AreEqual (0, node.Children.Count);
+			}
+        }
+
+        private void ChangeMetadata (TagLib.Image.File file)
+        {
+            file.ImageTag.Comment = "Testing!";
+            file.ImageTag.Keywords = new string [] { "One", "Two", "Three" };
+            file.Save ();
+        }
+
+        private void ValidateChangedMetadata (TagLib.Image.File file)
+        {
+            Assert.AreEqual ("Testing!", file.ImageTag.Comment);
+            Assert.AreEqual (new string [] { "One", "Two", "Three" }, file.ImageTag.Keywords);
+        }
+    }
+}
+#endif
diff --git a/src/Widgets/ImageView.cs b/src/Widgets/ImageView.cs
index 4b7682c..8796ee9 100644
--- a/src/Widgets/ImageView.cs
+++ b/src/Widgets/ImageView.cs
@@ -15,6 +15,7 @@ using Gtk;
 using Gdk;
 
 using FSpot.Utils;
+using TagLib.Image;
 
 namespace FSpot.Widgets
 {
@@ -61,8 +62,8 @@ namespace FSpot.Widgets
 			} 
 		}
 
-		PixbufOrientation pixbuf_orientation;
-		public PixbufOrientation PixbufOrientation {
+		ImageOrientation pixbuf_orientation;
+		public ImageOrientation PixbufOrientation {
 			get { return pixbuf_orientation; }
 			set {
 				if (value == pixbuf_orientation)
@@ -688,7 +689,7 @@ namespace FSpot.Widgets
 			if (zoom == 1.0 &&
 			    !Pixbuf.HasAlpha &&
 			    Pixbuf.BitsPerSample == 8 &&
-			    pixbuf_orientation == PixbufOrientation.TopLeft) {
+			    pixbuf_orientation == ImageOrientation.TopLeft) {
 				GdkWindow.DrawPixbuf (Style.BlackGC,
 						      Pixbuf,
 						      area.X - x_offset, area.Y - y_offset,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c4a60be..26b39c5 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -4,7 +4,8 @@ EXTRA_DIST = \
 	data/f-spot-0.6.1.5.db \
 	data/f-spot-0.6.2.db \
 	data/f-spot-0.7.0-17.2.db \
-	data/f-spot-0.7.0-18.0.db
+	data/f-spot-0.7.0-18.0.db \
+	data/taglib-sample.jpg
 
 if ENABLE_TESTS
 
diff --git a/tests/data/taglib-sample.jpg b/tests/data/taglib-sample.jpg
new file mode 100644
index 0000000..96955e7
Binary files /dev/null and b/tests/data/taglib-sample.jpg differ



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]