Krolyxon
Commit d26f399

Branches

Refs →

nsxivd26f399

Use thumbnails in EXIF tags; requirement for libexif is back

Author
Bert Münnich
Date
2014-06-09 22:59 +0200
Parent
0f7b26d
Commit
d26f39914e813aff492020b3d8463965ca8ca574

+107 −221

6 files changed

  1. M Makefile +4 −4
  2. M README.md +5 −5
  3. D exif.c +0 −141
  4. D exif.h +0 −42
  5. M image.c +32 −16
  6. M thumbs.c +66 −13
M Makefile View
@@ -1,15 +1,15 @@
1−VERSION = git-20140531
1+VERSION = git-20140609
22
33 PREFIX = /usr/local
44 MANPREFIX = $(PREFIX)/share/man
55
66 CC = gcc
77 CFLAGS = -std=c99 -Wall -pedantic -O2
8−CPPFLAGS = -I$(PREFIX)/include -D_XOPEN_SOURCE=500 -DHAVE_GIFLIB
8+CPPFLAGS = -I$(PREFIX)/include -D_XOPEN_SOURCE=500 -DHAVE_LIBEXIF -DHAVE_GIFLIB
99 LDFLAGS = -L$(PREFIX)/lib
10−LIBS = -lX11 -lImlib2 -lgif
10+LIBS = -lX11 -lImlib2 -lexif -lgif
1111
12−SRC = commands.c exif.c image.c main.c options.c thumbs.c util.c window.c
12+SRC = commands.c image.c main.c options.c thumbs.c util.c window.c
1313 OBJ = $(SRC:.c=.o)
1414
1515 all: sxiv
M README.md View
@@ -3,11 +3,11 @@
33 **Simple X Image Viewer**
44
55 sxiv is an alternative to feh and qiv. Its only dependencies besides xlib are
6−imlib2 and giflib. The primary goal for writing sxiv is to create an image
7−viewer, which only has the most basic features required for fast image viewing
8−(the ones I want). It has vi key bindings and works nicely with tiling window
9−managers. Its code base should be kept small and clean to make it easy for you
10−to dig into it and customize it for your needs.
6+imlib2, libexif and giflib. The primary goal for writing sxiv is to create an
7+image viewer, which only has the most basic features required for fast image
8+viewing (the ones I want). It has vi key bindings and works nicely with tiling
9+window managers. Its code base should be kept small and clean to make it easy
10+for you to dig into it and customize it for your needs.
1111
1212
1313 Features
D exif.c View
@@ -1,141 +0,0 @@
1−/* Copyright 2012 Bert Muennich
2− *
3− * This file is part of sxiv.
4− *
5− * sxiv is free software; you can redistribute it and/or modify
6− * it under the terms of the GNU General Public License as published
7− * by the Free Software Foundation; either version 2 of the License,
8− * or (at your option) any later version.
9− *
10− * sxiv is distributed in the hope that it will be useful,
11− * but WITHOUT ANY WARRANTY; without even the implied warranty of
12− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13− * GNU General Public License for more details.
14− *
15− * You should have received a copy of the GNU General Public License
16− * along with sxiv. If not, see <http://www.gnu.org/licenses/>.
17− */
18−
19−#define _POSIX_C_SOURCE 200112L
20−
21−#include <stdlib.h>
22−#include <fcntl.h>
23−#include <sys/stat.h>
24−#include <unistd.h>
25−
26−#include "exif.h"
27−#include "util.h"
28−
29−ssize_t s_read(int fd, const char *fn, void *buf, size_t n)
30−{
31− ssize_t ret;
32−
33− ret = read(fd, buf, n);
34− if (ret < n) {
35− warn("unexpected end-of-file: %s", fn);
36− return -1;
37− } else {
38− return ret;
39− }
40−}
41−
42−unsigned short btous(unsigned char *buf, byteorder_t order)
43−{
44− if (buf == NULL)
45− return 0;
46− if (order == BO_BIG_ENDIAN)
47− return buf[0] << 8 | buf[1];
48− else
49− return buf[1] << 8 | buf[0];
50−}
51−
52−unsigned int btoui(unsigned char *buf, byteorder_t order)
53−{
54− if (buf == NULL)
55− return 0;
56− if (order == BO_BIG_ENDIAN)
57− return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
58− else
59− return buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0];
60−}
61−
62−int exif_orientation(const fileinfo_t *file)
63−{
64− int fd;
65− unsigned char data[EXIF_MAX_LEN];
66− byteorder_t order = BO_BIG_ENDIAN;
67− unsigned int cnt, len, idx, val;
68−
69− if (file == NULL || file->path == NULL)
70− return -1;
71−
72− fd = open(file->path, O_RDONLY);
73− if (fd < 0)
74− return -1;
75−
76− if (s_read(fd, file->name, data, 2) < 0)
77− goto abort;
78− if (btous(data, order) != JPEG_MARKER_SOI)
79− goto abort;
80− if (s_read(fd, file->name, data, 4) < 0)
81− goto abort;
82−
83− if (btous(data, order) == JPEG_MARKER_APP0) {
84− len = btous(data + 2, order);
85− if (lseek(fd, len - 2, SEEK_CUR) == (off_t) -1)
86− goto abort;
87− if (s_read(fd, file->name, data, 4) < 0)
88− goto abort;
89− }
90− if (btous(data, order) != JPEG_MARKER_APP1)
91− goto abort;
92− len = btous(data + 2, order);
93− if (len < 8)
94− goto abort;
95−
96− if (s_read(fd, file->name, data, 6) < 0)
97− goto abort;
98− if (btoui(data, order) != EXIF_HEAD)
99− goto abort;
100−
101− len -= 8;
102− if (len < 12 || len > EXIF_MAX_LEN)
103− goto abort;
104− if (s_read(fd, file->name, data, len) < 0)
105− goto abort;
106−
107− switch (btous(data, order)) {
108− case EXIF_BO_BIG_ENDIAN:
109− order = BO_BIG_ENDIAN;
110− break;
111− case EXIF_BO_LITTLE_ENDIAN:
112− order = BO_LITTLE_ENDIAN;
113− break;
114− default:
115− goto abort;
116− break;
117− }
118−
119− if (btous(data + 2, order) != EXIF_TAG_MARK)
120− goto abort;
121− idx = btoui(data + 4, order);
122− if (idx > len - 2)
123− goto abort;
124−
125− val = 0;
126− cnt = btous(data + idx, order);
127−
128− for (idx += 2; cnt > 0 && idx < len - 12; cnt--, idx += 12) {
129− if (btous(data + idx, order) == EXIF_TAG_ORIENTATION) {
130− val = btous(data + idx + 8, order);
131− break;
132− }
133− }
134−
135− close(fd);
136− return val;
137−
138−abort:
139− close(fd);
140− return -1;
141−}
D exif.h View
@@ -1,42 +0,0 @@
1−/* Copyright 2012 Bert Muennich
2− *
3− * This file is part of sxiv.
4− *
5− * sxiv is free software; you can redistribute it and/or modify
6− * it under the terms of the GNU General Public License as published
7− * by the Free Software Foundation; either version 2 of the License,
8− * or (at your option) any later version.
9− *
10− * sxiv is distributed in the hope that it will be useful,
11− * but WITHOUT ANY WARRANTY; without even the implied warranty of
12− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13− * GNU General Public License for more details.
14− *
15− * You should have received a copy of the GNU General Public License
16− * along with sxiv. If not, see <http://www.gnu.org/licenses/>.
17− */
18−
19−#ifndef EXIF_H
20−#define EXIF_H
21−
22−#include "types.h"
23−
24−enum {
25− JPEG_MARKER_SOI = 0xFFD8,
26− JPEG_MARKER_APP0 = 0xFFE0,
27− JPEG_MARKER_APP1 = 0xFFE1
28−};
29−
30−enum {
31− EXIF_MAX_LEN = 0x10000,
32− EXIF_HEAD = 0x45786966,
33− EXIF_BO_BIG_ENDIAN = 0x4D4D,
34− EXIF_BO_LITTLE_ENDIAN = 0x4949,
35− EXIF_TAG_MARK = 0x002A,
36− EXIF_TAG_ORIENTATION = 0x0112
37−};
38−
39−int exif_orientation(const fileinfo_t*);
40−void exif_auto_orientate(const fileinfo_t*); /* in image.c */
41−
42−#endif /* EXIF_H */
M image.c View
@@ -24,17 +24,20 @@
2424 #include <sys/types.h>
2525 #include <unistd.h>
2626
27−#if HAVE_GIFLIB
28−#include <gif_lib.h>
29−enum { MIN_GIF_DELAY = 25 };
30−#endif
31−
32−#include "exif.h"
3327 #include "image.h"
3428 #include "options.h"
3529 #include "util.h"
3630 #include "config.h"
3731
32+#if HAVE_LIBEXIF
33+#include <libexif/exif-data.h>
34+#endif
35+
36+#if HAVE_GIFLIB
37+#include <gif_lib.h>
38+enum { MIN_GIF_DELAY = 25 };
39+#endif
40+
3841 float zoom_min;
3942 float zoom_max;
4043
@@ -92,9 +95,22 @@ void img_init(img_t *img, win_t *win)
9295 img->ss.delay = options->slideshow > 0 ? options->slideshow : SLIDESHOW_DELAY;
9396 }
9497
98+#if HAVE_LIBEXIF
9599 void exif_auto_orientate(const fileinfo_t *file)
96100 {
97− switch (exif_orientation(file)) {
101+ ExifData *ed;
102+ ExifEntry *entry;
103+ int byte_order, orientation = 0;
104+
105+ if ((ed = exif_data_new_from_file(file->path)) == NULL)
106+ return;
107+ byte_order = exif_data_get_byte_order(ed);
108+ entry = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_ORIENTATION);
109+ if (entry != NULL)
110+ orientation = exif_get_short(entry->data, byte_order);
111+ exif_data_unref(ed);
112+
113+ switch (orientation) {
98114 case 5:
99115 imlib_image_orientate(1);
100116 case 2:
@@ -116,6 +132,7 @@ void exif_auto_orientate(const fileinfo_t *file)
116132 break;
117133 }
118134 }
135+#endif
119136
120137 #if HAVE_GIFLIB
121138 bool img_load_gif(img_t *img, const fileinfo_t *file)
@@ -322,17 +339,16 @@ bool img_load(img_t *img, const fileinfo_t *file)
322339 imlib_context_set_image(img->im);
323340 imlib_image_set_changes_on_disk();
324341
325− if ((fmt = imlib_image_format()) == NULL) {
326− warn("could not open image: %s", file->name);
327− return false;
328− }
329− if (STREQ(fmt, "jpeg"))
330− exif_auto_orientate(file);
331−#if HAVE_GIFLIB
332− if (STREQ(fmt, "gif"))
333− img_load_gif(img, file);
342+#if HAVE_LIBEXIF
343+ exif_auto_orientate(file);
334344 #endif
335345
346+ if ((fmt = imlib_image_format()) != NULL) {
347+#if HAVE_GIFLIB
348+ if (STREQ(fmt, "gif"))
349+ img_load_gif(img, file);
350+#endif
351+ }
336352 img_apply_gamma(img);
337353
338354 img->w = imlib_image_get_width();
M thumbs.c View
@@ -19,6 +19,7 @@
1919 #define _POSIX_C_SOURCE 200112L
2020 #define _THUMBS_CONFIG
2121
22+#include <stdio.h>
2223 #include <stdlib.h>
2324 #include <string.h>
2425 #include <sys/types.h>
@@ -26,11 +27,15 @@
2627 #include <unistd.h>
2728 #include <utime.h>
2829
29−#include "exif.h"
3030 #include "thumbs.h"
3131 #include "util.h"
3232 #include "config.h"
3333
34+#if HAVE_LIBEXIF
35+#include <libexif/exif-data.h>
36+void exif_auto_orientate(const fileinfo_t*);
37+#endif
38+
3439 static const int thumb_dim = THUMB_SIZE + 10;
3540
3641 static char *cache_dir = NULL;
@@ -224,8 +229,7 @@ bool tns_load(tns_t *tns, int n, const fileinfo_t *file,
224229 bool use_cache, cache_hit = false;
225230 float z, zw, zh;
226231 thumb_t *t;
227− Imlib_Image im;
228− const char *fmt;
232+ Imlib_Image im = NULL;
229233
230234 if (tns == NULL || tns->thumbs == NULL)
231235 return false;
@@ -248,26 +252,75 @@ bool tns_load(tns_t *tns, int n, const fileinfo_t *file,
248252 }
249253
250254 if (!cache_hit) {
251− if (access(file->path, R_OK) < 0 ||
252− (im = imlib_load_image(file->path)) == NULL)
255+#if HAVE_LIBEXIF
256+ int pw = 0, ph = 0, x = 0, y = 0;
257+ bool err;
258+ ExifData *ed;
259+ ExifEntry *entry;
260+ ExifContent *ifd;
261+ ExifByteOrder byte_order;
262+ int tmpfd;
263+ char tmppath[] = "/tmp/sxiv-XXXXXX";
264+ Imlib_Image tmpim;
265+
266+ if ((ed = exif_data_new_from_file(file->path)) != NULL &&
267+ ed->data != NULL && ed->size > 0)
268+ {
269+ if ((tmpfd = mkstemp(tmppath)) >= 0) {
270+ err = write(tmpfd, ed->data, ed->size) != ed->size;
271+ close(tmpfd);
272+
273+ if (!err && (tmpim = imlib_load_image(tmppath)) != NULL) {
274+ byte_order = exif_data_get_byte_order(ed);
275+ ifd = ed->ifd[EXIF_IFD_EXIF];
276+ entry = exif_content_get_entry(ifd, EXIF_TAG_PIXEL_X_DIMENSION);
277+ if (entry != NULL)
278+ pw = exif_get_long(entry->data, byte_order);
279+ entry = exif_content_get_entry(ifd, EXIF_TAG_PIXEL_Y_DIMENSION);
280+ if (entry != NULL)
281+ ph = exif_get_long(entry->data, byte_order);
282+
283+ imlib_context_set_image(tmpim);
284+ w = imlib_image_get_width();
285+ h = imlib_image_get_height();
286+
287+ if (pw > w && ph > h) {
288+ zw = (float) pw / (float) w;
289+ zh = (float) ph / (float) h;
290+ if (zw < zh) {
291+ pw /= zh;
292+ x = (w - pw) / 2;
293+ w = pw;
294+ } else if (zw > zh) {
295+ ph /= zw;
296+ y = (h - ph) / 2;
297+ h = ph;
298+ }
299+ }
300+ if ((im = imlib_create_cropped_image(x, y, w, h)) == NULL)
301+ die("could not allocate memory");
302+ imlib_free_image_and_decache();
303+ }
304+ unlink(tmppath);
305+ }
306+ exif_data_unref(ed);
307+ }
308+#endif
309+ if (im == NULL && (access(file->path, R_OK) < 0 ||
310+ (im = imlib_load_image(file->path)) == NULL))
253311 {
254312 if (!silent)
255313 warn("could not open image: %s", file->name);
256314 return false;
257315 }
258316 }
259−
260317 imlib_context_set_image(im);
261318 imlib_context_set_anti_alias(1);
262319
263− if ((fmt = imlib_image_format()) == NULL) {
264− if (!silent)
265− warn("could not open image: %s", file->name);
266− imlib_free_image_and_decache();
267− return false;
268− }
269− if (STREQ(fmt, "jpeg"))
320+#if HAVE_LIBEXIF
321+ if (!cache_hit)
270322 exif_auto_orientate(file);
323+#endif
271324
272325 w = imlib_image_get_width();
273326 h = imlib_image_get_height();