Various wobbly patches



Hello,

I've been sorting my holidays pictures in f-spot and exporting them to a
webpage, and here are a few changes/additions I had to apply.
I'll try to list them here, before I forget about them, in case someone
find them usefull.
(Disclaimer: I'm new to c#, f-spot, gtk2/gnome, exif ...)
(Disclaimer2: I made a big diff against latest cvs from my version
-maybe containing patches from other people. jimmac's static-html
improvement for sure- and tried to split the differences by hand. so
maybe the patches won't work? )



- build fixes (using latest mono / f-spot  svn/cvs versions) - I didn't
exactly try to understand what was going on, just made it compile for
me..
-> build.txt



- I had various crashes, and issues (maybe triggered by other changes
from me)
-> fixes,workarounds.txt
Notably, there is a big problem with the reload triggered on every
slight changes to the photo. Alas, I didn't fix it, just increased the
timeout when typing comments. And in the end (every tag changed
triggered a reload of the photo!) I just commented it out...
And there's also one bug about jpeg import that didn't try hard enough
to find the exif date.


- A simple menu entry to set the selection to all the pictures in the db
not on disk. (eventually leading to a "remove from db" for me...)
-> SelectInvalid.txt



- A System to update the dates of some photos.
-> AdjustDate.txt
On disk I sort the pics in folders according to the date/occasion they
were taken. But at some point, I add pictures from friends who doesn't
set their camera dates. Or I stitch my panoramas. -> all this produces
photos in the same directories, but without the correct date.
So I added a way to alter the dates of the photos from the current
selection. Either by setting it to some value, or computing it from the
other "good" photos in the directories around them so that they at least
appear next to the "good" ones in the time line.
*** I think there is some issue with UniversalTime in the patch, the
date written in the exif maybe wrong whereas the one in the db seems
correct ***



- And I also updated the FolderExport to better please me. (better
resizing when there are panoramas, keeping the exif info correct,
keeping the photos light...)
-> export.txt


**********

Some random thoughts:
- The whole philosophy of whether f-spot wants update the db from the
photos on disk or the photos from db seems a bit fuzzy.
I think there should be a checkbox some where: "everything I change
should be applied to the jpgs: yes/no"
And a menu option "refresh db from files" -> mark the photos no longer
existing on disk, rebuild the thumbnails, re-read the dates..

- The labels/category :  why is there a distinction? I always use
category, in case I want to subclass someday..
And the list on the left is too long.. I'd be cool to be able to use the
small icons.

- Too many photos: I miss separations in the icon view. In my case, I'd
like to have groups / separators according to the folders on disk.

- More complex queries. I think a 3 states button (instead of a
checkbox) per tag would suit me (ie simple to use, yet powerful
enough):
"no / may / must"  display all the photos with the all "must" tags and
at least one "may" tag (if any).

- A more precise "dirty" when updating the photos, to avoid reloading
them for every change.

- consistent use of gnomevfs vs system.file : never quite clear to me
what was wanted / what was possible.

- Lack of debugger. I couldn't find a way to debug/trace. Is there a
MonoDevelop solution somewhere? and/or how does mdb work?
In the end, I just used System.Console...
But there is sometimes a freeze, and I have no clue how to break in see
where the code is locked..



xavier. - ok, next time I split up in several mails.. ;)




Index: configure.in
===================================================================
RCS file: /cvs/gnome/f-spot/configure.in,v
retrieving revision 1.68
diff -u -p -r1.68 configure.in
--- configure.in	7 Jul 2005 16:31:25 -0000	1.68
+++ configure.in	25 Jul 2005 23:34:45 -0000
@@ -54,7 +54,7 @@ dnl -- this check is 	
 LCMS_REQUIRED=1.12
 dnl -- LIBGPHOTO2_REQUIRED=2.1.4
 
-PKG_CHECK_MODULES(F, libgnome-2.0 >= $LIBGNOME_REQUIRED libgnomeui-2.0 >= $LIBGNOMEUI_REQUIRED libexif >= $LIBEXIF_REQUIRED_MIN libexif < $LIBEXIF_REQUIRED_MAX gtkhtml-sharp >= $GTKSHARP_REQUIRED gconf-sharp >= $GTKSHARP_REQUIRED glade-sharp >= $GTKSHARP_REQUIRED gtk+-2.0 >= 2.4)
+PKG_CHECK_MODULES(F, libgnome-2.0 >= $LIBGNOME_REQUIRED libgnomeui-2.0 >= $LIBGNOMEUI_REQUIRED libexif >= $LIBEXIF_REQUIRED_MIN libexif < $LIBEXIF_REQUIRED_MAX gtkhtml-sharp-2.0 >= $GTKSHARP_REQUIRED gconf-sharp-2.0 >= $GTKSHARP_REQUIRED glade-sharp-2.0 >= $GTKSHARP_REQUIRED gtk+-2.0 >= 2.4)
 AC_SUBST(F_CFLAGS)
 AC_SUBST(F_LIBS)
 
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/f-spot/src/Makefile.am,v
retrieving revision 1.34
diff -u -p -r1.34 Makefile.am
--- src/Makefile.am	2 Jul 2005 06:52:16 -0000	1.34
+++ src/Makefile.am	25 Jul 2005 23:34:47 -0000
@@ -92,74 +92,8 @@ F_SPOT_CSDISTFILES =				\
 	$(srcdir)/CameraSelectionDialog.cs	\
 	$(srcdir)/CameraFileSelectionDialog.cs	\
 	$(srcdir)/TagSelectionDialog.cs		\
-	$(srcdir)/main.cs			\
-						\
-	$(srcdir)/gnomevfs/Gnome.VfsSharp.voidObjectObjectSignal.cs	\
-	$(srcdir)/gnomevfs/Gnome.VfsSharp.voidObjectSignal.cs	\
-	$(srcdir)/gnomevfs/ObjectManager.cs			\
-	$(srcdir)/gnomevfs/Async.cs				\
-	$(srcdir)/gnomevfs/AsyncCallback.cs			\
-	$(srcdir)/gnomevfs/AsyncCallbackNative.cs		\
-	$(srcdir)/gnomevfs/AsyncDirectoryLoadCallback.cs	\
-	$(srcdir)/gnomevfs/AsyncDirectoryLoadCallbackNative.cs	\
-	$(srcdir)/gnomevfs/AsyncReadCallback.cs			\
-	$(srcdir)/gnomevfs/AsyncReadCallbackNative.cs		\
-	$(srcdir)/gnomevfs/AsyncWriteCallback.cs		\
-	$(srcdir)/gnomevfs/AsyncWriteCallbackNative.cs		\
-	$(srcdir)/gnomevfs/Directory.cs				\
-	$(srcdir)/gnomevfs/FileFlags.cs				\
-	$(srcdir)/gnomevfs/FileInfo.cs				\
-	$(srcdir)/gnomevfs/FileInfoFields.cs			\
-	$(srcdir)/gnomevfs/FileInfoOptions.cs			\
-	$(srcdir)/gnomevfs/FilePermissions.cs			\
-	$(srcdir)/gnomevfs/FileType.cs				\
-	$(srcdir)/gnomevfs/Handle.cs				\
-	$(srcdir)/gnomevfs/MimeType.cs				\
-	$(srcdir)/gnomevfs/MimeActionType.cs			\
-	$(srcdir)/gnomevfs/MimeAction.cs			\
-	$(srcdir)/gnomevfs/MimeApplication.cs			\
-	$(srcdir)/gnomevfs/MimeApplicationArgumentType.cs	\
-	$(srcdir)/gnomevfs/ModuleCallback.cs			\
-	$(srcdir)/gnomevfs/ModuleCallbackAuthentication.cs	\
-	$(srcdir)/gnomevfs/ModuleCallbackFullAuthenticationFlags.cs	\
-	$(srcdir)/gnomevfs/ModuleCallbackFillAuthentication.cs	\
-	$(srcdir)/gnomevfs/ModuleCallbackFullAuthentication.cs	\
-	$(srcdir)/gnomevfs/ModuleCallbackSaveAuthentication.cs	\
-	$(srcdir)/gnomevfs/ModuleCallbackStatusMessage.cs	\
-	$(srcdir)/gnomevfs/Monitor.cs				\
-	$(srcdir)/gnomevfs/MonitorType.cs			\
-	$(srcdir)/gnomevfs/OpenMode.cs				\
-	$(srcdir)/gnomevfs/Result.cs				\
-	$(srcdir)/gnomevfs/SeekPosition.cs			\
-	$(srcdir)/gnomevfs/SetFileInfoMask.cs			\
-	$(srcdir)/gnomevfs/Sync.cs				\
-	$(srcdir)/gnomevfs/Vfs.cs				\
-	$(srcdir)/gnomevfs/Volume.cs				\
-	$(srcdir)/gnomevfs/VolumeMonitor.cs			\
-	$(srcdir)/gnomevfs/Drive.cs				\
-	$(srcdir)/gnomevfs/DriveConnectedHandler.cs		\
-	$(srcdir)/gnomevfs/DriveDisconnectedHandler.cs		\
-	$(srcdir)/gnomevfs/DeviceType.cs			\
-	$(srcdir)/gnomevfs/VolumeType.cs			\
-	$(srcdir)/gnomevfs/VolumePreUnmountHandler.cs		\
-	$(srcdir)/gnomevfs/VolumeUnmountedHandler.cs		\
-	$(srcdir)/gnomevfs/VolumeMountedHandler.cs		\
-	$(srcdir)/gnomevfs/Uri.cs				\
-	$(srcdir)/gnomevfs/UriHideOptions.cs			\
-	$(srcdir)/gnomevfs/VfsException.cs			\
-	$(srcdir)/gnomevfs/VfsStream.cs				\
-	$(srcdir)/gnomevfs/VfsStreamAsyncResult.cs		\
-	$(srcdir)/gnomevfs/XferErrorAction.cs			\
-	$(srcdir)/gnomevfs/XferOverwriteAction.cs		\
-	$(srcdir)/gnomevfs/Xfer.cs				\
-	$(srcdir)/gnomevfs/XferPhase.cs				\
-	$(srcdir)/gnomevfs/XferOptions.cs			\
-	$(srcdir)/gnomevfs/XferErrorMode.cs			\
-	$(srcdir)/gnomevfs/XferOverwriteMode.cs			\
-	$(srcdir)/gnomevfs/XferProgressCallback.cs		\
-	$(srcdir)/gnomevfs/XferProgressInfo.cs			\
-	$(srcdir)/gnomevfs/XferProgressStatus.cs		\
-	$(srcdir)/gnomevfs/XferProgressCallbackNative.cs
+	$(srcdir)/main.cs
+	
 
 
 
@@ -170,9 +104,9 @@ ASSEMBLIES =					\
 	-r:Mono.Data.SqliteClient		\
 	-r:Mono.Posix				\
 	-r:ICSharpCode.SharpZipLib		\
-	-pkg:gtkhtml-sharp			\
-	-pkg:glade-sharp			\
-	-pkg:gconf-sharp
+	-pkg:gtkhtml-sharp-2.0			\
+	-pkg:glade-sharp-2.0			\
+	-pkg:gconf-sharp-2.0
 
 RESOURCES =										\
 	-resource:$(top_srcdir)/icons/f-spot-browse.png,f-spot-browse.png		\


Index: src/Exif.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/Exif.cs,v
retrieving revision 1.13
diff -u -p -r1.13 Exif.cs
--- src/Exif.cs	14 May 2005 09:38:49 -0000	1.13
+++ src/Exif.cs	25 Jul 2005 23:34:46 -0000
@@ -909,14 +909,18 @@ namespace Exif {
 			set {
 				unsafe {
 					_ExifData * obj = (_ExifData *) Handle.Handle;
-					if (value.Length > 65533)
+					if (value != null && value.Length > 65533)
 						throw new System.Exception ("Thumbnail too large");
 					
-					if (obj->data != IntPtr.Zero)
+					if (obj->data != IntPtr.Zero) {
 						free (obj->data);
+						obj->data = IntPtr.Zero;
+					}
 					
-					obj->data = malloc ((uint)value.Length);
-					Marshal.Copy (value, 0, obj->data, value.Length);
+					if (value != null) {
+						obj->data = malloc ((uint)value.Length);
+						Marshal.Copy (value, 0, obj->data, value.Length);
+					}
 				}
 			}
 		}

Index: src/JpegFile.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/JpegFile.cs,v
retrieving revision 1.9
diff -u -p -r1.9 JpegFile.cs
--- src/JpegFile.cs	2 Jun 2005 22:12:20 -0000	1.9
+++ src/JpegFile.cs	25 Jul 2005 23:34:47 -0000
@@ -58,7 +58,7 @@ namespace FSpot {
 
 			//this.ExifData.Dump ();
 
-#if true //USE_UNSTABLE_JPEG_HEADER_CODE
+#if false //USE_UNSTABLE_JPEG_HEADER_CODE
 			string  temp_path = path;
 			using (System.IO.FileStream stream = System.IO.File.OpenRead (path)) {
 				JpegHeader header = new JpegHeader (stream);

Index: src/PixbufUtils.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PixbufUtils.cs,v
retrieving revision 1.57
diff -u -p -r1.57 PixbufUtils.cs
--- src/PixbufUtils.cs	14 Jun 2005 14:34:16 -0000	1.57
+++ src/PixbufUtils.cs	25 Jul 2005 23:34:48 -0000
@@ -354,10 +369,17 @@ class PixbufUtils {
 
 	public static void SaveAtomic (Gdk.Pixbuf src, string filename, string type, string [] keys, string [] values)
 	{
-			string tmpname = filename + ".tmp";
-			src.Savev (tmpname, type, keys, values);
-			if (rename (tmpname, filename) < 0)
-				throw new Exception ("Error renaming file");
+		string tmpname = filename + ".tmp";
+
+		// Savev seamed to crash with null or empty pointers
+		if (keys == null || keys.Length == 0)
+			keys = new string[1];
+		if (values == null || values.Length == 0)
+			values = new string[1];
+
+		src.Savev (tmpname, type, keys, values);
+		if (rename (tmpname, filename) < 0)
+			throw new Exception ("Error renaming file");
 	}
 
 	public static Gdk.Pixbuf ScaleToAspect (Gdk.Pixbuf orig, int width, int height)

Index: src/PhotoImageView.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PhotoImageView.cs,v
retrieving revision 1.44
diff -u -p -r1.44 PhotoImageView.cs
--- src/PhotoImageView.cs	25 Jun 2005 20:50:31 -0000	1.44
+++ src/PhotoImageView.cs	25 Jul 2005 23:34:47 -0000
@@ -73,8 +73,9 @@ namespace FSpot {
 
 		public void HandleQueryItemChanged (IBrowsableCollection browsable, int item)
 		{
-			if (item == Item.Index)
-				Reload ();
+			/*if (item == Item.Index)
+				Reload ();*/
+			// reload slow and not needed. It should only be done when changing image data...
 		}
 
 		// Display.
Index: src/PhotoView.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PhotoView.cs,v
retrieving revision 1.60
diff -u -p -r1.60 PhotoView.cs
--- src/PhotoView.cs	22 Jun 2005 15:41:50 -0000	1.60
+++ src/PhotoView.cs	25 Jul 2005 23:34:48 -0000
@@ -375,7 +375,7 @@ public class PhotoView : EventBox {
 		this.query = query;
 		this.photo_store = photo_store;
 
-		description_delay = new FSpot.Delay (1000, new GLib.IdleHandler (CommitPendingChanges));
+		description_delay = new FSpot.Delay (10000, new GLib.IdleHandler (CommitPendingChanges));
 		this.Destroyed += HandleDestroy;


Index: src/MainWindow.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/MainWindow.cs,v
retrieving revision 1.202
diff -u -p -r1.202 MainWindow.cs
--- src/MainWindow.cs	18 Jun 2005 22:07:10 -0000	1.202
+++ src/MainWindow.cs	25 Jul 2005 23:34:47 -0000
@@ -1548,6 +1569,15 @@ public class MainWindow {
 		icon_view.Selection.Clear ();
 	}
 	
+	public void HandleSelectInvalidCommand (object sender, EventArgs args)
+	{
+		icon_view.Selection.Clear ();
+		foreach (Photo p in query.Photos) {
+			if (!System.IO.File.Exists(p.Path))
+				icon_view.Selection.Add (p);
+		}
+	}
+	
 	public void HandleDeleteSelectedTagCommand (object sender, EventArgs args)
 	{
 		Tag [] tags = this.tag_selection_widget.TagHighlight ();

Index: src/f-spot.glade
===================================================================
RCS file: /cvs/gnome/f-spot/src/f-spot.glade,v
retrieving revision 1.104
diff -u -p -r1.104 f-spot.glade
--- src/f-spot.glade	27 Jun 2005 08:06:00 -0000	1.104
+++ src/f-spot.glade	25 Jul 2005 23:34:52 -0000
@@ -6785,6 +6785,15 @@ Photo Details</property>
 		  </child>
 
 		  <child>
+		    <widget class="GtkMenuItem" id="select_invalid">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Select Invalid</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="HandleSelectInvalidCommand" last_modification_time="Sat, 23 Jul 2005 21:35:35 GMT"/>
+		    </widget>
+		  </child>
+
+		  <child>
 		    <widget class="GtkSeparatorMenuItem" id="separator13">
 		      <property name="visible">True</property>
 		    </widget>


Index: src/DateCommands.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/DateCommands.cs,v
retrieving revision 1.5
diff -u -p -r1.5 DateCommands.cs
--- src/DateCommands.cs	17 Feb 2005 05:53:06 -0000	1.5
+++ src/DateCommands.cs	25 Jul 2005 23:34:46 -0000
@@ -4,6 +4,8 @@
 
 using Gtk;
 using Gnome;
+using System;
+using System.Collections;
 
 public class DateCommands {
 	public class Set : FSpot.GladeDialog {
@@ -43,4 +45,151 @@ public class DateCommands {
 			return success;
 		}
 	}
+	
+	public class Adjust : FSpot.GladeDialog {
+		PhotoStore photo_store;
+		Photo[] selected_photos;
+		Gtk.Window parent_window;
+
+		[Glade.Widget] private Button ok_button;
+		[Glade.Widget] private DateEdit forced_dateedit;
+		[Glade.Widget] private ComboBox mode_combobox;
+		[Glade.Widget] private CheckButton update_exif_check;
+
+		public Adjust (PhotoStore photo_store, Gtk.Window parent_window, Photo[] selected_photos)
+		{
+			this.photo_store = photo_store;
+			this.parent_window = parent_window;
+			this.selected_photos = selected_photos;
+		}
+
+		private delegate DateTime ComputeDate(Photo photo);
+		
+		private DateTime ForcedDate(Photo photo) 
+		{
+			return forced_dateedit.Time;
+		}
+		
+		private DateTime ComputeDateFromNeighbours(Photo photo)
+		{
+			ArrayList relevant_dates = new ArrayList();
+			
+			// find in the DB all the images with the same path.
+			System.IO.DirectoryInfo Dir = new System.IO.DirectoryInfo(photo.DirectoryPath);
+			bool recurse = false;
+			do {
+				Photo[] photos = photo_store.Query(Dir, recurse);
+				foreach (Photo p in photos) {
+					if (Array.IndexOf(selected_photos, p) >= 0) {
+						// we are trying to fix those photos,
+						// so they aren't any good for us.
+						continue;
+					}
+					
+					relevant_dates.Add(p.Time);
+				}
+				
+				if (relevant_dates.Count == 0) {
+					System.Console.Write("not found, ");
+					// if we haven't found any relevant info, broaden our search.
+					if (! recurse) {
+						// 1st step: look in subfolders if any.
+						System.Console.WriteLine("recurse");
+						recurse = true;
+					} else {
+						// 2nd step: look in the parent folder.
+						Dir = Dir.Parent;
+						System.Console.WriteLine(" going up");
+					}
+				}
+			} while (relevant_dates.Count == 0 && Dir.Parent != null);
+			
+			if (relevant_dates.Count > 0) {
+				// pick the median
+				relevant_dates.Sort();
+				return (DateTime)relevant_dates[relevant_dates.Count/2];
+			} else {
+				return photo.Time;
+			}
+		}
+		
+		public bool Execute ()
+		{
+			// make sure we have some things to deal with.
+			if (selected_photos.Length == 0) {
+				return false;
+			}
+			
+			this.CreateDialog ("adjust_date_dialog");
+			
+			// define defaults
+			update_exif_check.Active = true;
+			mode_combobox.Active = 0;
+			
+			this.Dialog.DefaultResponse = ResponseType.Ok;
+			ResponseType response = (ResponseType) this.Dialog.Run ();
+
+			bool success = false;
+
+			if (response == ResponseType.Ok) {
+				ComputeDate compute_date = null;
+				if (mode_combobox.ActiveText == "Forced") {
+					compute_date = ForcedDate;
+					success = true;
+				} else if (mode_combobox.ActiveText == "By path") {
+					compute_date = ComputeDateFromNeighbours;
+					success = true;
+				}
+				
+				if (success && compute_date!=null) {
+					foreach (Photo photo in selected_photos) {							
+						DateTime date = compute_date(photo);
+												
+						if (update_exif_check.Active) {
+							uint [] version_ids = photo.VersionIds;
+							foreach (uint id in version_ids) {
+								string path = photo.GetVersionPath(id);
+								
+								FSpot.ImageFile img = FSpot.ImageFile.Create (path);
+								if (img is FSpot.JpegFile) {
+									FSpot.JpegFile jimg = img as FSpot.JpegFile;
+									jimg.SetDate(date);
+									jimg.SaveMetaData (path);
+								}
+							}
+						}
+						
+						// update DB
+						photo.Time = date;
+						photo_store.Commit(photo);
+					}
+				}
+			}
+			
+			this.Dialog.Destroy ();
+			return success;
+		}
+	}	
 }

Index: src/JpegFile.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/JpegFile.cs,v
retrieving revision 1.9
diff -u -p -r1.9 JpegFile.cs
--- src/JpegFile.cs	2 Jun 2005 22:12:20 -0000	1.9
+++ src/JpegFile.cs	25 Jul 2005 23:34:47 -0000
@@ -173,11 +173,28 @@ namespace FSpot {
 		public override System.DateTime Date () {
 			System.DateTime time;
 			try {
-				using (Exif.ExifData ed = new Exif.ExifData (path)) {
-					Exif.ExifContent content = ed.GetContents (Exif.Ifd.Exif);
-					Exif.ExifEntry entry = content.GetEntry (Exif.Tag.DateTimeOriginal);
-					time = Exif.ExifUtil.DateTimeFromString (entry.Value); 
-					time = time.ToUniversalTime ();
+				Exif.ExifData ed = this.ExifData;
+				{
+					Exif.ExifContent content1 = ed.GetContents (Exif.Ifd.Exif);
+					Exif.ExifContent content2 = ed.GetContents (Exif.Ifd.Zero);
+					
+					Exif.ExifEntry entry = null;
+					
+					if (entry == null && content1 != null)
+						entry = content1.Lookup (Exif.Tag.DateTimeOriginal);
+					if (entry == null && content2 != null)
+						entry = content2.Lookup (Exif.Tag.DateTimeOriginal);
+					if (entry == null && content1 != null)
+						entry = content1.Lookup (Exif.Tag.DateTime);
+					if (entry == null && content2 != null)
+						entry = content2.Lookup (Exif.Tag.DateTime);
+
+					if (entry == null) {
+						time = base.Date ();
+					} else {
+						time = Exif.ExifUtil.DateTimeFromString (entry.Value); 
+						time = time.ToUniversalTime ();
+					}
 				}
 			} catch (System.Exception e) {
 				time = base.Date ();
@@ -185,5 +202,18 @@ namespace FSpot {
 			return time;
 		}
 		
+		public void SetDate(System.DateTime date) {
+			try {
+				Exif.ExifData ed = this.ExifData;
+				{
+					Exif.ExifContent content = ed.GetContents (Exif.Ifd.Zero);
+					content.GetEntry(Exif.Tag.DateTime).Reset();
+					content.GetEntry(Exif.Tag.DateTime).SetData(date);
+					content.GetEntry(Exif.Tag.DateTimeOriginal).SetData(date);
+				}
+			 } catch (System.Exception e) {
+				System.Console.Write("problem updating exif date.");
+			 }		
+		}
 	}
 }

Index: src/MainWindow.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/MainWindow.cs,v
retrieving revision 1.202
diff -u -p -r1.202 MainWindow.cs
--- src/MainWindow.cs	18 Jun 2005 22:07:10 -0000	1.202
+++ src/MainWindow.cs	25 Jul 2005 23:34:47 -0000
@@ -58,6 +58,7 @@ public class MainWindow {
 	[Glade.Widget] MenuItem adjust_color;
 	[Glade.Widget] MenuItem exif_data;
 	[Glade.Widget] MenuItem sharpen;
+	[Glade.Widget] MenuItem adjust_date;
 	[Glade.Widget] MenuItem remove_from_catalog;
 
 	[Glade.Widget] MenuItem display_tags_menu_item;
@@ -1222,6 +1223,26 @@ public class MainWindow {
 		}
 	}
 
+	void HandleAdjustDate (object sender, EventArgs args)
+	{
+		DateCommands.Adjust adjust_command = new DateCommands.Adjust (db.Photos, main_window, SelectedPhotos());
+		bool success = adjust_command.Execute ();
+		if (success) {
+			// refresh view
+			UpdateQuery ();
+		}
+	}
+  
 	void HandleSharpen (object sender, EventArgs args)
 	{
 		Gtk.Dialog dialog = new Gtk.Dialog (Mono.Posix.Catalog.GetString ("Unsharp Mask"), main_window, Gtk.DialogFlags.Modal);
@@ -1733,6 +1763,7 @@ public class MainWindow {
 		select_none.Sensitive = active_selection;
 		exif_data.Sensitive = active_selection;
 		sharpen.Sensitive = active_selection;
+		adjust_date.Sensitive = active_selection;
 		remove_from_catalog.Sensitive = active_selection;
 
 		delete_selected_tag.Sensitive = tag_sensitive;

Index: src/PhotoStore.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PhotoStore.cs,v
retrieving revision 1.67
diff -u -p -r1.67 PhotoStore.cs
--- src/PhotoStore.cs	28 May 2005 10:35:45 -0000	1.67
+++ src/PhotoStore.cs	25 Jul 2005 23:34:48 -0000
@@ -81,6 +81,9 @@ public class Photo : DbItem, IComparable
 		get {
 			return time;
 		}
+		set {
+			time = value;
+		}
 	}
 
 	private string directory_path;
@@ -886,10 +890,12 @@ public class PhotoStore : DbStore {
 		SqliteCommand command = new SqliteCommand ();
 		command.Connection = Connection;
 		command.CommandText = String.Format ("UPDATE photos SET description = '{0}',     " +
-						     "                  default_version_id = {1} " +
-						     "              WHERE id = {2}",
+						     "                  default_version_id = {1}, " +
+						     "                  time = {2} " +
+						     "              WHERE id = {3}",
 						     SqlString (photo.Description),
 						     photo.DefaultVersionId,
+						     DbUtils.UnixTimeFromDateTime (photo.Time),
 						     photo.Id);
 		command.ExecuteNonQuery ();
 		command.Dispose ();
@@ -1026,18 +1032,26 @@ public class PhotoStore : DbStore {
 		return id_list.ToArray (typeof (Photo)) as Photo [];
 	}
 
-	public Photo [] Query (System.IO.DirectoryInfo dir)
+	public Photo [] Query (System.IO.DirectoryInfo dir, bool recursive)
 	{
-		string query_string = String.Format ("SELECT photos.id,                          " +
-						     "       photos.time,                        " +
-						     "       photos.directory_path,              " +
-						     "       photos.name,                        " +
-						     "       photos.description,                 " +
-						     "       photos.default_version_id           " +
-						     "     FROM photos                           " +
-						     "     WHERE directory_path = \"{0}\"", dir.FullName);
-
-		return Query (query_string);
+		string query_string = "SELECT photos.id,                          " +
+						 "       photos.time,                        " +
+						 "       photos.directory_path,              " +
+						 "       photos.name,                        " +
+						 "       photos.description,                 " +
+						 "       photos.default_version_id           " +
+						 "     FROM photos                           ";
+						     
+		// BUG:  the filename should be escaped! it may contain ', _ or %
+		// I guess this is problem that has been solved a thousand time
+		// but (having never used SQL) I don't know where to look for it.
+		string filter;
+		if (recursive) {
+			filter = String.Format ("WHERE directory_path like \"{0}%\"", dir.FullName);			
+		} else {
+			filter = String.Format ("WHERE directory_path = \"{0}\"", dir.FullName);
+		}
+		return Query (query_string + filter);
 	}	   
 
 	public Photo [] Query (Tag [] tags, DateRange range)

Index: src/f-spot.glade
===================================================================
RCS file: /cvs/gnome/f-spot/src/f-spot.glade,v
retrieving revision 1.104
diff -u -p -r1.104 f-spot.glade
--- src/f-spot.glade	27 Jun 2005 08:06:00 -0000	1.104
+++ src/f-spot.glade	25 Jul 2005 23:34:52 -0000
@@ -6833,6 +6842,15 @@ Photo Details</property>
 		  </child>
 
 		  <child>
+		    <widget class="GtkMenuItem" id="adjust_date">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Adjust date...</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="HandleAdjustDate" last_modification_time="Wed, 15 Jun 2005 21:20:06 GMT"/>
+		    </widget>
+		  </child>
+
+		  <child>
 		    <widget class="GtkSeparatorMenuItem" id="separator19">
 		      <property name="visible">True</property>
 		    </widget>
@@ -7030,7 +7048,7 @@ Photo Details</property>
 			      <property name="visible">True</property>
 			      <property name="label" translatable="yes">_Month</property>
 			      <property name="use_underline">True</property>
-			      <property name="active">False</property>
+			      <property name="active">True</property>
 			      <signal name="activate" handler="HandleArrangeByTime" last_modification_time="Fri, 20 Aug 2004 22:26:32 GMT"/>
 			    </widget>
 			  </child>
@@ -10921,6 +10939,237 @@ Photo Details</property>
   </child>
 </widget>
 
+<widget class="GtkDialog" id="adjust_date_dialog">
+  <property name="border_width">6</property>
+  <property name="title" translatable="yes">Adjust date</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">True</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">True</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
+  <property name="has_separator">False</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="vbox65">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">2</property>
+
+      <child internal-child="action_area">
+	<widget class="GtkHButtonBox" id="hbuttonbox10">
+	  <property name="visible">True</property>
+	  <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+	  <child>
+	    <widget class="GtkButton" id="button22">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-cancel</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-6</property>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="button23">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-ok</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-5</property>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">2</property>
+	  <property name="expand">False</property>
+	  <property name="fill">True</property>
+	  <property name="pack_type">GTK_PACK_END</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkTable" id="table20">
+	  <property name="visible">True</property>
+	  <property name="n_rows">3</property>
+	  <property name="n_columns">2</property>
+	  <property name="homogeneous">False</property>
+	  <property name="row_spacing">6</property>
+	  <property name="column_spacing">6</property>
+
+	  <child>
+	    <widget class="GtkLabel" id="label154">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">Mode:</property>
+	      <property name="use_underline">False</property>
+	      <property name="use_markup">False</property>
+	      <property name="justify">GTK_JUSTIFY_LEFT</property>
+	      <property name="wrap">False</property>
+	      <property name="selectable">False</property>
+	      <property name="xalign">0</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+	      <property name="width_chars">-1</property>
+	      <property name="single_line_mode">False</property>
+	      <property name="angle">0</property>
+	    </widget>
+	    <packing>
+	      <property name="left_attach">0</property>
+	      <property name="right_attach">1</property>
+	      <property name="top_attach">0</property>
+	      <property name="bottom_attach">1</property>
+	      <property name="x_options">fill</property>
+	      <property name="y_options"></property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkLabel" id="label155">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">Date:</property>
+	      <property name="use_underline">False</property>
+	      <property name="use_markup">False</property>
+	      <property name="justify">GTK_JUSTIFY_LEFT</property>
+	      <property name="wrap">False</property>
+	      <property name="selectable">False</property>
+	      <property name="xalign">0</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+	      <property name="width_chars">-1</property>
+	      <property name="single_line_mode">False</property>
+	      <property name="angle">0</property>
+	    </widget>
+	    <packing>
+	      <property name="left_attach">0</property>
+	      <property name="right_attach">1</property>
+	      <property name="top_attach">1</property>
+	      <property name="bottom_attach">2</property>
+	      <property name="x_options">fill</property>
+	      <property name="y_options"></property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GnomeDateEdit" id="forced_dateedit">
+	      <property name="visible">True</property>
+	      <property name="dateedit_flags">GNOME_DATE_EDIT_SHOW_TIME|GNOME_DATE_EDIT_24_HR</property>
+	      <property name="lower_hour">0</property>
+	      <property name="upper_hour">23</property>
+	    </widget>
+	    <packing>
+	      <property name="left_attach">1</property>
+	      <property name="right_attach">2</property>
+	      <property name="top_attach">1</property>
+	      <property name="bottom_attach">2</property>
+	      <property name="y_options"></property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkComboBox" id="mode_combobox">
+	      <property name="visible">True</property>
+	      <property name="items" translatable="yes">By path
+Forced</property>
+	      <property name="add_tearoffs">False</property>
+	      <property name="focus_on_click">True</property>
+	    </widget>
+	    <packing>
+	      <property name="left_attach">1</property>
+	      <property name="right_attach">2</property>
+	      <property name="top_attach">0</property>
+	      <property name="bottom_attach">1</property>
+	      <property name="x_options">fill</property>
+	      <property name="y_options">fill</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkCheckButton" id="update_exif_check">
+	      <property name="visible">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label" translatable="yes">Update EXIF data</property>
+	      <property name="use_underline">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="active">False</property>
+	      <property name="inconsistent">False</property>
+	      <property name="draw_indicator">True</property>
+	    </widget>
+	    <packing>
+	      <property name="left_attach">1</property>
+	      <property name="right_attach">2</property>
+	      <property name="top_attach">2</property>
+	      <property name="bottom_attach">3</property>
+	      <property name="x_options">fill</property>
+	      <property name="y_options"></property>
+	    </packing>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">True</property>
+	  <property name="fill">True</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkAlignment" id="alignment49">
+	  <property name="visible">True</property>
+	  <property name="xalign">0</property>
+	  <property name="yalign">0.5</property>
+	  <property name="xscale">0</property>
+	  <property name="yscale">1</property>
+	  <property name="top_padding">0</property>
+	  <property name="bottom_padding">0</property>
+	  <property name="left_padding">0</property>
+	  <property name="right_padding">0</property>
+
+	  <child>
+	    <widget class="GtkLabel" id="label156">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">&lt;small&gt;&lt;/small&gt;</property>
+	      <property name="use_underline">False</property>
+	      <property name="use_markup">True</property>
+	      <property name="justify">GTK_JUSTIFY_LEFT</property>
+	      <property name="wrap">False</property>
+	      <property name="selectable">False</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+	      <property name="width_chars">-1</property>
+	      <property name="single_line_mode">False</property>
+	      <property name="angle">0</property>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">True</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
 <widget class="GtkWindow" id="single_view">
   <property name="visible">True</property>
   <property name="title" translatable="yes">F-Spot View</property>


Index: src/ColorDialog.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/ColorDialog.cs,v
retrieving revision 1.25
diff -u -p -r1.25 ColorDialog.cs
--- src/ColorDialog.cs	2 Jun 2005 06:37:35 -0000	1.25
+++ src/ColorDialog.cs	25 Jul 2005 23:34:46 -0000
@@ -137,7 +137,7 @@ namespace FSpot {
 			try {
 				string version_path = photo.GetVersionPath (version);
 
-				PixbufUtils.SaveJpeg (final, version_path, 95, data);
+				PixbufUtils.SaveJpeg (final, version_path, 95, data, true, true);
 				ThumbnailGenerator.Create (version_path).Dispose ();
 				photo.DefaultVersionId = version;
 				((PhotoQuery)view.Query).Commit (view.Item.Index);

Index: src/FolderExport.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/FolderExport.cs,v
retrieving revision 1.11
diff -u -p -r1.11 FolderExport.cs
--- src/FolderExport.cs	21 Jul 2005 15:16:00 -0000	1.11
+++ src/FolderExport.cs	25 Jul 2005 23:34:47 -0000
@@ -95,9 +95,9 @@ namespace FSpot {
 			thumb_scrolledwindow.Add (view);
 			HandleSizeActive (null, null);
 			name_entry.Text = gallery_name;
-			uri_entry.Text = System.IO.Path.Combine (FSpot.Global.HomeDirectory, "public_html");
+			uri_entry.Text = System.IO.Path.Combine (FSpot.Global.HomeDirectory, "Desktop");
 			if (!System.IO.Directory.Exists (uri_entry.Text))
-				uri_entry.Text = FSpot.Global.HomeDirectory;
+				uri_entry.Text = FSpot.Global.HomeDirectory + "/webgallery";
 
 			Dialog.ShowAll ();
 
@@ -139,7 +139,7 @@ namespace FSpot {
 				}
 
 				if (scale) {
-					System.Console.WriteLine ("setting scale to {0}", size);
+					System.Console.WriteLine ("setting max size to {0}", size);
 					gallery.SetScale (size);
 				} else {
 					System.Console.WriteLine ("Exporting full size image");
@@ -271,26 +271,25 @@ namespace FSpot {
 
 		protected ScaleRequest [] requests;
 		
-		protected string [] pixbuf_keys = {"quality"};
-		protected string [] pixbuf_values = {"75"};
-
 		protected struct ScaleRequest {
 			public string Name;
 			public int Width;
 			public int Height;
-			public bool Skip;
-			public ScaleRequest (string name, int width, int height, bool skip)
+			public int Quality;
+			public bool KeepExif;
+			public ScaleRequest (string name, int width, int height, int quality, bool keep_exif)
 			{
 				this.Name = name != null ? name : "";
 				this.Width = width;
 				this.Height = height;
-				this.Skip = skip;
+				this.Quality = quality;
+				this.KeepExif = keep_exif;
 			}
 
-			public static ScaleRequest Default = new ScaleRequest ("", 0, 0, false);
+			public static ScaleRequest Default = new ScaleRequest ("", 0, 0, 75, false);
 
-			public bool AvoidScale (int size) { 
-				return (size < this.Width && size < this.Height && this.Skip);
+			public bool ShouldBeSkipped (int size) {
+			    return (this.Width != 0) && (this.Width > size || this.Height > size); 
 			}
 		}
 		
@@ -321,42 +320,24 @@ namespace FSpot {
 		{
 			Photo photo = (Photo) collection [image_num];
 			string photo_path = photo.DefaultVersionPath;
-			string path;
-			ScaleRequest req;
 
-			req = requests [0];
-			
-			MakeDir (SubdirPath (req.Name));
-			path = SubdirPath (req.Name, ImageName (image_num));
-			
-			if (!scale)
-				File.Copy(photo_path, path, true);
-			else 
-				PixbufUtils.Resize (photo_path, path, size, true); 
-			
-			Gdk.Pixbuf img = null;
-			Gdk.Pixbuf scaled = null;
-			
-			for (int i = 1; i < requests.Length; i++) {
-				req = requests [i];
-				if (scale && req.AvoidScale (size))
+			for (int i = 0; i < requests.Length; i++) {
+				ScaleRequest req = requests [i];
+				if (scale && req.ShouldBeSkipped(size))
 					continue;
 
-				if (img == null)
-					scaled = PixbufUtils.LoadAtMaxSize (photo_path, req.Width, req.Height);
-				else
-					scaled = PixbufUtils.ScaleToMaxSize (img, req.Width, req.Height, false);
-				
 				MakeDir (SubdirPath (req.Name));
-				path = SubdirPath (req.Name, ImageName (image_num));
-				scaled.Savev (path, "jpeg", pixbuf_keys, pixbuf_values);
-				
-				if (img != null)
-					img.Dispose ();
+				string dest_path = SubdirPath (req.Name, ImageName (image_num));
+				if (req.Width == 0) {
+					if (scale) {
+						PixbufUtils.Resize (photo_path, dest_path, size, (size*3)/4, true, req.KeepExif, req.Quality);
+					} else { 
+						File.Copy(photo_path, dest_path, true);
+					}
+				} else {
+					PixbufUtils.Resize (photo_path, dest_path, req.Width, req.Height, false, req.KeepExif, req.Quality);
+				}
 			}
-
-			if (scaled != null)
-				scaled.Dispose ();
 		}
 
 		protected string MakeDir (string path)
@@ -410,8 +391,6 @@ namespace FSpot {
 		public void SetScale (int size) {
 			this.scale = true;
 			this.size = size;
-			requests [0].Width = size;
-			requests [0].Height = size;
 		}
 	}
 
@@ -419,10 +398,11 @@ namespace FSpot {
 	{
 		public OriginalGallery (IPhotoCollection selection, string path, string name) : base (selection, path, name) 
 		{ 
-			requests = new ScaleRequest [] { new ScaleRequest ("hq", 0, 0, false),
-							 new ScaleRequest ("mq", 800, 600, true),
-							 new ScaleRequest ("lq", 640, 480, false),
-							 new ScaleRequest ("thumbs", 120, 90, false) };
+			requests = new ScaleRequest [] {
+							 new ScaleRequest ("hq", 0, 0, 85, true),
+							 new ScaleRequest ("mq", 800, 600, 80, true),
+							 new ScaleRequest ("lq", 640, 480, 75, true),
+							 new ScaleRequest ("thumbs", 120, 90, 75, false) };
 		}
 
 		public override void Generate ()
@@ -533,13 +519,14 @@ namespace FSpot {
 	{
 		int current;
 		int perpage = 16;
		string stylesheet = "f-spot-simple-white.css";
 		
 		public HtmlGallery (IPhotoCollection selection, string path, string name) : base (selection, path, name) 
 		{ 
-			requests = new ScaleRequest [] { new ScaleRequest ("hq", 0, 0, false),
-							 new ScaleRequest ("mq", 480, 320, false),
-							 new ScaleRequest ("thumbs", 120, 90, false) };
+			requests = new ScaleRequest [] { 
+							new ScaleRequest ("hq", 0, 0, 85, false),
+							 new ScaleRequest ("mq", 480, 320, 80, false),
+							 new ScaleRequest ("thumbs", 120, 90, 75, false) };
 		}
 		
 		public override void Generate ()
@@ -584,7 +571,12 @@ namespace FSpot {
 		
 		public string PhotoWebPath (int item)
 		{
-			return System.IO.Path.Combine (requests [1].Name, ImageName (item));	
+			string path = System.IO.Path.Combine (requests [1].Name, ImageName (item)); 
+			if (System.IO.File.Exists (SubdirPath (path)))
+				return path;
+			else 
+				// the size is too small for the mq to be generated. use hq directly.
+				return System.IO.Path.Combine (requests [0].Name, ImageName (item));				
 		}
 		
 		public string PhotoOriginalPath (int item)

@@ -678,12 +683,17 @@ namespace FSpot {
 		
 		static string IndexTitle (int page)
 		{
-			return String.Format ("{0}", page);
+			return String.Format ("{0}", page + 1);
 		}
 
 		public void WriteHeader (System.Web.UI.HtmlTextWriter writer)
 		{
 			writer.RenderBeginTag ("head");
+			
+			// apparently there is an encoding attribute to System.Web.UI.HtmlTextWriter
+			// but I can't find how to get the code set it in the html. So let's do it ourselves.
+			writer.Write ("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />");		
+
 			writer.RenderBeginTag ("title");
 			writer.Write (gallery_name);
 			writer.RenderEndTag ();

Index: src/MainWindow.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/MainWindow.cs,v
retrieving revision 1.202
diff -u -p -r1.202 MainWindow.cs
--- src/MainWindow.cs	18 Jun 2005 22:07:10 -0000	1.202
+++ src/MainWindow.cs	25 Jul 2005 23:34:47 -0000
@@ -1272,7 +1293,7 @@ public class MainWindow {
 				try {
 					string version_path = photo.GetVersionPath (version);
 					
-					PixbufUtils.SaveJpeg (final, version_path, 95, exif_data);
+					PixbufUtils.SaveJpeg (final, version_path, 95, exif_data, true, true);
 					FSpot.ThumbnailGenerator.Create (version_path).Dispose ();
 					photo.DefaultVersionId = version;
 					query.Commit (id);
Index: src/PhotoView.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PhotoView.cs,v
retrieving revision 1.60
diff -u -p -r1.60 PhotoView.cs
--- src/PhotoView.cs	22 Jun 2005 15:41:50 -0000	1.60
+++ src/PhotoView.cs	25 Jul 2005 23:34:48 -0000
@@ -263,13 +263,13 @@ public class PhotoView : EventBox {
 				photo.DefaultVersionId = photo.CreateDefaultModifiedVersion (photo.DefaultVersionId, false);
 				version = true;
 				PixbufUtils.SaveJpeg (edited, photo.DefaultVersionPath, 
-						      95, exif_data);
+						      95, exif_data, true, true);
 				FSpot.ThumbnailGenerator.Create (photo.DefaultVersionPath).Dispose ();
 				query.Commit (Item.Index);
 			} else {
 				// FIXME we need to invalidate the thumbnail in the cache as well
 				PixbufUtils.SaveJpeg (edited, photo.DefaultVersionPath, 
-						      95, exif_data);
+						      95, exif_data, true, true);
 				FSpot.ThumbnailGenerator.Create (photo.DefaultVersionPath).Dispose ();
 				query.MarkChanged (Item.Index);
 			}
Index: src/PixbufUtils.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PixbufUtils.cs,v
retrieving revision 1.57
diff -u -p -r1.57 PixbufUtils.cs
--- src/PixbufUtils.cs	14 Jun 2005 14:34:16 -0000	1.57
+++ src/PixbufUtils.cs	25 Jul 2005 23:34:48 -0000
@@ -101,12 +101,14 @@ class PixbufUtils {
 	public class AspectLoader : Gdk.PixbufLoader {
 		int max_width;
 		int max_height;
+		bool surface_mode;
 		PixbufOrientation orientation;
 
-		public AspectLoader (int max_width, int max_height) 
+		public AspectLoader (int max_width, int max_height, bool surface_mode) 
 		{
 			this.max_height = max_height;
 			this.max_width = max_width;
+			this.surface_mode = surface_mode;
 			SizePrepared += HandleSizePrepared;
 		}
 
@@ -124,10 +126,18 @@ class PixbufUtils {
 			default:
 				break;
 			}
-
-			double scale = Math.Min (max_width / (double)args.Width,
+			
+			double scale;
+			
+			if (surface_mode) {
+				System.Console.WriteLine("coucou bob");
+				double surface_load = (double)args.Width*(double)args.Height;
+				double surface_wanted = (double)max_width*(double)max_height;
+				scale = Math.Sqrt(surface_wanted/surface_load);
+			} else {
+				scale = Math.Min (max_width / (double)args.Width,
 						 max_height / (double)args.Height);
-
+			}
 			
 			int scale_width = (int)(scale * args.Width);
 			int scale_height = (int)(scale * args.Height);
@@ -199,8 +209,13 @@ class PixbufUtils {
 		
 	static public Pixbuf LoadAtMaxSize (string path, int max_width, int max_height)
 	{
+		return LoadAtMaxSize(path, max_width, max_height, false);
+	}
+	
+	static public Pixbuf LoadAtMaxSize (string path, int max_width, int max_height, bool surface_mode)
+	{
 #if true
-		PixbufUtils.AspectLoader loader = new AspectLoader (max_width, max_height);
+		PixbufUtils.AspectLoader loader = new AspectLoader (max_width, max_height, surface_mode);
 		return loader.LoadFromFile (path);
 #else
 		int width, height;
@@ -384,20 +406,26 @@ class PixbufUtils {
 	public static string Resize (string orig_path, int size, bool copy_meta)
 	{
 		string version_path = System.IO.Path.GetTempFileName ();
-		Resize (orig_path, version_path, size, copy_meta);
+		Resize (orig_path, version_path, size, size, false, copy_meta, 95);
 		return version_path;
 	}
 
-	public static void Resize (string orig_path, string dest_path, int size, bool copy_meta)
+	public static void Resize (string orig_path, string dest_path, int max_width, int max_height, bool surface_mode, bool copy_meta, int quality)
 	{
+		bool update_date;
 		Exif.ExifData exif_data;
-		if (copy_meta)
+		if (copy_meta) {
 			exif_data = new Exif.ExifData (orig_path);
-		else 
+			update_date = false;
+		} else {
 			exif_data = new Exif.ExifData ();
+			update_date = true;
+		}
+
+		bool with_thumbnail = max_width > 160*2 || max_height > 120*2;
 
-		Gdk.Pixbuf image = PixbufUtils.LoadAtMaxSize (orig_path, size, size);
-		PixbufUtils.SaveJpeg (image, dest_path, 95, exif_data);
+		Gdk.Pixbuf image = PixbufUtils.LoadAtMaxSize (orig_path, max_width, max_height, surface_mode);
+		PixbufUtils.SaveJpeg (image, dest_path, quality, exif_data, with_thumbnail, update_date);
 	}
 	
 
@@ -411,13 +439,17 @@ class PixbufUtils {
 	[DllImport ("libfspot")]
 	static extern bool f_pixbuf_save_jpeg (IntPtr src, string path, int quality, FPixbufJpegMarker [] markers, int num_markers);
 
-	public static void SaveJpeg (Pixbuf pixbuf, string path, int quality, Exif.ExifData exif_data)
+	public static void SaveJpeg (Pixbuf pixbuf, string path, int quality, Exif.ExifData exif_data, bool with_thumbnail, bool update_date)
 	{
-		// The DCF spec says thumbnails should be 160x120 always
-		Pixbuf thumbnail = ScaleToAspect (pixbuf, 160, 120);
-		byte [] thumb_data = Save (thumbnail, "jpeg", null, null);
-		exif_data.Data = thumb_data;
-		thumbnail.Dispose ();
+		if (with_thumbnail) {
+			// The DCF spec says thumbnails should be 160x120 always
+			Pixbuf thumbnail = ScaleToAspect (pixbuf, 160, 120);
+			byte [] thumb_data = Save (thumbnail, "jpeg", null, null);
+			exif_data.Data = thumb_data;
+			thumbnail.Dispose ();
+		} else {
+			exif_data.Data = null;
+		}
 
 		// Most of the things we will set will be in the 0th ifd
 		Exif.ExifContent content = exif_data.GetContents (Exif.Ifd.Zero);
@@ -426,7 +458,8 @@ class PixbufUtils {
 		content.GetEntry (Exif.Tag.Orientation).Reset ();
 
 		// set the write time in the datetime tag
-		content.GetEntry (Exif.Tag.DateTime).Reset ();
+		if (update_date)
+			content.GetEntry (Exif.Tag.DateTime).Reset ();
 
 		// set the software tag
 		content.GetEntry (Exif.Tag.Software).SetData (FSpot.Defines.PACKAGE + " version " + FSpot.Defines.VERSION);




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