diff --git a/Makefile b/Makefile
index 9c7afcd..a8320bb 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/README.md b/README.md
index 6c3a9c0..97d43c1 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/exif.c b/exif.c
deleted file mode 100644
index 424d36d..0000000
--- a/exif.c
+++ /dev/null
@@ -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 .
- */
-
-#define _POSIX_C_SOURCE 200112L
-
-#include
-#include
-#include
-#include
-
-#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;
-}
diff --git a/exif.h b/exif.h
deleted file mode 100644
index 257f094..0000000
--- a/exif.h
+++ /dev/null
@@ -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 .
- */
-
-#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 */
diff --git a/image.c b/image.c
index 7eec544..7312e73 100644
--- a/image.c
+++ b/image.c
@@ -24,17 +24,20 @@
#include
#include
-#if HAVE_GIFLIB
-#include
-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
+#endif
+
+#if HAVE_GIFLIB
+#include
+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();
diff --git a/thumbs.c b/thumbs.c
index 80249d7..0357836 100644
--- a/thumbs.c
+++ b/thumbs.c
@@ -19,6 +19,7 @@
#define _POSIX_C_SOURCE 200112L
#define _THUMBS_CONFIG
+#include
#include
#include
#include
@@ -26,11 +27,15 @@
#include
#include
-#include "exif.h"
#include "thumbs.h"
#include "util.h"
#include "config.h"
+#if HAVE_LIBEXIF
+#include
+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();