Use thumbnails in EXIF tags; requirement for libexif is back
This commit is contained in:
parent
0f7b26d33d
commit
d26f39914e
8
Makefile
8
Makefile
|
@ -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
|
||||||
|
|
10
README.md
10
README.md
|
@ -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
141
exif.c
|
@ -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
42
exif.h
|
@ -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 */
|
|
42
image.c
42
image.c
|
@ -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);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (STREQ(fmt, "jpeg"))
|
|
||||||
exif_auto_orientate(file);
|
exif_auto_orientate(file);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((fmt = imlib_image_format()) != NULL) {
|
||||||
#if HAVE_GIFLIB
|
#if HAVE_GIFLIB
|
||||||
if (STREQ(fmt, "gif"))
|
if (STREQ(fmt, "gif"))
|
||||||
img_load_gif(img, file);
|
img_load_gif(img, file);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
img_apply_gamma(img);
|
img_apply_gamma(img);
|
||||||
|
|
||||||
img->w = imlib_image_get_width();
|
img->w = imlib_image_get_width();
|
||||||
|
|
79
thumbs.c
79
thumbs.c
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue