Index: src/rotation-utils.c
===================================================================
--- src/rotation-utils.c	(revision 1437)
+++ 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);
+	patch_exif_tag(path, EXIF_TAG_ORIENTATION, &transform, 2, 0);
 }
 
 
Index: src/dlg-change-date.c
===================================================================
--- src/dlg-change-date.c	(revision 1437)
+++ 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,25 @@
 			comment_data_free (cdata);
 		}
 
+		if (is_active (data->cd_exif_checkbutton)) {
+			char buf[32];
+			struct tm tm;
+			int    res;
+
+			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 = patch_exif_tag(fdata->path, EXIF_TAG_DATE_TIME, buf, strlen(buf), 0)) != PATCH_EXIF_OK)
+				fprintf(stderr, "patch_exif_tag: error %d\n", res);
+
+			mtime++; // Step the time to enable sorting of pictures according to EXIF time
+		}
+
 		file_list = g_list_prepend (file_list, fdata->path);
 	}
 
@@ -173,7 +193,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 +255,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 +307,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 1437)
+++ 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 1437)
+++ 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>
 
@@ -372,3 +373,181 @@
 	}
 }
 
+
+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
+patch_exif_tag( const char *filename,
+	        ExifTag     etag,
+		const char *data,
+		int         size,
+		int         ifds)
+{
+	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 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
+
+	DEBUG(printf("patch_exif_tag(%s, %04x, %08x, %d, %02x)\n", filename, etag, data, size, ifds);)
+
+        // Init IFD stack
+	IFD_OFFSET_PUSH(0);
+	IFD_NAME_PUSH("START");
+
+        // 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)){
+	  
+		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:%d count:%d offset:%04lx\n", 
+				     DE_ENDIAN16(*((unsigned short*)(&buf[i]))), type, count, offset);)
+
+			// Our tag?
+			if (bcmp(&buf[i], (char *)&tag, 2) == 0){ 
+				
+				// Local value that can be patched directly in TAG table 
+				if ((types[type] * count) <= 4){
+					*((unsigned long*)(&buf[i + 8])) = ENDIAN32_IT(*data);
+					patches++;
+				}
+				// Offseted value of same or larger size that we can patch
+				else if (types[type] * count >= size){
+					memcpy((char *)(buf + tiff + offset), data, size);
+					patches++;
+				}
+				// Otherwise we are not able to patch the new value, at least not here
+				else {
+					fprintf(stderr, "patch_exif_tag: New TAG value does not fit, no patch applied\n");
+					continue;
+				}
+			}
+			// 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");
+			}
+			i += 12;
+		}
+		// Check for a valid next pointer and assume that to be IFD1 if we just checked IFD0
+		if (oi == 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 1437)
+++ libgthumb/gth-exif-utils.h	(working copy)
@@ -33,6 +33,13 @@
 #include "jpegutils/jpeg-data.h"
 #include "typedefs.h"
 
+// Return values from patch_exif_tags() 
+#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,
@@ -49,5 +56,10 @@
 				           const char   *dest);
 void        set_orientation_in_exif_data  (GthTransform  transform,
 				           ExifData     *edata);
+int         patch_exif_tag                ( const char *filename,
+					    ExifTag     etag,
+					    const char *data,
+					    int         size,
+					    int         ifds);
 
 #endif /* EXIF_UTILS_H */
