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 <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;
-}
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 <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 */
diff --git a/image.c b/image.c
index 7eec544..7312e73 100644
--- a/image.c
+++ b/image.c
@@ -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();
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 <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();