From 4252f6eb96ef00d5907dceda3af8c581917d7aa1 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Fri, 27 Jan 2012 20:23:03 +0100 Subject: optional exif support (build with exif=1), initial patch import --- src/exif.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/exif.h | 34 ++++++++++ src/feh.h | 3 + src/filelist.c | 8 +++ src/filelist.h | 7 ++ src/help.raw | 1 + src/imlib.c | 115 +++++++++++++++++++++++++++++++++ src/keyevents.c | 13 ++++ src/options.c | 14 +++- src/options.h | 6 ++ src/winwidget.c | 4 ++ 11 files changed, 401 insertions(+), 1 deletion(-) create mode 100644 src/exif.c create mode 100644 src/exif.h (limited to 'src') diff --git a/src/exif.c b/src/exif.c new file mode 100644 index 0000000..02154e4 --- /dev/null +++ b/src/exif.c @@ -0,0 +1,197 @@ +/* exif.c + +Copyright (C) 2012 Dennis Real. + +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 +#include +#include + +#include "feh.h" +#include "options.h" +#include "debug.h" +#include "exif.h" + + + +/* remove all spaces on the right end of a string */ +static void exif_trim_spaces(char *str) +{ + char *end; + + for (end = str; *str!='\0'; str++) + { + if (*str != ' ') + { + end = str; + } + } + *++end = '\0'; +} + + +/* show given exif tag content */ +static void exif_get_tag(ExifData *d, ExifIfd ifd, ExifTag tag, char* buffer, unsigned int maxsize) +{ + char s[MAX_EXIF_DATA]; + + if ( (d != NULL) && (buffer != NULL) && (maxsize>0) ) + { + ExifEntry *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, maxsize); + + /* 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 the given MakerNote tag if it exists */ +static 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) + { + 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') + { + snprintf(buffer, (size_t)maxsize, "%s: %s\n", exif_mnote_data_get_title(mn, i), buf); + } + } + } + } + } +} + + + +/* 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 exif data in readable form */ +void exif_get_info(ExifData * ed, char *buffer, unsigned int maxsize) +{ + ExifEntry *entry = NULL; + char buf[64]; + + if ( (buffer == NULL) || (maxsize == 0) ) + { + return; + } + else if (ed == NULL ) + { + snprintf(buffer, (size_t)maxsize, "%s\n", "No Exif data in file."); + return; + } + else if ( ed != NULL ) + { + /* normal exif tags */ + exif_get_tag(ed, EXIF_IFD_0, EXIF_TAG_MAKE, buffer, maxsize); + exif_get_tag(ed, EXIF_IFD_0, EXIF_TAG_MODEL, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_SHUTTER_SPEED_VALUE, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_APERTURE_VALUE, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_BIAS_VALUE, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_MODE, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_PROGRAM, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_SCENE_CAPTURE_TYPE, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_FLASH, buffer + strlen(buffer), maxsize - strlen(buffer)); + exif_get_tag(ed, EXIF_IFD_EXIF, EXIF_TAG_FLASH_ENERGY, buffer + strlen(buffer), maxsize - strlen(buffer)); + + /* 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); + + /* Nikon */ + if ( strcmp(buf, "Nikon") != 0 ) + { + /* Digital Vari-Program */ + exif_get_mnote_tag(ed, 171, buffer + strlen(buffer), maxsize - strlen(buffer)); + } + + } + } + } +} + +#endif diff --git a/src/exif.h b/src/exif.h new file mode 100644 index 0000000..4d72a57 --- /dev/null +++ b/src/exif.h @@ -0,0 +1,34 @@ +/* exif.h + +Copyright (C) 2012 Dennis Real. + +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. + +*/ + +#ifndef EXIF_H +#define EXIF_H + +#define MAX_EXIF_DATA 1024 + +extern ExifData * exif_get_data(char *path); +extern void exif_get_info(ExifData * ed, char *buffer, unsigned int maxsize); + +#endif diff --git a/src/feh.h b/src/feh.h index 550b6f5..6719963 100644 --- a/src/feh.h +++ b/src/feh.h @@ -146,6 +146,9 @@ void cb_reload_timer(void *data); char *feh_http_load_image(char *url); int feh_load_image_char(Imlib_Image * im, char *filename); void feh_draw_filename(winwidget w); +#ifdef HAVE_LIBEXIF +void feh_draw_exif(winwidget w); +#endif void feh_draw_actions(winwidget w); void feh_draw_caption(winwidget w); void feh_draw_info(winwidget w); diff --git a/src/filelist.c b/src/filelist.c index 522f3cc..32bc2a5 100644 --- a/src/filelist.c +++ b/src/filelist.c @@ -24,6 +24,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#ifdef HAVE_LIBEXIF +#include +#endif + #include "feh.h" #include "filelist.h" #include "options.h" @@ -65,6 +69,10 @@ void feh_file_free(feh_file * file) free(file->caption); if (file->info) feh_file_info_free(file->info); +#ifdef HAVE_LIBEXIF + if (file->info) + exif_data_unref(file->ed); +#endif free(file); return; } diff --git a/src/filelist.h b/src/filelist.h index 9ec302c..00e36e8 100644 --- a/src/filelist.h +++ b/src/filelist.h @@ -26,6 +26,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifndef FILELIST_H #define FILELIST_H +#ifdef HAVE_LIBEXIF +#include +#endif + struct __feh_file { char *filename; char *caption; @@ -33,6 +37,9 @@ struct __feh_file { /* info stuff */ feh_file_info *info; /* only set when needed */ +#ifdef HAVE_LIBEXIF + ExifData *ed; +#endif }; struct __feh_file_info { diff --git a/src/help.raw b/src/help.raw index f626580..818cea0 100644 --- a/src/help.raw +++ b/src/help.raw @@ -32,6 +32,7 @@ OPTIONS -x, --borderless Create borderless windows -d, --draw-filename Show the filename in the image window --draw-tinted Show overlay texts on semi-transparent background + -Q, --draw-exif Show some Exif information -^, --title TITLE Set window title (see FORMAT SPECIFIERS) -D, --slideshow-delay NUM Set delay between automatically changing slides --cycle-once Exit after one loop through the slideshow diff --git a/src/imlib.c b/src/imlib.c index 6d718f5..0b60180 100644 --- a/src/imlib.c +++ b/src/imlib.c @@ -39,6 +39,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #endif +#ifdef HAVE_LIBEXIF +#include "exif.h" +#endif + Display *disp = NULL; Visual *vis = NULL; Screen *scr = NULL; @@ -146,6 +150,9 @@ int feh_load_image(Imlib_Image * im, feh_file * file) file->filename = tmpname; feh_file_info_load(file, *im); file->filename = tempcpy; +#ifdef HAVE_LIBEXIF + file->ed = exif_get_data(tmpname); +#endif } if ((opt.slideshow) && (opt.reload == 0)) { /* Http, no reload, slideshow. Let's keep this image on hand... */ @@ -220,6 +227,10 @@ int feh_load_image(Imlib_Image * im, feh_file * file) return(0); } +#ifdef HAVE_LIBEXIF + file->ed = exif_get_data(file->filename); +#endif + D(("Loaded ok\n")); return(1); } @@ -492,6 +503,110 @@ void feh_draw_filename(winwidget w) return; } +#ifdef HAVE_LIBEXIF +void feh_draw_exif(winwidget w) +{ + static Imlib_Font fn = NULL; + int width = 0, height = 0, line_width = 0, line_height = 0; + Imlib_Image im = NULL; + int no_lines = 0, i; + int pos = 0; + int pos2 = 0; + char info_line[256]; + char *info_buf[128]; + char buffer[MAX_EXIF_DATA]; + + if ( (!w->file) || (!FEH_FILE(w->file->data)) + || (!FEH_FILE(w->file->data)->filename) ) + { + return; + } + + exif_get_info(FEH_FILE(w->file->data)->ed, buffer, MAX_EXIF_DATA); + + fn = feh_load_font(w); + + if (buffer == NULL) + { + snprintf(buffer, MAX_EXIF_DATA, "%s", estrdup("Failed to run exif command")); + gib_imlib_get_text_size(fn, &buffer[0], NULL, &width, &height, IMLIB_TEXT_TO_RIGHT); + no_lines = 1; + } + else + { + + while ( (no_lines < 128) && (pos < MAX_EXIF_DATA) ) + { + /* max 128 lines */ + pos2 = 0; + while ( pos2 < 256 ) /* max 256 chars per line */ + { + if ( (buffer[pos] != '\n') + && (buffer[pos] != '\0') ) + { + info_line[pos2] = buffer[pos]; + } + else if ( buffer[pos] == '\0' ) + { + pos = MAX_EXIF_DATA; /* all data seen */ + info_line[pos2] = '\0'; + } + else + { + info_line[pos2] = '\0'; /* line finished, continue with next line*/ + + pos++; + break; + } + + pos++; + pos2++; + } + + gib_imlib_get_text_size(fn, info_line, NULL, &line_width, + &line_height, IMLIB_TEXT_TO_RIGHT); + + if (line_height > height) + height = line_height; + if (line_width > width) + width = line_width; + info_buf[no_lines] = estrdup(info_line); + + no_lines++; + } + } + + if (no_lines == 0) + return; + + height *= no_lines; + width += 4; + + im = imlib_create_image(width, height); + if (!im) + { + eprintf("Couldn't create image. Out of memory?"); + } + + feh_imlib_image_fill_text_bg(im, width, height); + + for (i = 0; i < no_lines; i++) + { + gib_imlib_text_draw(im, fn, NULL, 2, (i * line_height) + 2, + info_buf[i], IMLIB_TEXT_TO_RIGHT, 0, 0, 0, 255); + gib_imlib_text_draw(im, fn, NULL, 1, (i * line_height) + 1, + info_buf[i], IMLIB_TEXT_TO_RIGHT, 255, 255, 255, 255); + + } + + gib_imlib_render_image_on_drawable(w->bg_pmap, im, 0, w->h - height, 1, 1, 0); + + gib_imlib_free_image_and_decache(im); + return; + +} +#endif + void feh_draw_info(winwidget w) { static Imlib_Font fn = NULL; diff --git a/src/keyevents.c b/src/keyevents.c index 873e114..0ada751 100644 --- a/src/keyevents.c +++ b/src/keyevents.c @@ -136,6 +136,9 @@ void init_keyevents(void) { feh_set_kb(&keys.toggle_actions, 0, XK_a, 0, 0, 0, 0); feh_set_kb(&keys.toggle_aliasing, 0, XK_A, 0, 0, 0, 0); feh_set_kb(&keys.toggle_filenames, 0, XK_d, 0, 0, 0, 0); +#ifdef HAVE_LIBEXIF + feh_set_kb(&keys.toggle_exif, 0, XK_e, 0, 0, 0, 0); +#endif feh_set_kb(&keys.toggle_info, 0, XK_i, 0, 0, 0, 0); feh_set_kb(&keys.toggle_pointer, 0, XK_o, 0, 0, 0, 0); feh_set_kb(&keys.toggle_caption, 0, XK_c, 0, 0, 0, 0); @@ -270,6 +273,10 @@ void init_keyevents(void) { cur_kb = &keys.toggle_aliasing; else if (!strcmp(action, "toggle_filenames")) cur_kb = &keys.toggle_filenames; +#ifdef HAVE_LIBEXIF + else if (!strcmp(action, "toggle_exif")) + cur_kb = &keys.toggle_exif; +#endif else if (!strcmp(action, "toggle_info")) cur_kb = &keys.toggle_info; else if (!strcmp(action, "toggle_pointer")) @@ -628,6 +635,12 @@ void feh_event_handle_keypress(XEvent * ev) opt.draw_filename = !opt.draw_filename; winwidget_rerender_all(0); } +#ifdef HAVE_LIBEXIF + else if (feh_is_kp(&keys.toggle_exif, keysym, state)) { + opt.draw_exif = !opt.draw_exif; + winwidget_rerender_all(0); + } +#endif else if (feh_is_kp(&keys.toggle_info, keysym, state)) { opt.draw_info = !opt.draw_info; winwidget_rerender_all(0); diff --git a/src/options.c b/src/options.c index 89f5e71..4c0ad5d 100644 --- a/src/options.c +++ b/src/options.c @@ -301,7 +301,11 @@ static void feh_getopt_theme(int argc, char **argv) static void feh_parse_option_array(int argc, char **argv, int finalrun) { static char stropts[] = - "a:A:b:B:cC:dD:e:E:f:Fg:GhH:iIj:J:kK:lL:mM:nNo:O:pPqrR:sS:tT:uUvVwW:xXy:YzZ" +#ifdef HAVE_LIBEXIF + "a:A:b:B:cC:dD:e:E:f:Fg:GhH:iIj:J:kK:lL:mM:nNo:O:pPQqrR:sS:tT:uUvVwW:xXy:YzZ" +#else + "a:A:b:B:cC:dD:e:E:f:Fg:GhH:iIj:J:kK:lL:mM:nNo:O:pPqrR:sS:tT:uUvVwW:xXy:YzZ" +#endif ".@:^:~:):|:+:"; /* (*name, has_arg, *flag, val) See: struct option in getopts.h */ @@ -329,6 +333,9 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) {"auto-zoom" , 0, 0, 'Z'}, {"ignore-aspect" , 0, 0, 'X'}, {"draw-filename" , 0, 0, 'd'}, +#ifdef HAVE_LIBEXIF + {"draw-exif" , 0, 0, 'Q'}, +#endif {"preload" , 0, 0, 'p'}, {"reverse" , 0, 0, 'n'}, {"thumbnails" , 0, 0, 't'}, @@ -476,6 +483,11 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) case 'd': opt.draw_filename = 1; break; +#ifdef HAVE_LIBEXIF + case 'Q': + opt.draw_exif = 1; + break; +#endif case 'F': opt.full_screen = 1; break; diff --git a/src/options.h b/src/options.h index 899bcf1..bee7c73 100644 --- a/src/options.h +++ b/src/options.h @@ -49,6 +49,9 @@ struct __fehoptions { unsigned char jump_on_resort; unsigned char full_screen; unsigned char draw_filename; +#ifdef HAVE_LIBEXIF + unsigned char draw_exif; +#endif unsigned char list; unsigned char quiet; unsigned char preload; @@ -163,6 +166,9 @@ struct __fehkb { struct __fehkey render; struct __fehkey toggle_actions; struct __fehkey toggle_filenames; +#ifdef HAVE_LIBEXIF + struct __fehkey toggle_exif; +#endif struct __fehkey toggle_info; struct __fehkey toggle_pointer; struct __fehkey toggle_aliasing; diff --git a/src/winwidget.c b/src/winwidget.c index ed7002a..e263702 100644 --- a/src/winwidget.c +++ b/src/winwidget.c @@ -574,6 +574,10 @@ void winwidget_render_image(winwidget winwid, int resize, int force_alias) winwidget_update_caption(winwid); if (opt.draw_filename) feh_draw_filename(winwid); +#ifdef HAVE_LIBEXIF + if (opt.draw_exif) + feh_draw_exif(winwid); +#endif if (opt.draw_actions) feh_draw_actions(winwid); if (opt.draw_info && opt.info_cmd) -- cgit v1.2.3