Index: src/rotation-utils.c
===================================================================
--- src/rotation-utils.c	(revision 1439)
+++ src/rotation-utils.c	(working copy)
@@ -59,28 +59,10 @@
 write_orientation_field (const char   *path,
 			 GthTransform  transform)
 {
-	JPEGData     *jdata;
-	ExifData     *edata;
-
 	if (path == NULL)
 		return;
 
-	jdata = jpeg_data_new_from_file (path);
-	if (jdata == NULL)
-		return;
-
-	edata = jpeg_data_get_exif_data (jdata);
-	if (edata == NULL) {
-		jpeg_data_unref (jdata);
-		return;
-	}
-
-	set_orientation_in_exif_data (transform, edata);
-
-	jpeg_data_save_file (jdata, path);
-
-	exif_data_unref (edata);
-	jpeg_data_unref (jdata);
+	gth_minimal_exif_tag_write(path, EXIF_TAG_ORIENTATION, &transform, 2, 0);
 }
 
 
Index: src/dlg-change-date.c
===================================================================
--- src/dlg-change-date.c	(revision 1439)
+++ src/dlg-change-date.c	(working copy)
@@ -50,6 +50,7 @@
 
 	GtkWidget    *cd_last_modified_checkbutton;
 	GtkWidget    *cd_comment_checkbutton;
+	GtkWidget    *cd_exif_checkbutton;
 
 	GtkWidget    *cd_following_date_radiobutton;
 	GtkWidget    *cd_created_radiobutton;
@@ -156,6 +157,60 @@
 			comment_data_free (cdata);
 		}
 
+		if (is_active (data->cd_exif_checkbutton)) {
+			char buf[32];
+			struct tm tm;
+			int    res;
+
+			char             *local_file_to_modify = NULL;
+			GnomeVFSFileInfo *info;
+			gboolean          is_local;
+			gboolean          remote_copy_ok;
+		
+		        is_local = is_local_file (fdata->path);
+
+		        /* If the original file is stored on a remote VFS location, copy it to a local
+		           temp file, modify it, then copy it back. This is easier than modifying the
+		           underlying jpeg code (and other code) to handle VFS URIs. */
+
+		        local_file_to_modify = obtain_local_file (fdata->path);
+
+		        if (local_file_to_modify == NULL) {
+		                _gtk_error_dialog_run (GTK_WINDOW (data->dialog),
+		                        _("Could not create a local temporary copy of the remote file."));
+		                return;
+		        }
+		        info = gnome_vfs_file_info_new ();
+		        gnome_vfs_get_file_info (fdata->path, info, GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS|GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
+
+			localtime_r(&mtime, &tm);
+			snprintf(buf, 32, "%04d:%02d:%02d %02d:%02d:%02d ", 
+			       tm.tm_year + 1900,
+			       tm.tm_mon + 1,
+			       tm.tm_mday,
+			       tm.tm_hour,
+			       tm.tm_min,
+			       tm.tm_sec );
+			if ((res = gth_minimal_exif_tag_write(local_file_to_modify, EXIF_TAG_DATE_TIME, buf, strlen(buf), 0)) != PATCH_EXIF_OK)
+				fprintf(stderr, "gth_minimal_exif_tag_write: error %d\n", res);
+
+			mtime++; // Step the time to enable sorting of pictures according to EXIF time
+
+		        if (!is_local)
+		                remote_copy_ok = copy_cache_file_to_remote_uri (local_file_to_modify, fdata->path);
+
+		        g_free (local_file_to_modify);
+
+		        if (!is_local && !remote_copy_ok) {
+                		_gtk_error_dialog_run (GTK_WINDOW (data->dialog),
+                            		_("Could not move temporary file to remote location. Check remote permissions."));
+		        } else {
+                		gnome_vfs_set_file_info (fdata->path, info, GNOME_VFS_SET_FILE_INFO_PERMISSIONS|GNOME_VFS_SET_FILE_INFO_OWNER);
+		        }
+
+		        gnome_vfs_file_info_unref (info);
+		}
+
 		file_list = g_list_prepend (file_list, fdata->path);
 	}
 
@@ -173,7 +228,8 @@
 {
 	gtk_widget_set_sensitive (data->ok_button,
 				  gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->cd_last_modified_checkbutton))
-				  || gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->cd_comment_checkbutton)));
+				  || gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->cd_comment_checkbutton))
+				  || gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->cd_exif_checkbutton)));
 		
 	gtk_widget_set_sensitive (data->cd_dateedit, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->cd_following_date_radiobutton)));
 	gtk_widget_set_sensitive (data->cd_timezone_box, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->cd_adjust_timezone_radiobutton)));
