changeset 2698:940f217da9ec

Sort/search on Exif.Photo.DateTimeDigitized Implement sort and search on Exif.Photo.DateTimeDigitized Note: pan view not included
author Colin Clark <colin.clark@cclark.uk>
date Wed, 03 Jan 2018 20:58:28 +0000
parents f090fbf9362f
children 4a8a114c1c5a
files doc/docbook/GuideImageSearchSearch.xml doc/docbook/GuideMainWindowStatusBar.xml src/collect.c src/exif-common.c src/filedata.c src/filedata.h src/lua.c src/menu.c src/search.c src/typedefs.h web/help/GuideImageSearchSearch.html web/help/GuideMainWindowStatusBar.html
diffstat 12 files changed, 192 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/doc/docbook/GuideImageSearchSearch.xml	Wed Jan 03 17:49:15 2018 +0000
+++ b/doc/docbook/GuideImageSearchSearch.xml	Wed Jan 03 20:58:28 2018 +0000
@@ -89,7 +89,7 @@
           <guilabel>File date</guilabel>
         </term>
         <listitem>
-          The search will match if the file modification time on disk is equal to, before, after, or between the entered date, depending on the method selected from the drop down menu. The
+          The search will match if the file date is equal to, before, after, or between the entered date, depending on the method selected from the drop down menu. The
           <emphasis>between</emphasis>
           test is inclusive, for example a file with date of 10/04/2003 will match if the date parameters are between 10/04/2003 and 12/31/2003.
           <para />
@@ -103,9 +103,10 @@
           </code>
           button displays a pop up calendar to enter the date.
           <para />
-          The
-          <emphasis role="strong">Exif date</emphasis>
-          checkbox permits searches to be made on the exif date of images. If an image does not have an exif date, it will default to 01 January 1970.
+          One of four date types may be selected. They are described in the
+          <link linkend="GuideReferenceFileDates">Reference section</link>
+          .
+          <note>If an image does not have an exif date, it will default to 01 January 1970.</note>
         </listitem>
       </varlistentry>
       <varlistentry>
--- a/doc/docbook/GuideMainWindowStatusBar.xml	Wed Jan 03 17:49:15 2018 +0000
+++ b/doc/docbook/GuideMainWindowStatusBar.xml	Wed Jan 03 20:58:28 2018 +0000
@@ -39,18 +39,14 @@
       </varlistentry>
       <varlistentry>
         <term>
-          <guilabel>File Creation Date</guilabel>
+          <guilabel>File Date</guilabel>
         </term>
         <listitem>
-          <para>Images are sorted by file creation date.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term>
-          <guilabel>Exif Date</guilabel>
-        </term>
-        <listitem>
-          <para>Images are sorted by file Exif date.</para>
+          <para>
+            Images are sorted by one of four types of file date. They are described in the
+            <link linkend="GuideReferenceFileDates">Reference section</link>
+            .
+          </para>
         </listitem>
       </varlistentry>
       <varlistentry>
--- a/src/collect.c	Wed Jan 03 17:49:15 2018 +0000
+++ b/src/collect.c	Wed Jan 03 20:58:28 2018 +0000
@@ -169,6 +169,18 @@
 			if (cia->fd->cdate > cib->fd->cdate) return 1;
 			return 0;
 			break;
+		case SORT_EXIFTIME:
+			if (cia->fd->exifdate < cib->fd->exifdate) return -1;
+			if (cia->fd->exifdate > cib->fd->exifdate) return 1;
+			break;
+		case SORT_EXIFTIMEDIGITIZED:
+			if (cia->fd->exifdate_digitized < cib->fd->exifdate_digitized) return -1;
+			if (cia->fd->exifdate_digitized > cib->fd->exifdate_digitized) return 1;
+			break;
+		case SORT_RATING:
+			if (cia->fd->rating < cib->fd->rating) return -1;
+			if (cia->fd->rating > cib->fd->rating) return 1;
+			break;
 		case SORT_PATH:
 			return utf8_compare(cia->fd->path, cib->fd->path, options->file_sort.case_sensitive);
 			break;
--- a/src/exif-common.c	Wed Jan 03 17:49:15 2018 +0000
+++ b/src/exif-common.c	Wed Jan 03 20:58:28 2018 +0000
@@ -250,6 +250,57 @@
 	return text;
 }
 
