From: Colin Clark Date: Wed, 3 Jan 2018 20:58:28 +0000 (+0000) Subject: Sort/search on Exif.Photo.DateTimeDigitized X-Git-Tag: v1.5~189 X-Git-Url: http://geeqie.org/cgi-bin/gitweb.cgi?p=geeqie.git;a=commitdiff_plain;h=0ef10ad0e7864cad4ec6e79029a39369e3c9fa9a Sort/search on Exif.Photo.DateTimeDigitized Implement sort and search on Exif.Photo.DateTimeDigitized Note: pan view not included --- diff --git a/doc/docbook/GuideImageSearchSearch.xml b/doc/docbook/GuideImageSearchSearch.xml index 55a70822..210493e8 100644 --- a/doc/docbook/GuideImageSearchSearch.xml +++ b/doc/docbook/GuideImageSearchSearch.xml @@ -89,7 +89,7 @@ File date - 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 between 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. @@ -103,9 +103,10 @@ button displays a pop up calendar to enter the date. - The - Exif date - 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 + Reference section + . + If an image does not have an exif date, it will default to 01 January 1970. diff --git a/doc/docbook/GuideMainWindowStatusBar.xml b/doc/docbook/GuideMainWindowStatusBar.xml index 6c327032..dbbb36f9 100644 --- a/doc/docbook/GuideMainWindowStatusBar.xml +++ b/doc/docbook/GuideMainWindowStatusBar.xml @@ -39,18 +39,14 @@ - File Creation Date + File Date - Images are sorted by file creation date. - - - - - Exif Date - - - Images are sorted by file Exif date. + + Images are sorted by one of four types of file date. They are described in the + Reference section + . + diff --git a/src/collect.c b/src/collect.c index cc2dd6e6..57730136 100644 --- a/src/collect.c +++ b/src/collect.c @@ -169,6 +169,18 @@ static gint collection_list_sort_cb(gconstpointer a, gconstpointer b) 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; diff --git a/src/exif-common.c b/src/exif-common.c index 155898e5..2af25a56 100644 --- a/src/exif-common.c +++ b/src/exif-common.c @@ -250,6 +250,57 @@ static gchar *exif_build_formatted_DateTime(ExifData *exif) 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 @@ static gchar *exif_build_formatted_GPSAltitude(ExifData *exif) 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")), diff --git a/src/filedata.c b/src/filedata.c index 301f448d..d0c6484f 100644 --- a/src/filedata.c +++ b/src/filedata.c @@ -503,6 +503,41 @@ void read_exif_time_data(FileData *file) } } +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_data(GList *files) } } +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 @@ gint filelist_sort_compare_filedata(FileData *fa, FileData *fb) 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 @@ GList *filelist_sort(GList *list, SortType method, gboolean ascend) { set_exif_time_data(list); } + if (method == SORT_EXIFTIMEDIGITIZED) + { + set_exif_time_digitized_data(list); + } if (method == SORT_RATING) { set_rating_data(list); diff --git a/src/filedata.h b/src/filedata.h index ea29f2f7..367996dd 100644 --- a/src/filedata.h +++ b/src/filedata.h @@ -162,5 +162,6 @@ gboolean file_data_register_real_time_monitor(FileData *fd); 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: */ diff --git a/src/lua.c b/src/lua.c index 72b02cdd..eabbad0e 100644 --- a/src/lua.c +++ b/src/lua.c @@ -167,7 +167,22 @@ static int lua_exif_get_datum(lua_State *L) 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; } diff --git a/src/menu.c b/src/menu.c index 8fc69956..6c1d38b1 100644 --- a/src/menu.c +++ b/src/menu.c @@ -149,7 +149,10 @@ gchar *sort_type_get_text(SortType method) 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 @@ GtkWidget *submenu_add_sort(GtkWidget *menu, GCallback func, gpointer data, 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); diff --git a/src/search.c b/src/search.c index f0463022..cbe235b3 100644 --- a/src/search.c +++ b/src/search.c @@ -119,6 +119,7 @@ struct _SearchData GtkWidget *menu_date; GtkWidget *date_sel; GtkWidget *date_sel_end; + GtkWidget *date_type; GtkWidget *check_dimensions; GtkWidget *menu_dimensions; @@ -172,7 +173,6 @@ struct _SearchData gint search_rating; gint search_rating_end; gboolean search_comment_match_case; - gboolean search_date_exif; MatchType search_type; @@ -1859,11 +1859,23 @@ static gboolean search_file_next(SearchData *sd) 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 @@ void search_new(FileData *dir_fd, FileData *example_file) _("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 @@ void search_new(FileData *dir_fd, FileData *example_file) 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, diff --git a/src/typedefs.h b/src/typedefs.h index 6f250271..134adb0c 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -74,6 +74,7 @@ typedef enum { SORT_PATH, SORT_NUMBER, SORT_EXIFTIME, + SORT_EXIFTIMEDIGITIZED, SORT_RATING, SORT_CLASS } SortType; @@ -588,6 +589,7 @@ struct _FileData { 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; diff --git a/web/help/GuideImageSearchSearch.html b/web/help/GuideImageSearchSearch.html index 30180097..82aa5a9e 100644 --- a/web/help/GuideImageSearchSearch.html +++ b/web/help/GuideImageSearchSearch.html @@ -543,7 +543,7 @@ dd.answer div.label { float: left; } File date
- 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 between 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.

@@ -557,9 +557,10 @@ dd.answer div.label { float: left; } button displays a pop up calendar to enter the date.

- The - Exif date - 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 + Reference section + . +
If an image does not have an exif date, it will default to 01 January 1970.
Image dimensions diff --git a/web/help/GuideMainWindowStatusBar.html b/web/help/GuideMainWindowStatusBar.html index 5a1e458f..77ebd847 100644 --- a/web/help/GuideMainWindowStatusBar.html +++ b/web/help/GuideMainWindowStatusBar.html @@ -501,16 +501,14 @@ dd.answer div.label { float: left; }

Images are sorted by file modification date.

- File Creation Date + File Date
-

Images are sorted by file creation date.

-
-
- Exif Date -
-
-

Images are sorted by file Exif date.

+

+ Images are sorted by one of four types of file date. They are described in the + Reference section + . +

Size