@@ -234,6 +290,7 @@
 
 	data->cd_last_modified_checkbutton = glade_xml_get_widget (data->gui, "cd_last_modified_checkbutton");
 	data->cd_comment_checkbutton = glade_xml_get_widget (data->gui, "cd_comment_checkbutton");
+	data->cd_exif_checkbutton = glade_xml_get_widget (data->gui, "cd_exif_checkbutton");
 
 	data->cd_following_date_radiobutton = glade_xml_get_widget (data->gui, "cd_following_date_radiobutton");
 	data->cd_created_radiobutton = glade_xml_get_widget (data->gui, "cd_created_radiobutton");
@@ -285,6 +342,10 @@
 			  "clicked",
 			  G_CALLBACK (radio_button_clicked),
 			  data);
+	g_signal_connect (G_OBJECT (data->cd_exif_checkbutton), 
+			  "clicked",
+			  G_CALLBACK (radio_button_clicked),
+			  data); 
 	
 	g_signal_connect (G_OBJECT (data->cd_following_date_radiobutton), 
 			  "clicked",
Index: data/glade/gthumb_tools.glade
===================================================================
--- data/glade/gthumb_tools.glade	(revision 1439)
+++ data/glade/gthumb_tools.glade	(working copy)
@@ -2133,6 +2133,25 @@
 			  <property name="fill">False</property>
 			</packing>
 		      </child>
+
+		      <child>
+			<widget class="GtkCheckButton" id="cd_exif_checkbutton">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="label" translatable="yes">EXIF date</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="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
 		    </widget>
 		    <packing>
 		      <property name="padding">0</property>
Index: libgthumb/gth-exif-utils.c
===================================================================
--- libgthumb/gth-exif-utils.c	(revision 1440)
+++ libgthumb/gth-exif-utils.c	(working copy)
@@ -24,6 +24,7 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <time.h>
 #include <glib.h>
 #include <libgnomeui/gnome-thumbnail.h>
@@ -598,3 +599,226 @@
 
 	return remote_copy_ok;
 }