+static gchar *exif_build_formatted_DateTimeDigitized(ExifData *exif)
+{
+	gchar *text = exif_get_data_as_text(exif, "Exif.Photo.DateTimeDigitized");
+	gchar *subsec = NULL;
+	gchar buf[128];
+	gchar *tmp;
+	gint buflen;
+	struct tm tm;
+	GError *error = NULL;
+
+	if (text)
+		{
+		subsec = exif_get_data_as_text(exif, "Exif.Photo.SubSecTimeDigitized");
+		}
+	else
+		{
+		text = exif_get_data_as_text(exif, "Exif.Image.DateTime");
+		if (text) subsec = exif_get_data_as_text(exif, "Exif.Photo.SubSecTime");
+		}
+
+	/* Convert the stuff into a tm struct */
+	memset(&tm, 0, sizeof(tm)); /* Uh, strptime could let garbage in tm! */
+	if (text && strptime(text, "%Y:%m:%d %H:%M:%S", &tm))
+		{
+		buflen = strftime(buf, sizeof(buf), "%x %X", &tm);
+		if (buflen > 0)
+			{
+			tmp = g_locale_to_utf8(buf, buflen, NULL, NULL, &error);
+			if (error)
+				{
+				log_printf("Error converting locale strftime to UTF-8: %s\n", error->message);
+				g_error_free(error);
+				}
+			else
+				{
+				g_free(text);
+				text = g_strdup(tmp);
+				}
+			}
+		}
+
+	if (subsec)
+		{
+		tmp = text;
+		text = g_strconcat(tmp, ".", subsec, NULL);
+		g_free(tmp);
+		g_free(subsec);
+		}
+	return text;
+}
+
 static gchar *exif_build_formatted_ShutterSpeed(ExifData *exif)
 {
 	ExifRational *r;
@@ -563,6 +614,7 @@
 ExifFormattedText ExifFormattedList[] = {
 	EXIF_FORMATTED_TAG(Camera,		N_("Camera")),
 	EXIF_FORMATTED_TAG(DateTime,		N_("Date")),
+	EXIF_FORMATTED_TAG(DateTimeDigitized,	N_("DateDigitized")),
 	EXIF_FORMATTED_TAG(ShutterSpeed,	N_("Shutter speed")),
 	EXIF_FORMATTED_TAG(Aperture,		N_("Aperture")),
 	EXIF_FORMATTED_TAG(ExposureBias,	N_("Exposure bias")),
--- a/src/filedata.c	Wed Jan 03 17:49:15 2018 +0000
+++ b/src/filedata.c	Wed Jan 03 20:58:28 2018 +0000
@@ -503,6 +503,41 @@
 		}
 }
 
+void read_exif_time_digitized_data(FileData *file)
+{
+	if (file->exifdate > 0)
+		{
+		DEBUG_1("%s set_exif_time_digitized_data: Already exists for %s", get_exec_time(), file->path);
+		return;
+		}
+
+	file->exif = exif_read_fd(file);
+
+	if (file->exif)
+		{
+		gchar *tmp = exif_get_data_as_text(file->exif, "Exif.Photo.DateTimeDigitized");
+		DEBUG_2("%s set_exif_time_digitized_data: reading %p %s", get_exec_time(), file, file->path);
+
+		if (tmp)
+			{
+			struct tm time_str;
+			uint year, month, day, hour, min, sec;
+
+			sscanf(tmp, "%4d:%2d:%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
+			time_str.tm_year  = year - 1900;
+			time_str.tm_mon   = month - 1;
+			time_str.tm_mday  = day;
+			time_str.tm_hour  = hour;
+			time_str.tm_min   = min;
+			time_str.tm_sec   = sec;
+			time_str.tm_isdst = 0;
+
+			file->exifdate_digitized = mktime(&time_str);
+			g_free(tmp);
+			}
+		}
+}
+
 void set_exif_time_data(GList *files)
 {
 	DEBUG_1("%s set_exif_time_data: ...", get_exec_time());
@@ -516,6 +551,19 @@
 		}
 }
 
