gthumb r2239 - in trunk: . data/glade libgthumb src



Author: mjc
Date: Thu Jan 31 19:30:57 2008
New Revision: 2239
URL: http://svn.gnome.org/viewvc/gthumb?rev=2239&view=rev

Log:
2008-01-31  Michael J. Chudobiak  <mjc svn gnome org>

        * libgthumb/gth-exif-utils.c:
        * libgthumb/gth-exif-utils.h:
        Purged gth_minimal_exif_tag_write, gth_minimal_exif_tag_action.
        Use exiv2-based routines now.

        * data/glade/gthumb_tools.glade:
        * src/dlg-change-date.c: (ok_clicked), (update_sensitivity),
        (dlg_change_date):
        Added the ability to change DateTimeOriginal and DateTimeDigitized,
        in addition to the existing DateTime-changing function.



Modified:
   trunk/ChangeLog
   trunk/data/glade/gthumb_tools.glade
   trunk/libgthumb/gth-exif-utils.c
   trunk/libgthumb/gth-exif-utils.h
   trunk/src/dlg-change-date.c

Modified: trunk/data/glade/gthumb_tools.glade
==============================================================================
--- trunk/data/glade/gthumb_tools.glade	(original)
+++ trunk/data/glade/gthumb_tools.glade	Thu Jan 31 19:30:57 2008
@@ -2205,7 +2205,45 @@
 			<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="label" translatable="yes">Exif DateTime tag</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>
+
+		      <child>
+			<widget class="GtkCheckButton" id="cd_exif_orig_checkbutton">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="label" translatable="yes">Exif DateTimeOriginal tag</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>
+
+		      <child>
+			<widget class="GtkCheckButton" id="cd_exif_dig_checkbutton">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="label" translatable="yes">Exif DateTimeDigitized tag</property>
 			  <property name="use_underline">True</property>
 			  <property name="relief">GTK_RELIEF_NORMAL</property>
 			  <property name="focus_on_click">True</property>

Modified: trunk/libgthumb/gth-exif-utils.c
==============================================================================
--- trunk/libgthumb/gth-exif-utils.c	(original)
+++ trunk/libgthumb/gth-exif-utils.c	Thu Jan 31 19:30:57 2008
@@ -319,308 +319,6 @@
 }
 
 
