summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Friesel <derf@finalrewind.org>2012-01-27 20:23:03 +0100
committerDaniel Friesel <derf@finalrewind.org>2012-01-27 20:23:03 +0100
commit4252f6eb96ef00d5907dceda3af8c581917d7aa1 (patch)
tree7850c29f32d7bbb2be61d865b2900f24c7d54eb7 /src
parentf32e4f8b3876b5cf063b92fa8988a7bda3672795 (diff)
optional exif support (build with exif=1), initial patch import
Diffstat (limited to 'src')
-rw-r--r--src/exif.c197
-rw-r--r--src/exif.h34
-rw-r--r--src/feh.h3
-rw-r--r--src/filelist.c8
-rw-r--r--src/filelist.h7
-rw-r--r--src/help.raw1
-rw-r--r--src/imlib.c115
-rw-r--r--src/keyevents.c13
-rw-r--r--src/options.c14
-rw-r--r--src/options.h6
-rw-r--r--src/winwidget.c4
11 files changed, 401 insertions, 1 deletions
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 <stdio.h>
+#include <string.h>
+#include <libexif/exif-data.h>
+
+#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 <libexif/exif-data.h>
+#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 <libexif/exif-data.h>
+#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 <curl/curl.h>
#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)