@@ -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 | ||||
@@ -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 | |||||
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 | Features | ||||
@@ -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; | |||||
} |
@@ -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 */ |
@@ -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) { | |||||
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 | #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(); | ||||
@@ -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; | |||||
const char *fmt; | |||||
Imlib_Image im = NULL; | |||||
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 || | |||||
(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) | 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 (!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); | 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(); | ||||