Use thumbnails in EXIF tags; requirement for libexif is back

This commit is contained in:
Bert Münnich 2014-06-09 22:59:49 +02:00
parent 0f7b26d33d
commit d26f39914e
6 changed files with 107 additions and 221 deletions

View File

@ -1,15 +1,15 @@
VERSION = git-20140531 VERSION = git-20140609
PREFIX = /usr/local PREFIX = /usr/local
MANPREFIX = $(PREFIX)/share/man MANPREFIX = $(PREFIX)/share/man
CC = gcc CC = gcc
CFLAGS = -std=c99 -Wall -pedantic -O2 CFLAGS = -std=c99 -Wall -pedantic -O2
CPPFLAGS = -I$(PREFIX)/include -D_XOPEN_SOURCE=500 -DHAVE_GIFLIB CPPFLAGS = -I$(PREFIX)/include -D_XOPEN_SOURCE=500 -DHAVE_LIBEXIF -DHAVE_GIFLIB
LDFLAGS = -L$(PREFIX)/lib LDFLAGS = -L$(PREFIX)/lib
LIBS = -lX11 -lImlib2 -lgif LIBS = -lX11 -lImlib2 -lexif -lgif
SRC = commands.c exif.c image.c main.c options.c thumbs.c util.c window.c SRC = commands.c image.c main.c options.c thumbs.c util.c window.c
OBJ = $(SRC:.c=.o) OBJ = $(SRC:.c=.o)
all: sxiv all: sxiv

View File

@ -3,11 +3,11 @@
**Simple X Image Viewer** **Simple X Image Viewer**
sxiv is an alternative to feh and qiv. Its only dependencies besides xlib are sxiv is an alternative to feh and qiv. Its only dependencies besides xlib are
imlib2 and giflib. The primary goal for writing sxiv is to create an image imlib2, libexif and giflib. The primary goal for writing sxiv is to create an
viewer, which only has the most basic features required for fast image viewing image viewer, which only has the most basic features required for fast image
(the ones I want). It has vi key bindings and works nicely with tiling window viewing (the ones I want). It has vi key bindings and works nicely with tiling
managers. Its code base should be kept small and clean to make it easy for you window managers. Its code base should be kept small and clean to make it easy
to dig into it and customize it for your needs. for you to dig into it and customize it for your needs.
Features Features

141
exif.c
View File

@ -1,141 +0,0 @@
/* Copyright 2012 Bert Muennich
*
* This file is part of sxiv.
*
* sxiv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* sxiv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sxiv. If not, see <http://www.gnu.org/licenses/>.
*/
#define _POSIX_C_SOURCE 200112L
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include "exif.h"
#include "util.h"
ssize_t s_read(int fd, const char *fn, void *buf, size_t n)
{
ssize_t ret;
ret = read(fd, buf, n);
if (ret < n) {
warn("unexpected end-of-file: %s", fn);
return -1;
} else {
return ret;
}
}
unsigned short btous(unsigned char *buf, byteorder_t order)
{
if (buf == NULL)
return 0;
if (order == BO_BIG_ENDIAN)
return buf[0] << 8 | buf[1];
else
return buf[1] << 8 | buf[0];
}
unsigned int btoui(unsigned char *buf, byteorder_t order)
{
if (buf == NULL)
return 0;
if (order == BO_BIG_ENDIAN)
return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
else
return buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0];
}
int exif_orientation(const fileinfo_t *file)
{
int fd;
unsigned char data[EXIF_MAX_LEN];
byteorder_t order = BO_BIG_ENDIAN;
unsigned int cnt, len, idx, val;
if (file == NULL || file->path == NULL)
return -1;
fd = open(file->path, O_RDONLY);
if (fd < 0)
return -1;
if (s_read(fd, file->name, data, 2) < 0)
goto abort;
if (btous(data, order) != JPEG_MARKER_SOI)
goto abort;
if (s_read(fd, file->name, data, 4) < 0)
goto abort;
if (btous(data, order) == JPEG_MARKER_APP0) {
len = btous(data + 2, order);
if (lseek(fd, len - 2, SEEK_CUR) == (off_t) -1)
goto abort;
if (s_read(fd, file->name, data, 4) < 0)
goto abort;
}
if (btous(data, order) != JPEG_MARKER_APP1)
goto abort;
len = btous(data + 2, order);
if (len < 8)
goto abort;
if (s_read(fd, file->name, data, 6) < 0)
goto abort;
if (btoui(data, order) != EXIF_HEAD)
goto abort;
len -= 8;
if (len < 12 || len > EXIF_MAX_LEN)
goto abort;
if (s_read(fd, file->name, data, len) < 0)
goto abort;
switch (btous(data, order)) {
case EXIF_BO_BIG_ENDIAN:
order = BO_BIG_ENDIAN;
break;
case EXIF_BO_LITTLE_ENDIAN:
order = BO_LITTLE_ENDIAN;
break;
default:
goto abort;
break;
}
if (btous(data + 2, order) != EXIF_TAG_MARK)
goto abort;
idx = btoui(data + 4, order);
if (idx > len - 2)
goto abort;
val = 0;
cnt = btous(data + idx, order);
for (idx += 2; cnt > 0 && idx < len - 12; cnt--, idx += 12) {
if (btous(data + idx, order) == EXIF_TAG_ORIENTATION) {
val = btous(data + idx + 8, order);
break;
}
}
close(fd);
return val;
abort:
close(fd);
return -1;
}

