Use thumbnails in EXIF tags; requirement for libexif is back

master
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
MANPREFIX = $(PREFIX)/share/man
CC = gcc
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
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)
all: sxiv

View File

@ -3,11 +3,11 @@
**Simple X Image Viewer**
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
viewer, which only has the most basic features required for fast image viewing
(the ones I want). It has vi key bindings and works nicely with tiling window
managers. Its code base should be kept small and clean to make it easy for you
to dig into it and customize it for your needs.
imlib2, libexif and giflib. The primary goal for writing sxiv is to create an
image viewer, which only has the most basic features required for fast image
viewing (the ones I want). It has vi key bindings and works nicely with tiling
window managers. Its code base should be kept small and clean to make it easy
for you to dig into it and customize it for your needs.
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 <unistd.h>
#if HAVE_GIFLIB
#include <gif_lib.h>
enum { MIN_GIF_DELAY = 25 };
#endif
#include "exif.h"
#include "image.h"
#include "options.h"
#include "util.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_max;
@ -92,9 +95,22 @@ void img_init(img_t *img, win_t *win)
img->ss.delay = options->slideshow > 0 ? options->slideshow : SLIDESHOW_DELAY;
}
#if HAVE_LIBEXIF
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:
imlib_image_orientate(1);
case 2:
@ -116,6 +132,7 @@ void exif_auto_orientate(const fileinfo_t *file)
break;
}
}
#endif
#if HAVE_GIFLIB
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_image_set_changes_on_disk();
if ((fmt = imlib_image_format()) == NULL) {
warn("could not open image: %s", file->name);
return false;
}
if (STREQ(fmt, "jpeg"))
exif_auto_orientate(file);
#if HAVE_GIFLIB
if (STREQ(fmt, "gif"))
img_load_gif(img, file);
#if HAVE_LIBEXIF
exif_auto_orientate(file);
#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->w = imlib_image_get_width();

View File

@ -19,6 +19,7 @@
#define _POSIX_C_SOURCE 200112L
#define _THUMBS_CONFIG
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@ -26,11 +27,15 @@
#include <unistd.h>
#include <utime.h>
#include "exif.h"
#include "thumbs.h"
#include "util.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 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;
float z, zw, zh;
thumb_t *t;
Imlib_Image im;
const char *fmt;
Imlib_Image im = NULL;
if (tns == NULL || tns->thumbs == NULL)
return false;
@ -248,26 +252,75 @@ bool tns_load(tns_t *tns, int n, const fileinfo_t *file,
}
if (!cache_hit) {
if (access(file->path, R_OK) < 0 ||
(im = imlib_load_image(file->path)) == NULL)
#if HAVE_LIBEXIF
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)
warn("could not open image: %s", file->name);
return false;
}
}
imlib_context_set_image(im);
imlib_context_set_anti_alias(1);
if ((fmt = imlib_image_format()) == NULL) {
if (!silent)
warn("could not open image: %s", file->name);
imlib_free_image_and_decache();
return false;
}
if (STREQ(fmt, "jpeg"))
#if HAVE_LIBEXIF
if (!cache_hit)
exif_auto_orientate(file);
#endif
w = imlib_image_get_width();
h = imlib_image_get_height();