+void set_exif_time_digitized_data(GList *files)
+{
+	DEBUG_1("%s set_exif_time_digitized_data: ...", get_exec_time());
+
+	while (files)
+		{
+		FileData *file = files->data;
+
+		read_exif_time_digitized_data(file);
+		files = files->next;
+		}
+}
+
 void set_rating_data(GList *files)
 {
 	gchar *rating_str;
@@ -1046,6 +1094,11 @@
 			if (fa->exifdate > fb->exifdate) return 1;
 			/* fall back to name */
 			break;
+		case SORT_EXIFTIMEDIGITIZED:
+			if (fa->exifdate_digitized < fb->exifdate_digitized) return -1;
+			if (fa->exifdate_digitized > fb->exifdate_digitized) return 1;
+			/* fall back to name */
+			break;
 		case SORT_RATING:
 			if (fa->rating < fb->rating) return -1;
 			if (fa->rating > fb->rating) return 1;
@@ -1111,6 +1164,10 @@
 		{
 		set_exif_time_data(list);
 		}
+	if (method == SORT_EXIFTIMEDIGITIZED)
+		{
+		set_exif_time_digitized_data(list);
+		}
 	if (method == SORT_RATING)
 		{
 		set_rating_data(list);
--- a/src/filedata.h	Wed Jan 03 17:49:15 2018 +0000
+++ b/src/filedata.h	Wed Jan 03 20:58:28 2018 +0000
@@ -162,5 +162,6 @@
 gboolean file_data_unregister_real_time_monitor(FileData *fd);
 
 void read_exif_time_data(FileData *file);
+void read_exif_time_digitized_data(FileData *file);
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/lua.c	Wed Jan 03 17:49:15 2018 +0000
+++ b/src/lua.c	Wed Jan 03 20:58:28 2018 +0000
@@ -167,7 +167,22 @@
 			lua_pushnil(L);
 			return 1;
 			}
-		} // if (strcmp(key, "Exif.Photo.Da...
+		}
+	else if (strcmp(key, "Exif.Photo.DateTimeDigitized") == 0)
+		{
+		memset(&tm, 0, sizeof(tm));
+		if (value && strptime(value, "%Y:%m:%d %H:%M:%S", &tm))
+			{
+			datetime = mktime(&tm);
+			lua_pushnumber(L, datetime);
+			return 1;
+			}
+		else
+			{
+			lua_pushnil(L);
+			return 1;
+			}
+		}
 	lua_pushstring(L, value);
 	return 1;
 }
--- a/src/menu.c	Wed Jan 03 17:49:15 2018 +0000
+++ b/src/menu.c	Wed Jan 03 20:58:28 2018 +0000
@@ -149,7 +149,10 @@
 			return _("Sort by file creation date");
 			break;
 		case SORT_EXIFTIME:
-			return _("Sort by Exif-date");
+			return _("Sort by Exif date original");
+			break;
+		case SORT_EXIFTIMEDIGITIZED:
+			return _("Sort by Exif date digitized");
 			break;
 		case SORT_NONE:
 			return _("Unsorted");
@@ -212,6 +215,7 @@
 	submenu_add_sort_item(submenu, func, SORT_TIME, show_current, type);
 	submenu_add_sort_item(submenu, func, SORT_CTIME, show_current, type);
 	submenu_add_sort_item(submenu, func, SORT_EXIFTIME, show_current, type);
+	submenu_add_sort_item(submenu, func, SORT_EXIFTIMEDIGITIZED, show_current, type);
 	submenu_add_sort_item(submenu, func, SORT_SIZE, show_current, type);
 	submenu_add_sort_item(submenu, func, SORT_RATING, show_current, type);
 	submenu_add_sort_item(submenu, func, SORT_CLASS, show_current, type);
--- a/src/search.c	Wed Jan 03 17:49:15 2018 +0000
+++ b/src/search.c	Wed Jan 03 20:58:28 2018 +0000
@@ -119,6 +119,7 @@
 	GtkWidget *menu_date;
 	GtkWidget *date_sel;
 	GtkWidget *date_sel_end;
+	GtkWidget *date_type;
 
 	GtkWidget *check_dimensions;
 	GtkWidget *menu_dimensions;
@@ -172,7 +173,6 @@
 	gint   search_rating;
 	gint   search_rating_end;
 	gboolean   search_comment_match_case;
-	gboolean   search_date_exif;
 
 	MatchType search_type;
 
@@ -1859,11 +1859,23 @@
 		tested = TRUE;
 		match = FALSE;
 
-		if (sd->search_date_exif)
+		if (g_strcmp0(gtk_combo_box_text_get_active_text(
+						GTK_COMBO_BOX_TEXT(sd->date_type)), _("Changed")) == 0)
+			{
+			file_date = fd->cdate;
+			}
+		else if (g_strcmp0(gtk_combo_box_text_get_active_text(
+						GTK_COMBO_BOX_TEXT(sd->date_type)), _("Original")) == 0)
 			{
 			read_exif_time_data(fd);
 			file_date = fd->exifdate;
 			}
+		else if (g_strcmp0(gtk_combo_box_text_get_active_text(
+						GTK_COMBO_BOX_TEXT(sd->date_type)), _("Digitized")) == 0)
+			{
+			read_exif_time_digitized_data(fd);
+			file_date = fd->exifdate_digitized;
+			}
 		else
 			{
 			file_date = fd->date;
@@ -2998,6 +3010,7 @@
 			   _("File date is"), &sd->match_date_enable,
 			   text_search_menu_date, sizeof(text_search_menu_date) / sizeof(MatchList),
 			   G_CALLBACK(menu_choice_date_cb), sd);