-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]
-
-static unsigned short de_get16(void *ptr, guint endian)
-{
-	unsigned short val;
-
-	memcpy(&val, ptr, sizeof(val));
-	val = DE_ENDIAN16(val);
-
-	return val;
-}
-
-static unsigned int de_get32(void *ptr, guint endian)
-{
-	unsigned int val;
-
-	memcpy(&val, ptr, sizeof(val));
-	val = DE_ENDIAN32(val);
-
-	return val;
-}
-
-int static
-gth_minimal_exif_tag_action (const char *local_file,
-			     ExifTag     etag,
-			     void       *data,
-			     int         size,
-			     int         access)
-{
-	/* This function updates/reads 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 (DEBUG_INFO, "gth_minimal_exif_tag_access (%s, %04x, %08x, %d)\n", local_file, etag, data, size);
-
-	// local files only
-	g_assert (uri_has_scheme (local_file) == FALSE);
-
-        // Init IFD stack
- 	IFD_OFFSET_PUSH(0);
- 	IFD_NAME_PUSH("START");
- 
- 	// open file r (read (r))
- 	if ((jf = fopen (local_file, "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_get32(&buf[i] + 4, endian);
- 	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 (DEBUG_INFO, "%s:\n", IFD_NAME_PULL());
- 		tags    = de_get16(&buf[i], endian);
- 		i       = i + 2;
- 
- 		// Check this IFD for tags of interest
- 		while (tags-- && i < readsize - 12) {
- 			type   = de_get16(&buf[i + 2], endian);
- 			count  = de_get32(&buf[i + 4], endian);
- 			offset = de_get32(&buf[i + 8], endian);
- 
- 			debug (DEBUG_INFO, "TAG: %04x type:%02d count:%02d offset:%04lx ", 
-			       de_get16(&buf[i], endian), type, count, offset);
- 
- 			// Our tag?
- 			if (bcmp (&buf[i], (char *)&tag, 2) == 0) { 
- 
-				// Write TAG value
-				if (access == 1) { 
-
-					// 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");
-						i = i + 12;
-						continue;
-					}
-					
-					if (offset + tiff + count * types[type] > sizeof (buf)) return PATCH_EXIF_TRASHED_IFD;
-
-					// Copy the data
-					stitch = 0;
-					while (stitch < count) {
-						switch (types[type]) {
-						case 1:
-							buf[tiff + offset + stitch] = *(char *) (data + stitch);
-							break;
-						case 2:
-							*((unsigned short*)(&buf[tiff + offset + stitch * 2])) = 
-								ENDIAN16_IT(*(guint16 *) (data + stitch * 2));
-							break;
-						case 4:
-							*((unsigned long*) (&buf[tiff + offset + stitch * 4])) = 
-								ENDIAN32_IT(*(guint32 *) (data + stitch * 4));
-							break;
-						default:
-							fprintf(stderr, "gth_minimal_exif_tag_write:unsupported element size\n");
-							return PATCH_EXIF_UNSUPPORTED_TYPE;
-						}
-						stitch++;
-					}
-				}
-				// Read a TAG value
-				else{ 
-					int ret = PATCH_EXIF_OK;
-
-					// Local value that can be read directly in TAG table 
-					if ((types[type] * count) <= 4 && size >= (types[type] * count)) {
- 
-						// Fake TIFF offset
-						offset = i + 8 - tiff; 
-						patches++;
-					}
-					// Offseted value of less or equal size than buffer
-					else if (types[type] * count <= size) {
-						patches++;
-					}
-					// Otherwise we are not able to read the value
-					else {
-						fprintf(stderr, "gth_minimal_exif_tag_read: TAG value does not fit, Can't read full value\n");
-						// Adjust count and warn for partial data
-						count = size / types[type];
-						ret = PATCH_EXIF_TAGVAL_OVERFLOW;
-					}
-					
-					stitch = 0;
-					while (stitch < count) {
-						switch (types[type]) {
-						case 1:
-							*(char *) (data + stitch) = buf[tiff + offset + stitch];
-							break;
-						case 2:
-							*(guint16 *) (data + stitch * 2) = 
-								de_get16(&buf[tiff + offset + stitch * 2], endian);
-							
-							break;
-						case 4:
-							*(guint32 *) (data + stitch * 4) =
-								de_get32(&buf[tiff + offset + stitch * 4], endian);
-							
-							break;
-						default:
-							fprintf(stderr, "gth_minimal_exif_tag_read:unsupported element size\n");
-							return PATCH_EXIF_UNSUPPORTED_TYPE;
-						}
-						stitch++;
-					}					
-					return ret;
-				}
-			}
- 			// 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 (DEBUG_INFO, "\n");
- 					
- 			i = i + 12;
- 		}
-
- 		// Check for a valid next pointer and assume that to be IFD1 if we just checked IFD0
- 		if (cifdi == 1 && i < readsize - tiff && (i = de_get32(&buf[i], endian)) != 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;
- 
- 	// open file rb+ (read (r) and modify (+), b indicates binary file accces on non-Unix systems
- 	if ((jf = fopen (local_file, "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; 
-}
-
-
-int
-gth_minimal_exif_tag_write (const char *local_file,
- 	                    ExifTag     etag,
- 			    void       *data,
- 			    int         size)
-{
- 	debug (DEBUG_INFO, "gth_minimal_exif_tag_write(%s, %04x, %08x, %d)\n", local_file, etag, data, size); 
-	return gth_minimal_exif_tag_action (local_file, etag, data, size, 1);
-}
-
-
 void
 write_orientation_field (const char   *local_file,
 			 GthTransform  transform)

Modified: trunk/libgthumb/gth-exif-utils.h
==============================================================================
--- trunk/libgthumb/gth-exif-utils.h	(original)
+++ trunk/libgthumb/gth-exif-utils.h	Thu Jan 31 19:30:57 2008
@@ -105,10 +105,6 @@
                                            const char   *uri_dest,
                                            const char   *tag_name,
                                            const char   *tag_value);
-int           gth_minimal_exif_tag_write  (const char   *filename,
-                                           ExifTag       etag,
-                                           void         *data,
-                                           int           size);
 void	      write_orientation_field     (const char   *filename, 
 				  	   GthTransform  transform);
 GList *       gth_read_exiv2		  (const char   *filename,

Modified: trunk/src/dlg-change-date.c
==============================================================================
--- trunk/src/dlg-change-date.c	(original)
+++ trunk/src/dlg-change-date.c	Thu Jan 31 19:30:57 2008
@@ -51,6 +51,8 @@
 	GtkWidget    *cd_last_modified_checkbutton;
 	GtkWidget    *cd_comment_checkbutton;
 	GtkWidget    *cd_exif_checkbutton;
+	GtkWidget    *cd_exif_orig_checkbutton;
+	GtkWidget    *cd_exif_dig_checkbutton;
 
 	GtkWidget    *cd_following_date_radiobutton;
 	GtkWidget    *cd_created_radiobutton;
@@ -157,7 +159,9 @@
 			comment_data_free (cdata);
 		}
 
-		if (is_active (data->cd_exif_checkbutton)) {
+		if (is_active (data->cd_exif_checkbutton) ||
+		    is_active (data->cd_exif_orig_checkbutton) ||
+		    is_active (data->cd_exif_dig_checkbutton)) {
 			char buf[32];
 			struct tm tm;
 			int    res;
@@ -184,16 +188,22 @@
 		        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 ", 
+			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, 20)) != PATCH_EXIF_OK)
-				 _gtk_error_dialog_run (GTK_WINDOW (data->dialog),
-			         	_("Could not write Exif DataTime tag. Error %d."), res);
+
+			if (is_active (data->cd_exif_checkbutton))
+				update_and_save_metadata (local_file_to_modify, local_file_to_modify, "Exif.Image.DateTime", buf);
+
+			if (is_active (data->cd_exif_orig_checkbutton))
+				update_and_save_metadata (local_file_to_modify, local_file_to_modify, "Exif.Photo.DateTimeOriginal", buf);
+
+			if (is_active (data->cd_exif_dig_checkbutton))
+                                update_and_save_metadata (local_file_to_modify, local_file_to_modify, "Exif.Photo.DateTimeDigitized", buf);
 
 			mtime++; // Step the time to enable sorting of pictures according to EXIF time
 
@@ -230,7 +240,9 @@
 	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_exif_checkbutton)));
+				  || gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->cd_exif_checkbutton))
+				  || gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->cd_exif_orig_checkbutton))
+				  || gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->cd_exif_dig_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)));
@@ -292,6 +304,8 @@
 	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_exif_orig_checkbutton = glade_xml_get_widget (data->gui, "cd_exif_orig_checkbutton");
+	data->cd_exif_dig_checkbutton = glade_xml_get_widget (data->gui, "cd_exif_dig_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");
@@ -347,6 +361,14 @@
 			  "clicked",
 			  G_CALLBACK (radio_button_clicked),
 			  data); 
+        g_signal_connect (G_OBJECT (data->cd_exif_orig_checkbutton),
+                          "clicked",
+                          G_CALLBACK (radio_button_clicked),
+                          data);
+        g_signal_connect (G_OBJECT (data->cd_exif_dig_checkbutton),
+                          "clicked",
+                          G_CALLBACK (radio_button_clicked),
+                          data);
 	
 	g_signal_connect (G_OBJECT (data->cd_following_date_radiobutton), 
 			  "clicked",



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