Mercurial > hg > forks > geeqie
changeset 2823:938790283e32
Additional parameters from ZoneDetect
Additional parameters derived from GPS data:
formatted.countryname - ISO 3166 country name
formatted.countrycode - ISO 3166 two-letter country code
author | Colin Clark <colin.clark@cclark.uk> |
---|---|
date | Tue, 21 Aug 2018 17:02:20 +0100 |
parents | 087b44aa5a0a |
children | c9eded8ad4e0 |
files | doc/docbook/GuideReferenceTags.xml doc/docbook/GuideSidebarsInfo.xml src/exif-common.c web/help/GuideReferenceXmpExif.html web/help/GuideSidebarsInfo.html |
diffstat | 5 files changed, 253 insertions(+), 144 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/docbook/GuideReferenceTags.xml Tue Aug 21 12:21:17 2018 +0100 +++ b/doc/docbook/GuideReferenceTags.xml Tue Aug 21 17:02:20 2018 +0100 @@ -301,6 +301,44 @@ </row> <row> <entry> + <para>formatted.countryname</para> + </entry> + <entry> + <para> + Exif.GPSInfo.GPSLatitude + <para /> + Exif.GPSInfo.GPSLatitudeRef + <para /> + Exif.GPSInfo.GPSLongitude + <para /> + Exif.GPSInfo.GPSLongitudeRef + </para> + </entry> + <entry> + <para>ISO 3166 country name indicated by lat/long</para> + </entry> + </row> + <row> + <entry> + <para>formatted.countrycode</para> + </entry> + <entry> + <para> + Exif.GPSInfo.GPSLatitude + <para /> + Exif.GPSInfo.GPSLatitudeRef + <para /> + Exif.GPSInfo.GPSLongitude + <para /> + Exif.GPSInfo.GPSLongitudeRef + </para> + </entry> + <entry> + <para>ISO 3166 two-letter abbreviated country name indicated by lat/long</para> + </entry> + </row> + <row> + <entry> <para>formatted.star_rating</para> </entry> <entry>
--- a/doc/docbook/GuideSidebarsInfo.xml Tue Aug 21 12:21:17 2018 +0100 +++ b/doc/docbook/GuideSidebarsInfo.xml Tue Aug 21 17:02:20 2018 +0100 @@ -282,6 +282,14 @@ </entry> </row> <row> + <entry>formatted.countryname</entry> + <entry>ISO 3166 country name indicated by GPS lat/long values</entry> + </row> + <row> + <entry>formatted.countrycode</entry> + <entry>ISO 3166 two-letter abbreviated country name indicated by GPS lat/long values</entry> + </row> + <row> <entry>file.size</entry> <entry>file size in bytes</entry> </row>
--- a/src/exif-common.c Tue Aug 21 12:21:17 2018 +0100 +++ b/src/exif-common.c Tue Aug 21 17:02:20 2018 +0100 @@ -612,25 +612,21 @@ } /** - * @brief Extracts timezone from a ZoneDetect search structure - * @param results ZoneDetect search structure - * @returns Timezone in the form "Europe/London" + * @brief Extracts timezone data from a ZoneDetect search structure + * @param[in] results ZoneDetect search structure + * @param[out] timezone in the form "Europe/London" + * @param[out] countryname in the form "United Kingdom" + * @param[out] countryalpha2 in the form "GB" * * Refer to https://github.com/BertoldVdb/ZoneDetect * for structure details */ -static gchar *zd_tz(ZoneDetectResult* results) +static void zd_tz(ZoneDetectResult *results, gchar **timezone, gchar **countryname, gchar **countryalpha2) { - gchar *timezone = NULL; gchar *timezone_pre = NULL; gchar *timezone_id = NULL; unsigned int index = 0; - if (!results) - { - return NULL; - } - while(results[index].lookupResult != ZD_LOOKUP_END) { if(results[index].data) @@ -645,29 +641,36 @@ { timezone_id = g_strdup(results[index].data[i]); } + if (g_strstr_len(results[index].fieldNames[i], -1, "CountryName")) + { + *countryname = g_strdup(results[index].data[i]); + } + if (g_strstr_len(results[index].fieldNames[i], -1, "CountryAlpha2")) + { + *countryalpha2 = g_strdup(results[index].data[i]); + } } } index++; } - timezone = g_strconcat(timezone_pre, timezone_id, NULL); + *timezone = g_strconcat(timezone_pre, timezone_id, NULL); g_free(timezone_pre); g_free(timezone_id); - return timezone; } /** - * @brief Creates local time from GPS lat/long - * @param exif - * @returns Localised time and date - * - * GPS lat/long is translated to timezone using ZoneDetect. - * GPS UTC is converted to Unix time stamp (seconds since 1970). - * The TZ environment variable is set to the relevant timezone - * and the Unix timestamp converted to local time using locale. - * If the conversion fails, unformatted UTC is returned. + * @brief Gets timezone data from an exif structure + * @param[in] exif + * @returns TRUE if timezone data found + * @param[out] exif_date_time exif date/time in the form 2018:11:30:17:05:04 + * @param[out] timezone in the form "Europe/London" + * @param[out] countryname in the form "United Kingdom" + * @param[out] countryalpha2 in the form "GB" + * + * */ -static gchar *exif_build_formatted_localtime(ExifData *exif) +static gboolean exif_build_tz_data(ExifData *exif, gchar **exif_date_time, gchar **timezone, gchar **countryname, gchar **countryalpha2) { gfloat latitude; gfloat longitude; @@ -677,24 +680,14 @@ gchar *text_longitude_ref; gchar *text_date; gchar *text_time; - gchar *text_date_time = NULL; - gchar buf[128]; - gchar *tmp; - gint buflen; - GError *error = NULL; gchar *lat_deg; gchar *lat_min; gchar *lon_deg; gchar *lon_min; - gchar *time_zone; - gchar *time_zone_org; - struct tm *tm_local; - struct tm tm_utc; - time_t stamp; gchar *zd_path; - gchar *zone_selected; ZoneDetect *cd; ZoneDetectResult *results; + gboolean ret = FALSE; text_latitude = exif_get_data_as_text(exif, "Exif.GPSInfo.GPSLatitude"); text_longitude = exif_get_data_as_text(exif, "Exif.GPSInfo.GPSLongitude"); @@ -706,7 +699,7 @@ if (text_latitude && text_longitude && text_latitude_ref && text_longitude_ref && text_date && text_time) { - text_date_time = g_strconcat(text_date, ":", text_time, NULL); + *exif_date_time = g_strconcat(text_date, ":", text_time, NULL); lat_deg = strtok(text_latitude, "deg'"); lat_min = strtok(NULL, "deg'"); @@ -730,42 +723,11 @@ if (cd) { results = ZDLookup(cd, latitude, longitude, NULL); - zone_selected = zd_tz(results); - time_zone = g_strconcat("TZ=", zone_selected, NULL); - time_zone_org = g_strconcat("TZ=", getenv("TZ"), NULL); - putenv("TZ=UTC"); - g_free(zone_selected); - - memset(&tm_utc, 0, sizeof(tm_utc)); - if (text_date_time && strptime(text_date_time, "%Y:%m:%d:%H:%M:%S", &tm_utc)) + if (results) { - stamp = mktime(&tm_utc); // Convert the struct to a Unix timestamp - putenv(time_zone); // Switch to destination time zone - - tm_local = localtime(&stamp); - - /* Convert to localtime using locale */ - buflen = strftime(buf, sizeof(buf), "%x %X", tm_local); - 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_date_time); - text_date_time = g_strdup(tmp); - } - } - g_free(tmp); + zd_tz(results, timezone, countryname, countryalpha2); + ret = TRUE; } - putenv(time_zone_org); - - g_free(time_zone); - g_free(time_zone_org); } else { @@ -776,96 +738,149 @@ g_free(zd_path); } - g_free(text_latitude); - g_free(text_longitude); - g_free(text_latitude_ref); - g_free(text_longitude_ref); - g_free(text_date); - g_free(text_time); + return ret; +} + +/** + * @brief Creates local time from GPS lat/long + * @param[in] exif + * @returns Localised time and date + * + * GPS lat/long is translated to timezone using ZoneDetect. + * GPS UTC is converted to Unix time stamp (seconds since 1970). + * The TZ environment variable is set to the relevant timezone + * and the Unix timestamp converted to local time using locale. + * If the conversion fails, unformatted UTC is returned. + */ +static gchar *exif_build_formatted_localtime(ExifData *exif) +{ + gchar buf[128]; + gchar *tmp; + gint buflen; + GError *error = NULL; + gchar *time_zone_image; + gchar *time_zone_org; + struct tm *tm_local; + struct tm tm_utc; + time_t stamp; + gchar *exif_date_time = NULL; + gchar *timezone = NULL; + gchar *countryname = NULL; + gchar *countryalpha2 = NULL; + + if (exif_build_tz_data(exif, &exif_date_time, &timezone, &countryname, &countryalpha2)) + { + time_zone_image = g_strconcat("TZ=", timezone, NULL); + time_zone_org = g_strconcat("TZ=", getenv("TZ"), NULL); + putenv("TZ=UTC"); - return text_date_time; + memset(&tm_utc, 0, sizeof(tm_utc)); + if (exif_date_time && strptime(exif_date_time, "%Y:%m:%d:%H:%M:%S", &tm_utc)) + { + stamp = mktime(&tm_utc); // Convert the struct to a Unix timestamp + putenv(time_zone_image); // Switch to destination time zone + + tm_local = localtime(&stamp); + + /* Convert to localtime using locale */ + buflen = strftime(buf, sizeof(buf), "%x %X", tm_local); + 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(exif_date_time); + exif_date_time = g_strdup(tmp); + } + } + g_free(tmp); + } + putenv(time_zone_org); + + g_free(time_zone_image); + g_free(time_zone_org); + } + + g_free(timezone); + g_free(countryname); + g_free(countryalpha2); + + return exif_date_time; } /** * @brief Gets timezone from GPS lat/long - * @param exif + * @param[in] exif * @returns Timezone string in the form "Europe/London" - * - * + * + * */ static gchar *exif_build_formatted_timezone(ExifData *exif) { - gfloat latitude; - gfloat longitude; - gchar *text_latitude; - gchar *text_longitude; - gchar *text_latitude_ref; - gchar *text_longitude_ref; - gchar *lat_deg; - gchar *lat_min; - gchar *lon_deg; - gchar *lon_min; gchar *time_zone = NULL; - gchar *zd_path; - ZoneDetect *cd; - ZoneDetectResult *results; + gchar *exif_date_time = NULL; + gchar *timezone = NULL; + gchar *countryname = NULL; + gchar *countryalpha2 = NULL; + + exif_build_tz_data(exif, &exif_date_time, &timezone, &countryname, &countryalpha2); + + g_free(exif_date_time); + g_free(countryname); + g_free(countryalpha2); + + return timezone; +} - text_latitude = exif_get_data_as_text(exif, "Exif.GPSInfo.GPSLatitude"); - text_longitude = exif_get_data_as_text(exif, "Exif.GPSInfo.GPSLongitude"); - text_latitude_ref = exif_get_data_as_text(exif, "Exif.GPSInfo.GPSLatitudeRef"); - text_longitude_ref = exif_get_data_as_text(exif, "Exif.GPSInfo.GPSLongitudeRef"); +/** + * @brief Gets countryname from GPS lat/long + * @param[in] exif + * @returns Countryname string + * + * + */ +static gchar *exif_build_formatted_countryname(ExifData *exif) +{ + gchar *exif_date_time = NULL; + gchar *timezone = NULL; + gchar *countryname = NULL; + gchar *countryalpha2 = NULL; - if ((text_latitude && g_strrstr(text_latitude, "deg")) && - (text_longitude && g_strrstr(text_longitude, "deg")) && - ( - (text_latitude_ref && g_strrstr(text_latitude_ref, "N")) || - (text_latitude_ref && g_strrstr(text_latitude_ref, "S")) - ) && - ( - (text_longitude_ref && g_strrstr(text_longitude_ref, "E")) || - (text_longitude_ref && g_strrstr(text_longitude_ref, "W")) - ) - ) - { - lat_deg = strtok(text_latitude, "deg'"); - lat_min = strtok(NULL, "deg'"); - latitude = atof(lat_deg) + atof(lat_min) / 60; - if (g_strcmp0(text_latitude_ref, "South") == 0) - { - latitude = -latitude; - } - lon_deg = strtok(text_longitude, "deg'"); - lon_min = strtok(NULL, "deg'"); - longitude = atof(lon_deg) + atof(lon_min) / 60; - if (g_strcmp0(text_longitude_ref, "West") == 0) - { - longitude = -longitude; - } - zd_path = g_build_filename(GQ_BIN_DIR, TIMEZONE_DATABASE, NULL); - if (g_file_test(zd_path, G_FILE_TEST_EXISTS)) - { - cd = ZDOpenDatabase(zd_path); - if (cd) - { - results = ZDLookup(cd, latitude, longitude, NULL); - time_zone = zd_tz(results); - ZDFreeResults(results); - } - else - { - log_printf("Error: Init of timezone database %s failed\n", zd_path); - } - ZDCloseDatabase(cd); - } - g_free(zd_path); - } + exif_build_tz_data(exif, &exif_date_time, &timezone, &countryname, &countryalpha2); + + g_free(exif_date_time); + g_free(timezone); + g_free(countryalpha2); + + return countryname; +} - g_free(text_latitude); - g_free(text_longitude); - g_free(text_latitude_ref); - g_free(text_longitude_ref); +/** + * @brief Gets two-letter country code from GPS lat/long + * @param[in] exif + * @returns Countryalpha2 string + * + * + */ +static gchar *exif_build_formatted_countrycode(ExifData *exif) +{ + gchar *exif_date_time = NULL; + gchar *timezone = NULL; + gchar *countryname = NULL; + gchar *countryalpha2 = NULL; - return time_zone; + exif_build_tz_data(exif, &exif_date_time, &timezone, &countryname, &countryalpha2); + + g_free(exif_date_time); + g_free(timezone); + g_free(countryname); + + return countryalpha2; } static gchar *exif_build_formatted_star_rating(ExifData *exif) @@ -898,6 +913,8 @@ EXIF_FORMATTED_TAG(GPSAltitude, N_("GPS altitude")), EXIF_FORMATTED_TAG(localtime, N_("Local time")), EXIF_FORMATTED_TAG(timezone, N_("Time zone")), + EXIF_FORMATTED_TAG(countryname, N_("Country name")), + EXIF_FORMATTED_TAG(countrycode, N_("Country code")), EXIF_FORMATTED_TAG(star_rating, N_("Star rating")), {"file.size", N_("File size"), NULL}, {"file.date", N_("File date"), NULL},
--- a/web/help/GuideReferenceXmpExif.html Tue Aug 21 12:21:17 2018 +0100 +++ b/web/help/GuideReferenceXmpExif.html Tue Aug 21 17:02:20 2018 +0100 @@ -756,6 +756,44 @@ </td> </tr> <tr> +<td class="td-colsep td-rowsep"> + <span class="para">formatted.countryname</span> + </td> +<td class="td-colsep td-rowsep"> + <span class="para"> + Exif.GPSInfo.GPSLatitude + <p class="para block block-first"></p> + Exif.GPSInfo.GPSLatitudeRef + <p class="para block"></p> + Exif.GPSInfo.GPSLongitude + <p class="para block"></p> + Exif.GPSInfo.GPSLongitudeRef + </span> + </td> +<td class="td-rowsep"> + <span class="para">ISO 3166 country name indicated by lat/long</span> + </td> +</tr> +<tr class="tr-shade"> +<td class="td-colsep td-rowsep"> + <span class="para">formatted.countrycode</span> + </td> +<td class="td-colsep td-rowsep"> + <span class="para"> + Exif.GPSInfo.GPSLatitude + <p class="para block block-first"></p> + Exif.GPSInfo.GPSLatitudeRef + <p class="para block"></p> + Exif.GPSInfo.GPSLongitude + <p class="para block"></p> + Exif.GPSInfo.GPSLongitudeRef + </span> + </td> +<td class="td-rowsep"> + <span class="para">ISO 3166 two-letter abbreviated country name indicated by lat/long</span> + </td> +</tr> +<tr> <td class="td-colsep"> <span class="para">formatted.star_rating</span> </td>
--- a/web/help/GuideSidebarsInfo.html Tue Aug 21 12:21:17 2018 +0100 +++ b/web/help/GuideSidebarsInfo.html Tue Aug 21 17:02:20 2018 +0100 @@ -727,6 +727,14 @@ </td> </tr> <tr class="tr-shade"> +<td class="td-colsep td-rowsep">formatted.countryname</td> +<td class="td-rowsep">ISO 3166 country name indicated by GPS lat/long values</td> +</tr> +<tr> +<td class="td-colsep td-rowsep">formatted.countrycode</td> +<td class="td-rowsep">ISO 3166 two-letter abbreviated country name indicated by GPS lat/long values</td> +</tr> +<tr class="tr-shade"> <td class="td-colsep td-rowsep">file.size</td> <td class="td-rowsep">file size in bytes</td> </tr>