+
 	sd->date_sel = date_selection_new();
 	date_selection_time_set(sd->date_sel, time(NULL));
 	gtk_box_pack_start(GTK_BOX(hbox), sd->date_sel, FALSE, FALSE, 0);
@@ -3010,8 +3023,16 @@
 	date_selection_time_set(sd->date_sel_end, time(NULL));
 	gtk_box_pack_start(GTK_BOX(hbox2), sd->date_sel_end, FALSE, FALSE, 0);
 	gtk_widget_show(sd->date_sel_end);
-	pref_checkbox_new_int(hbox, _("Exif date"),
-				sd->search_date_exif, &sd->search_date_exif);
+
+	sd->date_type = gtk_combo_box_text_new();
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->date_type), _("Modified"));
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->date_type), _("Status Changed"));
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->date_type), _("Original"));
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->date_type), _("Digitized"));
+	gtk_box_pack_start(GTK_BOX(hbox), sd->date_type, FALSE, FALSE, 0);
+	gtk_combo_box_set_active(GTK_COMBO_BOX(sd->date_type), 0);
+	gtk_widget_set_tooltip_text(sd->date_type, "Modified (mtime)\nStatus Changed (ctime)\nOriginal (Exif.Photo.DateTimeOriginal)\nDigitized (Exif.Photo.DateTimeDigitized)");
+	gtk_widget_show(sd->date_type);
 
 	/* Search for image dimensions */
 	hbox = menu_choice(sd->box_search, &sd->check_dimensions, &sd->menu_dimensions,
--- a/src/typedefs.h	Wed Jan 03 17:49:15 2018 +0000
+++ b/src/typedefs.h	Wed Jan 03 20:58:28 2018 +0000
@@ -74,6 +74,7 @@
 	SORT_PATH,
 	SORT_NUMBER,
 	SORT_EXIFTIME,
+	SORT_EXIFTIMEDIGITIZED,
 	SORT_RATING,
 	SORT_CLASS
 } SortType;
@@ -588,6 +589,7 @@
 
 	ExifData *exif;
 	time_t exifdate;
+	time_t exifdate_digitized;
 	GHashTable *modified_xmp; // hash table which contains unwritten xmp metadata in format: key->list of string values
 	GList *cached_metadata;
 	gint rating;
--- a/web/help/GuideImageSearchSearch.html	Wed Jan 03 17:49:15 2018 +0000
+++ b/web/help/GuideImageSearchSearch.html	Wed Jan 03 20:58:28 2018 +0000
@@ -543,7 +543,7 @@
           <span class="guilabel">File date</span>
         </dt>
 <dd>
-          The search will match if the file modification time on disk is equal to, before, after, or between the entered date, depending on the method selected from the drop down menu. The
+          The search will match if the file date is equal to, before, after, or between the entered date, depending on the method selected from the drop down menu. The
           <span class="emphasis">between</span>
           test is inclusive, for example a file with date of 10/04/2003 will match if the date parameters are between 10/04/2003 and 12/31/2003.
           <p class="para block"></p>
@@ -557,9 +557,10 @@
           </span>
           button displays a pop up calendar to enter the date.
           <p class="para block"></p>
-          The
-          <span class="emphasis emphasis-bold">Exif date</span>
-          checkbox permits searches to be made on the exif date of images. If an image does not have an exif date, it will default to 01 January 1970.
+          One of four date types may be selected. They are described in the
+          <a class="link" href=".html#GuideReferenceFileDates" title="">Reference section</a>
+          .
+          <div class="admonition block note block-indent"><div class="note-inner">If an image does not have an exif date, it will default to 01 January 1970.</div></div>
         </dd>
 <dt class="term">
           <span class="guilabel">Image dimensions</span>
--- a/web/help/GuideMainWindowStatusBar.html	Wed Jan 03 17:49:15 2018 +0000
+++ b/web/help/GuideMainWindowStatusBar.html	Wed Jan 03 20:58:28 2018 +0000
@@ -501,16 +501,14 @@
           <p class="para block block-first">Images are sorted by file modification date.</p>
         </dd>
 <dt class="term">
-          <span class="guilabel">File Creation Date</span>
+          <span class="guilabel">File Date</span>
         </dt>
 <dd>
-          <p class="para block block-first">Images are sorted by file creation date.</p>
-        </dd>
-<dt class="term">
-          <span class="guilabel">Exif Date</span>
-        </dt>
-<dd>
-          <p class="para block block-first">Images are sorted by file Exif date.</p>
+          <p class="para block block-first">
+            Images are sorted by one of four types of file date. They are described in the
+            <a class="link" href=".html#GuideReferenceFileDates" title="">Reference section</a>
+            .
+          </p>
         </dd>
 <dt class="term">
           <span class="guilabel">Size</span>