42
exif.h
View File

@ -1,42 +0,0 @@
/* Copyright 2012 Bert Muennich
*
* This file is part of sxiv.
*
* sxiv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* sxiv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sxiv. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EXIF_H
#define EXIF_H
#include "types.h"
enum {
JPEG_MARKER_SOI = 0xFFD8,
JPEG_MARKER_APP0 = 0xFFE0,
JPEG_MARKER_APP1 = 0xFFE1
};
enum {
EXIF_MAX_LEN = 0x10000,
EXIF_HEAD = 0x45786966,
EXIF_BO_BIG_ENDIAN = 0x4D4D,
EXIF_BO_LITTLE_ENDIAN = 0x4949,
EXIF_TAG_MARK = 0x002A,
EXIF_TAG_ORIENTATION = 0x0112
};
int exif_orientation(const fileinfo_t*);
void exif_auto_orientate(const fileinfo_t*); /* in image.c */
#endif /* EXIF_H */

48
image.c
View File

@ -24,17 +24,20 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#if HAVE_GIFLIB
#include <gif_lib.h>
enum { MIN_GIF_DELAY = 25 };
#endif
#include "exif.h"
#include "image.h" #include "image.h"
#include "options.h" #include "options.h"
#include "util.h" #include "util.h"
#include "config.h" #include "config.h"
#if HAVE_LIBEXIF
#include <libexif/exif-data.h>
#endif
#if HAVE_GIFLIB
#include <gif_lib.h>
enum { MIN_GIF_DELAY = 25 };
#endif
float zoom_min; float zoom_min;
float zoom_max; float zoom_max;
@ -92,9 +95,22 @@ void img_init(img_t *img, win_t *win)
img->ss.delay = options->slideshow > 0 ? options->slideshow : SLIDESHOW_DELAY; img->ss.delay = options->slideshow > 0 ? options->slideshow : SLIDESHOW_DELAY;
} }
#if HAVE_LIBEXIF
void exif_auto_orientate(const fileinfo_t *file) void exif_auto_orientate(const fileinfo_t *file)
{ {
switch (exif_orientation(file)) { ExifData *ed;
ExifEntry *entry;
int byte_order, orientation = 0;
if ((ed = exif_data_new_from_file(file->path)) == NULL)
return;
byte_order = exif_data_get_byte_order(ed);
entry = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_ORIENTATION);
if (entry != NULL)
orientation = exif_get_short(entry->data, byte_order);
exif_data_unref(ed);
switch (orientation) {
case 5: case 5:
imlib_image_orientate(1); imlib_image_orientate(1);
case 2: case 2:
@ -116,6 +132,7 @@ void exif_auto_orientate(const fileinfo_t *file)
break; break;
} }
} }
#endif
#if HAVE_GIFLIB #if HAVE_GIFLIB
bool img_load_gif(img_t *img, const fileinfo_t *file) 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)
imlib_context_set_image(img->im); imlib_context_set_image(img->im);
imlib_image_set_changes_on_disk(); imlib_image_set_changes_on_disk();
if ((fmt = imlib_image_format()) == NULL) { #if HAVE_LIBEXIF
warn("could not open image: %s", file->name); exif_auto_orientate(file);
return false;
}
if (STREQ(fmt, "jpeg"))
exif_auto_orientate(file);
#if HAVE_GIFLIB
if (STREQ(fmt, "gif"))
img_load_gif(img, file);
#endif #endif
if ((fmt = imlib_image_format()) != NULL) {
#if HAVE_GIFLIB
if (STREQ(fmt, "gif"))
img_load_gif(img, file);
#endif
}
img_apply_gamma(img); img_apply_gamma(img);
img->w = imlib_image_get_width(); img->w = imlib_image_get_width();

