aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAraki Ken <arakiken@users.sf.net>2014-09-25 14:21:41 +0000
committerTatsuya Kinoshita <tats@debian.org>2014-12-06 11:47:05 +0000
commit4a9c976e32a6bab9dbac4380803e5eb92f601284 (patch)
tree141245504b05389d70eb854736948405b4c4e706
parentsystem() -> fork()&execvp() (diff)
downloadw3m-4a9c976e32a6bab9dbac4380803e5eb92f601284.tar.gz
w3m-4a9c976e32a6bab9dbac4380803e5eb92f601284.zip
Show the first frame of animation gif files.
Diffstat (limited to '')
-rw-r--r--terms.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/terms.c b/terms.c
index 66d0ff8..5f0e638 100644
--- a/terms.c
+++ b/terms.c
@@ -484,6 +484,89 @@ put_image_osc5379(char *url, int x, int y, int w, int h, int sx, int sy, int sw,
MOVE(Currentbuf->cursorY,Currentbuf->cursorX);
}
+static void
+save_gif(const char *path, u_char *header, size_t header_size, u_char *body, size_t body_size)
+{
+ int fd;
+
+ if ((fd = open(path, O_WRONLY|O_CREAT, 0600)) >= 0) {
+ write(fd, header, header_size) ;
+ write(fd, body, body_size) ;
+ write(fd, "\x3b" , 1) ;
+ close(fd) ;
+ }
+}
+
+static u_char *
+skip_gif_header(u_char *p)
+{
+ /* Header */
+ p += 10;
+
+ if (*(p) & 0x80) {
+ p += (3 * (2 << ((*p) & 0x7)));
+ }
+ p += 3;
+
+ return p;
+}
+
+static void
+save_first_animation_frame(const char *path)
+{
+ int fd;
+ struct stat st;
+ u_char *header;
+ size_t header_size;
+ u_char *body;
+ u_char *p;
+ ssize_t len;
+
+ if ((fd = open( path, O_RDONLY)) < 0) {
+ return 0;
+ }
+
+ if (fstat( fd, &st) != 0 || ! (header = GC_malloc( st.st_size))){
+ close( fd);
+ return 0;
+ }
+
+ len = read(fd, header, st.st_size);
+ close(fd);
+
+ /* Header */
+
+ if (len != st.st_size || strncmp(header, "GIF89a", 6) != 0) {
+ return 0;
+ }
+
+ p = skip_gif_header(header);
+ header_size = p - header;
+
+ /* Application Extension */
+ if (p[0] == 0x21 && p[1] == 0xff) {
+ p += 19;
+ }
+
+ /* Other blocks */
+ body = NULL;
+ while (p + 2 < header + st.st_size) {
+ if (*(p++) == 0x21 && *(p++) == 0xf9 && *(p++) == 0x04) {
+ if( body) {
+ /* Graphic Control Extension */
+ save_gif(path, header, header_size, body, p - 3 - body);
+ break;
+ }
+ else {
+ /* skip the first frame. */
+ }
+ body = p - 3;
+ }
+ }
+
+ return 1;
+}
+
void
put_image_sixel(char *url, int x, int y, int w, int h, int sx, int sy, int sw, int sh)
{
@@ -492,6 +575,10 @@ put_image_sixel(char *url, int x, int y, int w, int h, int sx, int sy, int sw, i
MOVE(y,x);
flush_tty();
+ if (!strstr(url, "://")) {
+ save_first_animation_frame(url);
+ }
+
if ((pid = fork()) == 0) {
char *argv[11];
char digit[2][11+1];