+
+
+const char leth[]  = {0x49, 0x49, 0x2a, 0x00}; // Little endian TIFF header
+const char beth[]  = {0x4d, 0x4d, 0x00, 0x2a}; // Big endian TIFF header
+const char types[] = {0x00, 0x01, 0x01, 0x02, 0x04, 0x08, 0x00, 0x08, 0x00, 0x04, 0x08}; // size in bytes for EXIF types
+ 
+#define DE_ENDIAN16(val) endian == G_BIG_ENDIAN ? GUINT16_FROM_BE(val) : GUINT16_FROM_LE(val)
+#define DE_ENDIAN32(val) endian == G_BIG_ENDIAN ? GUINT32_FROM_BE(val) : GUINT32_FROM_LE(val)
+ 
+#define ENDIAN16_IT(val) endian == G_BIG_ENDIAN ? GUINT16_TO_BE(val) : GUINT16_TO_LE(val)
+#define ENDIAN32_IT(val) endian == G_BIG_ENDIAN ? GUINT32_TO_BE(val) : GUINT32_TO_LE(val)
+ 
+#define IFD_OFFSET_PUSH(val) if (oi < sizeof(offsets) - 1) offsets[oi++] = val; else return PATCH_EXIF_TOO_MANY_IFDS;
+#define IFD_OFFSET_PULL()    offsets[--oi]
+ 
+#define IFD_NAME_PUSH(val) names[ni++] = val;
+#define IFD_NAME_PULL()    names[--ni]
+ 
+#define DEBUG(x)
+ 
+int
+gth_minimal_exif_tag_write (const char *filename,
+ 	                    ExifTag     etag,
+ 			    const char *data,
+ 			    int         size,
+ 			    int         ifds)
+{
+	/* This function updates ONLY the affected tag. Unlike libexif, it does
+	   not attempt to correct or re-format other data. This helps preserve
+	   the integrity of certain MakerNote entries, by avoiding re-positioning
+	   of the data whenever possible. Some MakerNotes incorporate absolute
+	   offsets and others use relative offsets. The offset issue is 
+	   avoided if tags are not moved or resized if not required. */
+
+ 	FILE *jf;            	// File descriptor to file to patch
+ 	char  buf[1024 * 64]; 	// Working buffer
+ 	int   i;               	// index into working buffer
+ 	int   tag;             	// endianed version of 'etag' in call
+ 	int   gpsifd;          	// endianed gps ifd pointer tag
+ 	int   exififd;         	// endianed exif ifd pointer tag
+ 	int   offset;          	// de-endianed offset in various situations
+ 	int   tags;            	// number of tags in current ifd
+ 	int   type;            	// de-endianed type of tag used as index into types[]
+ 	int   count;           	// de-endianed count of elements in a tag
+ 	int   stitch;          	// offset in data buffer in type size increments
+        int   tiff = 0;   	// offset to active tiff header
+        int   endian = 0;   	// detected endian of data
+ 	int   readsize = 0;   	// number of read bytes from file into buffer
+ 	int   writesize = 0;   	// number of written bytes from buffer to file
+ 	int   patches = 0;   	// number of values changed
+ 
+ 	// IFD stack variables
+ 	unsigned long offsets[32];  // Offsets in working buffer to start of IFDs
+        char         *names[32];    // Printable names of IFD:s (for debug mostly)
+        int           oi = 0;       // index into offsets
+        int           ni = 0;       // iundex into names
+ 	int           cifdi = 0;    // curret ifd index
+ 
+ 	DEBUG(printf("gth_minimal_exif_tag_write(%s, %04x, %08x, %d, %02x)\n", filename, etag, data, size, ifds);)
+ 
+        // Init IFD stack
+ 	IFD_OFFSET_PUSH(0);
+ 	IFD_NAME_PUSH("START");
+ 
+	g_assert (is_local_file (filename));
+
+ 	// get path to file
+ 	if ((filename = get_file_path_from_uri (filename)) == NULL )
+ 		return PATCH_EXIF_FILE_ERROR;
+ 
+ 	// open file r (read (r))
+ 	if ((jf = fopen(filename, "r")) == NULL)
+ 		return PATCH_EXIF_FILE_ERROR;
+ 
+        // Fill buffer
+        readsize = fread(buf, 1, sizeof(buf), jf);
+ 
+ 	// close file during prcessing
+ 	fclose(jf);
+ 
+        // Check for TIFF header and catch endianess
+ 	i = 0;
+ 	while (i < readsize){
+ 
+ 		// Little endian TIFF header
+ 		if (bcmp(&buf[i], leth, 4) == 0){ 
+ 			endian = G_LITTLE_ENDIAN;
+                }
+ 
+ 		// Big endian TIFF header
+ 		else if (bcmp(&buf[i], beth, 4) == 0){ 
+ 			endian = G_BIG_ENDIAN;
+                }
+ 
+ 		// Keep looking through buffer
+ 		else {
+ 			i++;
+ 			continue;
+ 		}
+ 		// We have found either big or little endian TIFF header
+ 		tiff    = i;
+ 		break;
+        }
+ 
+ 	// So did we find a TIFF header or did we just hit end of buffer?
+ 	if (tiff == 0) return PATCH_EXIF_NO_TIFF;
+ 
+        // Endian some tag values that we will look for
+ 	exififd = ENDIAN16_IT(0x8769);
+ 	gpsifd  = ENDIAN16_IT(0x8825);
+        tag     = ENDIAN16_IT(etag);
+ 
+        // Read out the offset
+        offset  = DE_ENDIAN32(*((unsigned long*)(&buf[i] + 4)));
+ 	i       = i + offset;
+ 
+        // Start out with IFD0 (and add more IFDs while we go)
+ 	IFD_OFFSET_PUSH(i);
+ 	IFD_NAME_PUSH("IFD0");
+ 
+        // As long as we find more IFDs check out the tags in each
+ 	while ((oi >=0 && (i = IFD_OFFSET_PULL()) != 0 && i < readsize - 2)){
+ 	  
+ 		cifdi    = oi; // remember which ifd we are at
+ 
+ 		DEBUG(printf("%s:\n", IFD_NAME_PULL());)
+ 		tags    = DE_ENDIAN16(*((unsigned short*)(&buf[i])));
+ 		i       = i + 2;
+ 
+ 		// Check this IFD for tags of interest
+ 		while (tags-- && i < readsize - 12 ){
+ 			type   = DE_ENDIAN16(*((unsigned short*)(&buf[i + 2])));
+ 			count  = DE_ENDIAN32(*((unsigned long*) (&buf[i + 4])));
+ 			offset = DE_ENDIAN32(*((unsigned long*) (&buf[i + 8])));
+ 
+ 			DEBUG(printf("TAG: %04x type:%02d count:%02d offset:%04lx ", 
+ 				     DE_ENDIAN16(*((unsigned short*)(&buf[i]))), type, count, offset);)
+ 
+ 			// Our tag?
+ 			if (bcmp(&buf[i], (char *)&tag, 2) == 0){ 
+ 
+ 				DEBUG(printf("*");)
+ 				
+ 				// Local value that can be patched directly in TAG table 
+ 				if ((types[type] * count) <= 4){
+ 
+ 					// Fake TIFF offset
+ 					offset = i + 8 - tiff; 
+ 					patches++;
+ 				}
+ 				// Offseted value of same or larger size that we can patch
+ 				else if (types[type] * count >= size){
+ 
+ 					// Adjust count to new length
+ 					count = size / types[type]; 
+ 					*((unsigned short*)(&buf[i + 4])) = ENDIAN32_IT(count);
+ 					patches++;
+ 				}
+ 				// Otherwise we are not able to patch the new value, at least not here
+ 				else {
+ 					fprintf(stderr, "gth_minimal_exif_tag_write: New TAG value does not fit, no patch applied\n");
+ 					continue;
+ 				}
+ 				stitch = 0;
+ 
+ 				// Copy the data
+ 				while (stitch < count){
+ 					switch (types[type]){
+ 					case 1:
+ 						buf[tiff + offset + stitch] = data[stitch];
+ 						break;
+ 					case 2:
+ 						*((unsigned short*)(&buf[tiff + offset + stitch * 2])) = 
+ 							ENDIAN16_IT(data[stitch * 2]);
+ 						break;
+ 					case 4:
+ 						*((unsigned long*)(&buf[tiff + offset + stitch * 4])) = 
+ 							ENDIAN32_IT(data[stitch * 4]);
+ 						break;
+ 					default:
+ 						fprintf(stderr, "gth_minimal_exif_tag_write:unsupported value size\n");
+ 					}
+ 					stitch++;
+ 				}
+ 			}
+ 			// EXIF pointer tag?
+ 			else if (bcmp(&buf[i], (char *)&exififd, 2) == 0){ 
+ 				IFD_OFFSET_PUSH(offset + tiff);
+ 				IFD_NAME_PUSH("EXIF");
+ 			}
+ 			// GPS pointer tag?
+ 			else if (bcmp(&buf[i], (char *)&gpsifd, 2) == 0){ 
+ 				IFD_OFFSET_PUSH(offset + tiff);
+ 				IFD_NAME_PUSH("GPS");
+ 			}
+ 
+ 			DEBUG(printf("\n");)
+ 					
+ 			i += 12;
+ 		}
+ 		// Check for a valid next pointer and assume that to be IFD1 if we just checked IFD0
+ 		if (cifdi == 1 && i < readsize - 2 && (i = DE_ENDIAN32((*((unsigned long*) (&buf[i]))))) != 0){ 
+ 			i = i + tiff;
+ 			IFD_OFFSET_PUSH(i);
+ 			IFD_NAME_PUSH("IFD1");
+ 			
+ 		}
+        }
+
+ 	// Check if we need to save
+ 	if (patches == 0)
+ 		return PATCH_EXIF_NO_TAGS_FOUND;
+ 
+ 	// open file rb+ (read (r) and modify (+), b indicates binary file accces on non-Unix systems
+ 	if ((jf = fopen(filename, "rb+")) == NULL)
+ 		return PATCH_EXIF_FILE_ERROR;
+ 
+        // Save changes
+ 	writesize = fwrite(buf, 1, readsize, jf);
+ 	fclose(jf);
+ 
+ 	return readsize == writesize ? PATCH_EXIF_OK : PATCH_EXIF_FILE_ERROR; 
+}
Index: libgthumb/gth-exif-utils.h
===================================================================
--- libgthumb/gth-exif-utils.h	(revision 1439)
+++ libgthumb/gth-exif-utils.h	(working copy)
@@ -33,6 +33,13 @@
 #include "jpegutils/jpeg-data.h"
 #include "typedefs.h"
 
+// Return values from gth_minimal_exif_tag_writes() 
+#define PATCH_EXIF_OK              0
+#define PATCH_EXIF_TOO_MANY_IFDS   1
+#define PATCH_EXIF_TOO_FEW_IFDS    2
+#define PATCH_EXIF_FILE_ERROR      3
+#define PATCH_EXIF_NO_TIFF         4
+#define PATCH_EXIF_NO_TAGS_FOUND   5
 
 ExifData   *gth_exif_data_new_from_uri    (const char   *path);
 char *      get_exif_tag                  (const char   *filename,
@@ -51,7 +58,13 @@
 				           ExifData     *edata);
 void	    get_metadata_for_file         (const char   *url,
 					   GHashTable   *metadata_hash);
-gboolean    write_metadata_tag_to_file    (const char *path,
-					   const char *tag_name,
-					   const char *value);
+gboolean    write_metadata_tag_to_file    (const char   *path,
+					   const char   *tag_name,
+					   const char   *value);
+int         gth_minimal_exif_tag_write    (const char   *filename,
+                                           ExifTag       etag,
+                                           const char   *data,
+                                           int           size,
+                                           int           ifds);
+
 #endif /* EXIF_UTILS_H */