View File

@ -19,6 +19,7 @@
#define _POSIX_C_SOURCE 200112L #define _POSIX_C_SOURCE 200112L
#define _THUMBS_CONFIG #define _THUMBS_CONFIG
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
@ -26,11 +27,15 @@
#include <unistd.h> #include <unistd.h>
#include <utime.h> #include <utime.h>
#include "exif.h"
#include "thumbs.h" #include "thumbs.h"
#include "util.h" #include "util.h"
#include "config.h" #include "config.h"
#if HAVE_LIBEXIF
#include <libexif/exif-data.h>
void exif_auto_orientate(const fileinfo_t*);
#endif
static const int thumb_dim = THUMB_SIZE + 10; static const int thumb_dim = THUMB_SIZE + 10;
static char *cache_dir = NULL; static char *cache_dir = NULL;
@ -224,8 +229,7 @@ bool tns_load(tns_t *tns, int n, const fileinfo_t *file,
bool use_cache, cache_hit = false; bool use_cache, cache_hit = false;
float z, zw, zh; float z, zw, zh;
thumb_t *t; thumb_t *t;
Imlib_Image im; Imlib_Image im = NULL;
const char *fmt;
if (tns == NULL || tns->thumbs == NULL) if (tns == NULL || tns->thumbs == NULL)
return false; return false;
@ -248,26 +252,75 @@ bool tns_load(tns_t *tns, int n, const fileinfo_t *file,
} }
if (!cache_hit) { if (!cache_hit) {
if (access(file->path, R_OK) < 0 || #if HAVE_LIBEXIF
(im = imlib_load_image(file->path)) == NULL) int pw = 0, ph = 0, x = 0, y = 0;
bool err;
ExifData *ed;
ExifEntry *entry;
ExifContent *ifd;
ExifByteOrder byte_order;
int tmpfd;
char tmppath[] = "/tmp/sxiv-XXXXXX";
Imlib_Image tmpim;
if ((ed = exif_data_new_from_file(file->path)) != NULL &&
ed->data != NULL && ed->size > 0)
{
if ((tmpfd = mkstemp(tmppath)) >= 0) {
err = write(tmpfd, ed->data, ed->size) != ed->size;
close(tmpfd);
if (!err && (tmpim = imlib_load_image(tmppath)) != NULL) {
byte_order = exif_data_get_byte_order(ed);
ifd = ed->ifd[EXIF_IFD_EXIF];
entry = exif_content_get_entry(ifd, EXIF_TAG_PIXEL_X_DIMENSION);
if (entry != NULL)
pw = exif_get_long(entry->data, byte_order);
entry = exif_content_get_entry(ifd, EXIF_TAG_PIXEL_Y_DIMENSION);
if (entry != NULL)
ph = exif_get_long(entry->data, byte_order);
imlib_context_set_image(tmpim);
w = imlib_image_get_width();
h = imlib_image_get_height();
if (pw > w && ph > h) {
zw = (float) pw / (float) w;
zh = (float) ph / (float) h;
if (zw < zh) {
pw /= zh;
x = (w - pw) / 2;
w = pw;
} else if (zw > zh) {
ph /= zw;
y = (h - ph) / 2;
h = ph;
}
}
if ((im = imlib_create_cropped_image(x, y, w, h)) == NULL)
die("could not allocate memory");
imlib_free_image_and_decache();
}
unlink(tmppath);
}
exif_data_unref(ed);
}
#endif
if (im == NULL && (access(file->path, R_OK) < 0 ||
(im = imlib_load_image(file->path)) == NULL))
{ {
if (!silent) if (!silent)
warn("could not open image: %s", file->name); warn("could not open image: %s", file->name);
return false; return false;
} }
} }
imlib_context_set_image(im); imlib_context_set_image(im);
imlib_context_set_anti_alias(1); imlib_context_set_anti_alias(1);
if ((fmt = imlib_image_format()) == NULL) { #if HAVE_LIBEXIF
if (!silent) if (!cache_hit)
warn("could not open image: %s", file->name);
imlib_free_image_and_decache();
return false;
}
if (STREQ(fmt, "jpeg"))
exif_auto_orientate(file); exif_auto_orientate(file);
#endif
w = imlib_image_get_width(); w = imlib_image_get_width();
h = imlib_image_get_height(); h = imlib_image_get_height();