diff options
Diffstat (limited to 'src/exif.c')
-rw-r--r-- | src/exif.c | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/src/exif.c b/src/exif.c new file mode 100644 index 0000000..6b0719d --- /dev/null +++ b/src/exif.c @@ -0,0 +1,439 @@ +/* exif.c + +Copyright (C) 2012 Dennis Real. +Copyright (C) 2021 Birte Kristina Friesel. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies of the Software and its documentation and acknowledgment shall be +given in the documentation and software packages that this Software was +used. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#ifdef HAVE_LIBEXIF + +#include <stdio.h> +#include <string.h> +#include <libexif/exif-data.h> +#include <limits.h> + +#include "feh.h" +#include "options.h" +#include "debug.h" +#include "exif.h" +#include "exif_canon.h" +#include "exif_nikon.h" +#include "exif_cfg.h" + + +/* remove all spaces on the right end of a string */ +void exif_trim_spaces(char *str) +{ + char *end; + + for (end = str; *str != '\0'; str++) { + if (*str != ' ') { + end = str + 1; + } + } + *end = '\0'; +} + + + +/* show given exif tag content with tag name */ +void exif_get_tag(ExifData * d, ExifIfd ifd, ExifTag tag, char *buffer, + unsigned int maxsize) +{ + char s[EXIF_MAX_DATA]; + ExifEntry *entry = NULL; + + if ((d != NULL) && (buffer != NULL) && (maxsize > 0)) { + entry = exif_content_get_entry(d->ifd[ifd], tag); + if (entry != NULL) { + /* Get the contents of the tag in human-readable form */ + exif_entry_get_value(entry, s, EXIF_MAX_DATA); + + /* Don't bother printing it if it's entirely blank */ + exif_trim_spaces(s); + if (*s != '\0') { + D(("%s: %s\n", + exif_tag_get_name_in_ifd(tag, ifd), s)); + snprintf(buffer, (size_t) maxsize, + "%s: %s\n", + exif_tag_get_name_in_ifd(tag, + ifd), s); + } + } + } +} + + + +/* show given exif tag content without tag name */ +void exif_get_tag_content(ExifData * d, ExifIfd ifd, ExifTag tag, + char *buffer, unsigned int maxsize) +{ + char s[EXIF_MAX_DATA]; + ExifEntry *entry = NULL; + + if ((d != NULL) && (buffer != NULL) && (maxsize > 0)) { + entry = exif_content_get_entry(d->ifd[ifd], tag); + if (entry != NULL) { + /* Get the contents of the tag in human-readable form */ + exif_entry_get_value(entry, s, EXIF_MAX_DATA); + + /* Don't bother printing it if it's entirely blank */ + exif_trim_spaces(s); + if (*s != '\0') { + D(("%s - %s\n", + exif_tag_get_name_in_ifd(tag, ifd), s)); + snprintf(buffer, (size_t) maxsize, "%s", + s); + } + } + } + +} + + + +/* Show the given MakerNote tag if it exists */ +void exif_get_mnote_tag(ExifData * d, unsigned int tag, char *buffer, + unsigned int maxsize) +{ + ExifMnoteData *mn = NULL; + int i, num; + char buf[1024]; + + if ((d != NULL) && (buffer != NULL) && (maxsize > 0)) { + mn = exif_data_get_mnote_data(d); + } else { + return; + } + + if (mn != NULL) { + num = exif_mnote_data_count(mn); + + /* Loop through all MakerNote tags, searching for the desired one */ + for (i = 0; i < num; ++i) { + D(("%d/%d %d 0x%2x %s; %s\n", i, num, + exif_mnote_data_get_id(mn, i), + exif_mnote_data_get_id(mn, i), + exif_mnote_data_get_name(mn, i), + exif_mnote_data_get_title(mn, i))); + + if (exif_mnote_data_get_id(mn, i) == tag) { + if (exif_mnote_data_get_value + (mn, i, buf, sizeof(buf))) { + /* Don't bother printing it if it's entirely blank */ + exif_trim_spaces(buf); + if (*buf != '\0') { + D(("%s\n", buf)); + snprintf(buffer, + (size_t) maxsize, + "%s: %s\n", + exif_mnote_data_get_title + (mn, i), buf); + } + } + } + } + } +} + +void exif_get_make_model_lens(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char make[EXIF_STD_BUF_LEN]; + char model[EXIF_STD_BUF_LEN]; + char lens[EXIF_STD_BUF_LEN]; + unsigned int offset = 0; + + make[0] = model[0] = lens[0] = '\0'; + + exif_get_tag_content(ed, EXIF_IFD_0, EXIF_TAG_MAKE, make, sizeof(make)); + exif_get_tag_content(ed, EXIF_IFD_0, EXIF_TAG_MODEL, model, sizeof(model)); + exif_get_tag_content(ed, EXIF_IFD_EXIF, 0xa434, lens, sizeof(lens)); + + if (make[0] && strncmp(make, model, strlen(make)) != 0) { + offset += snprintf(buffer, maxsize, "%s ", make); + } + if (model[0]) { + offset += snprintf(buffer + offset, maxsize - offset, "%s", model); + } + if (lens[0]) { + offset += snprintf(buffer + offset, maxsize - offset, " + %s", lens); + } + snprintf(buffer + offset, maxsize - offset, "\n"); +} + +void exif_get_exposure(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char fnumber[EXIF_STD_BUF_LEN]; + char exposure[EXIF_STD_BUF_LEN]; + char iso[EXIF_STD_BUF_LEN]; + char focus[EXIF_STD_BUF_LEN]; + char focus35[EXIF_STD_BUF_LEN]; + unsigned int offset = 0; + + fnumber[0] = exposure[0] = iso[0] = '\0'; + focus[0] = focus35[0] = '\0'; + + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, fnumber, sizeof(fnumber)); + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, exposure, sizeof(exposure)); + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, iso, sizeof(iso)); + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, focus, sizeof(focus)); + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM, focus35, sizeof(focus35)); + + if (fnumber[0] || exposure[0]) { + offset += snprintf(buffer, maxsize, "%s %s ", fnumber, exposure); + } + if (iso[0]) { + offset += snprintf(buffer + offset, maxsize - offset, "ISO%s ", iso); + } + if (focus[0] && focus35[0]) { + snprintf(buffer + offset, maxsize - offset, "%s (%s mm)\n", focus, focus35); + } else if (focus[0]) { + snprintf(buffer + offset, maxsize - offset, "%s\n", focus); + } +} + +void exif_get_flash(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char flash[EXIF_STD_BUF_LEN]; + + flash[0] = '\0'; + + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_FLASH, flash, sizeof(flash)); + + if (flash[0]) { + snprintf(buffer, maxsize, "%s\n", flash); + } +} + +void exif_get_mode(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char mode[EXIF_STD_BUF_LEN]; + char program[EXIF_STD_BUF_LEN]; + + mode[0] = program[0] = '\0'; + + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_MODE, mode, sizeof(mode)); + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_PROGRAM, program, sizeof(program)); + + if (mode[0] || program[0]) { + snprintf(buffer, maxsize, "%s (%s)\n", mode, program); + } +} + +void exif_get_datetime(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char datetime[EXIF_STD_BUF_LEN]; + + datetime[0] = '\0'; + + exif_get_tag_content(ed, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, datetime, sizeof(datetime)); + + if (datetime[0]) { + snprintf(buffer, maxsize, "%s\n", datetime); + } +} + +void exif_get_description(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char description[EXIF_STD_BUF_LEN]; + + description[0] = '\0'; + + exif_get_tag_content(ed, EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION, description, sizeof(description)); + + if (description[0]) { + snprintf(buffer, maxsize, "\"%s\"\n", description); + } +} + + +/* get gps coordinates if available */ +void exif_get_gps_coords(ExifData * ed, char *buffer, unsigned int maxsize) +{ + char buf[EXIF_STD_BUF_LEN]; + + buf[0] = '\0'; + exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF, + buf, sizeof(buf)); + if (buf[0] != '\0') { + snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), + "GPS: %s ", buf); + } else { + return; + } + + buf[0] = '\0'; + exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE, buf, + sizeof(buf)); + if (buf[0] != '\0') { + snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), + "%s ", buf); + } else { + return; + } + + buf[0] = '\0'; + exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF, + buf, sizeof(buf)); + if (buf[0] != '\0') { + snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), + ", %s ", buf); + } else { + return; + } + + buf[0] = '\0'; + exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE, buf, + sizeof(buf)); + if (buf[0] != '\0') { + snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), + "%s ", buf); + } else { + return; + } + + buf[0] = '\0'; + exif_get_tag_content(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_MAP_DATUM, buf, + sizeof(buf)); + if (buf[0] != '\0') { + snprintf(buffer + strlen(buffer), maxsize - strlen(buffer), + "(%s)\n", buf); + } else { + return; + } + +} + + + +/* return data structure with exif data if available */ +ExifData *exif_get_data(char *path) +{ + ExifData *ed = NULL; + + /* Load an ExifData object from an EXIF file */ + ed = exif_data_new_from_file(path); + if (ed == NULL) { + D(("File not readable or no Exif data present in %s\n", + path)); + } + + return (ed); +} + + + + +/* get all exif data in readable form */ +void exif_get_info(ExifData * ed, char *buffer, unsigned int maxsize) +{ + ExifEntry *entry = NULL; + char buf[EXIF_STD_BUF_LEN]; + unsigned short int i = 0; + + if ((buffer == NULL) || (maxsize == 0)) { + return; + } else if (ed == NULL) { + snprintf(buffer, (size_t) maxsize, "%s\n", + "No Exif data in file."); + return; + } + + exif_get_description(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + exif_get_make_model_lens(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + exif_get_exposure(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + exif_get_mode(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + exif_get_flash(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + exif_get_datetime(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + + /* show vendor specific makernote tags */ + entry = + exif_content_get_entry(ed->ifd[EXIF_IFD_0], + EXIF_TAG_MAKE); + if (entry != NULL) { + + if (exif_entry_get_value(entry, buf, sizeof(buf))) { + exif_trim_spaces(buf); + + if ((strcmp(buf, "NIKON CORPORATION") == 0) + || (strcmp(buf, "Nikon") == 0) + || (strcmp(buf, "NIKON") == 0) + ) { + /* show nikon makernote exif tags. list must be defined in exif_cfg.h */ + i = 0; + while ((i < USHRT_MAX) + && + (Exif_makernote_nikon_tag_list + [i] != + EXIF_NIKON_MAKERNOTE_END)) + { + exn_get_mnote_nikon_tags + (ed, + Exif_makernote_nikon_tag_list + [i], + buffer + + strlen(buffer), + maxsize - + strlen(buffer)); + i++; + } + + } else if ((strcmp(buf, "Canon") == 0)) { + /* show canon makernote exif tags. list must be defined in exif_cfg.h */ + i = 0; + while ((i < USHRT_MAX) + && + (Exif_makernote_canon_tag_list + [i] != + EXIF_CANON_MAKERNOTE_END)) + { + exc_get_mnote_canon_tags + (ed, + Exif_makernote_canon_tag_list + [i], + buffer + + strlen(buffer), + maxsize - + strlen(buffer)); + i++; + } + + } else { + } + } + + } + + /* show gps coordinates */ + exif_get_gps_coords(ed, buffer + strlen(buffer), + maxsize - strlen(buffer)); + +} + +#endif |