@@ -8,7 +8,7 @@ LIBS = -lX11 -lImlib2 -lgif | |||||
PREFIX = /usr/local | PREFIX = /usr/local | ||||
MANPREFIX = $(PREFIX)/share/man | MANPREFIX = $(PREFIX)/share/man | ||||
SRC = commands.c image.c main.c options.c thumbs.c util.c window.c | SRC = commands.c exif.c image.c main.c options.c thumbs.c util.c window.c | ||||
OBJ = $(SRC:.c=.o) | OBJ = $(SRC:.c=.o) | ||||
all: options sxiv | all: options sxiv | ||||
@@ -0,0 +1,131 @@ | |||||
/* sxiv: exif.c | |||||
* Copyright (c) 2011 Bert Muennich <be.muennich at googlemail.com> | |||||
* | |||||
* This program 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. | |||||
* | |||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc., | |||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
#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, 4) < 0) | |||||
goto abort; | |||||
if (btous(data, order) != JPEG_MARKER_SOI) | |||||
goto abort; | |||||
if (btous(data + 2, order) != JPEG_MARKER_APP1) | |||||
goto abort; | |||||
if (s_read(fd, file->name, data, 2) < 0) | |||||
goto abort; | |||||
len = btous(data, 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); | |||||
printf("exif orientation: %s: %u\n", file->name, val); | |||||
break; | |||||
} | |||||
} | |||||
close(fd); | |||||
return val; | |||||
abort: | |||||
close(fd); | |||||
return -1; | |||||
} |
@@ -0,0 +1,41 @@ | |||||
/* sxiv: exif.h | |||||
* Copyright (c) 2011 Bert Muennich <be.muennich at googlemail.com> | |||||
* | |||||
* This program 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. | |||||
* | |||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc., | |||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
#ifndef EXIF_H | |||||
#define EXIF_H | |||||
#include "types.h" | |||||
enum { | |||||
JPEG_MARKER_SOI = 0xFFD8, | |||||
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 */ |
@@ -25,6 +25,7 @@ | |||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <gif_lib.h> | #include <gif_lib.h> | ||||
#include "exif.h" | |||||
#include "image.h" | #include "image.h" | ||||
#include "options.h" | #include "options.h" | ||||
#include "util.h" | #include "util.h" | ||||
@@ -64,6 +65,34 @@ void img_init(img_t *img, win_t *win) { | |||||
img->multi.animate = false; | img->multi.animate = false; | ||||
} | } | ||||
void exif_auto_orientate(const fileinfo_t *file) { | |||||
switch (exif_orientation(file)) { | |||||
case 5: | |||||
imlib_image_orientate(1); | |||||
case 2: | |||||
imlib_image_flip_vertical(); | |||||
break; | |||||
case 3: | |||||
imlib_image_orientate(2); | |||||
break; | |||||
case 7: | |||||
imlib_image_orientate(1); | |||||
case 4: | |||||
imlib_image_flip_horizontal(); | |||||
break; | |||||
case 6: | |||||
imlib_image_orientate(1); | |||||
break; | |||||
case 8: | |||||
imlib_image_orientate(3); | |||||
break; | |||||
} | |||||
} | |||||
bool img_load_gif(img_t *img, const fileinfo_t *file) { | bool img_load_gif(img_t *img, const fileinfo_t *file) { | ||||
GifFileType *gif; | GifFileType *gif; | ||||
GifRowType *rows = NULL; | GifRowType *rows = NULL; | ||||
@@ -254,6 +283,8 @@ bool img_load(img_t *img, const fileinfo_t *file) { | |||||
warn("could not open image: %s", file->name); | warn("could not open image: %s", file->name); | ||||
return false; | return false; | ||||
} | } | ||||
if (STREQ(fmt, "jpeg")) | |||||
exif_auto_orientate(file); | |||||
if (STREQ(fmt, "gif")) | if (STREQ(fmt, "gif")) | ||||
img_load_gif(img, file); | img_load_gif(img, file); | ||||
@@ -26,6 +26,7 @@ | |||||
#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" | ||||
@@ -254,6 +255,8 @@ bool tns_load(tns_t *tns, int n, const fileinfo_t *file, | |||||
imlib_free_image_and_decache(); | imlib_free_image_and_decache(); | ||||
return false; | return false; | ||||
} | } | ||||
if (STREQ(fmt, "jpeg")) | |||||
exif_auto_orientate(file); | |||||
w = imlib_image_get_width(); | w = imlib_image_get_width(); | ||||
h = imlib_image_get_height(); | h = imlib_image_get_height(); | ||||
@@ -6,6 +6,11 @@ typedef enum { | |||||
true | true | ||||
} bool; | } bool; | ||||
typedef enum { | |||||
BO_BIG_ENDIAN, | |||||
BO_LITTLE_ENDIAN | |||||
} byteorder_t; | |||||
typedef enum { | typedef enum { | ||||
MODE_IMAGE, | MODE_IMAGE, | ||||
MODE_THUMB | MODE_THUMB | ||||