diff options
author | Araki Ken <arakiken@users.sf.net> | 2014-03-01 06:31:27 +0000 |
---|---|---|
committer | Tatsuya Kinoshita <tats@debian.org> | 2014-12-06 11:47:04 +0000 |
commit | 0c0d4b5f387483dac627349e3415d5a7e7177fb2 (patch) | |
tree | 36af390b9874a199c2447735e4d0dbf2550c1ee7 /image.c | |
parent | * display.c: Draw underline on anchor text which is not overlapped with any i... (diff) | |
download | w3m-0c0d4b5f387483dac627349e3415d5a7e7177fb2.tar.gz w3m-0c0d4b5f387483dac627349e3415d5a7e7177fb2.zip |
Read width and height from jpeg, png and gif files directly instead of executing w3mimgdisplay -size.
Diffstat (limited to 'image.c')
-rw-r--r-- | image.c | 91 |
1 files changed, 91 insertions, 0 deletions
@@ -625,6 +625,91 @@ getImage(Image * image, ParsedURL *current, int flag) return cache; } +static int +parseImageHeader(char *path, u_int *width, u_int *height) +{ + char *suffix; + + suffix = path + strlen(path); + if (strcasecmp(suffix - 5, ".jpeg") == 0 || strcasecmp(suffix - 4 , ".jpg") == 0) { + FILE *fp = fopen(path, "r"); + if (fp) { + u_char buf[2]; + if (fread(buf, 1, 2, fp) != 2 || memcmp(buf, "\xff\xd8", 2) != 0 || + fseek(fp, 2, SEEK_CUR) < 0) /* 0xffe0 */ + goto jpg_error; + + while (fread(buf, 1, 2, fp) == 2) { + size_t len = ((buf[0] << 8) | buf[1]) - 2; + if (fseek(fp, len, SEEK_CUR) < 0) goto jpg_error; + if (fread(buf, 1, 2, fp) == 2 && memcmp(buf, "\xff\xc0", 2) == 0) { + fseek(fp, 3, SEEK_CUR); + if (fread(buf, 1, 2, fp) == 2) { + *height = (buf[0] << 8) | buf[1]; + if (fread(buf, 1, 2, fp) == 2) { + *width = (buf[0] << 8) | buf[1]; + fclose(fp); + return TRUE; + } + } + break; + } + } + + jpg_error: + fclose(fp); + return FALSE; + } + } + else if (strcasecmp(suffix - 4, ".png") == 0) { + FILE *fp = fopen(path, "r"); + if (fp) { + u_char buf[8]; + if (fread(buf, 1, 8, fp) != 8 || + memcmp(buf, "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8) != 0 || + fseek(fp, 8, SEEK_CUR) < 0) + goto png_error; + + if (fread(buf, 1, 4, fp) == 4) { + *width = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + if (fread(buf, 1, 4, fp) == 4) { + *height = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + fclose(fp); + return TRUE; + } + } + + png_error: + fclose(fp); + return FALSE; + } + } + else if (strcasecmp(suffix - 4, ".gif") == 0) { + FILE *fp = fopen(path, "r"); + if (fp) { + u_char buf[3]; + if (fread(buf, 1, 3, fp) != 3 || memcmp(buf, "GIF", 3) != 0 || + fseek(fp, 3, SEEK_CUR) < 0) { + goto png_error; + } + if (fread(buf, 1, 2, fp) == 2) { + *width = (buf[1] << 8) | buf[0]; + if (fread(buf, 1, 2, fp) == 2) { + *height = (buf[1] << 8) | buf[0]; + fclose(fp); + return TRUE; + } + } + } + + gif_error: + fclose(fp); + return FALSE; + } + + return FALSE; +} + int getImageSize(ImageCache * cache) { @@ -637,6 +722,10 @@ getImageSize(ImageCache * cache) if (!cache || !(cache->loaded & IMG_FLAG_LOADED) || (cache->width > 0 && cache->height > 0)) return FALSE; + + if (parseImageHeader(cache->file, &w, &h)) + goto got_image_size; + tmp = Strnew(); if (!strchr(Imgdisplay, '/')) Strcat_m_charp(tmp, w3m_auxbin_dir(), "/", NULL); @@ -652,6 +741,8 @@ getImageSize(ImageCache * cache) if (!(w > 0 && h > 0)) return FALSE; + +got_image_size: w = (int)(w * image_scale / 100 + 0.5); if (w == 0) w = 1; |