From b99e22bb614c3ff22ace371cbd9cb0575f4df20b Mon Sep 17 00:00:00 2001 From: Akira Kakuto Date: Mon, 16 Feb 2015 14:04:13 +0000 Subject: web2c/pdftexdir/writejpg.c: support Exif in addition to JFIF. (borrowed from dvipdfm-x) git-svn-id: svn://tug.org/texlive/trunk@36291 c570f23f-e606-0410-a88d-b1316a301751 --- Build/source/texk/web2c/pdftexdir/ChangeLog | 5 + Build/source/texk/web2c/pdftexdir/writejpg.c | 169 ++++++++++++++++++++++++++- 2 files changed, 171 insertions(+), 3 deletions(-) (limited to 'Build/source/texk/web2c') diff --git a/Build/source/texk/web2c/pdftexdir/ChangeLog b/Build/source/texk/web2c/pdftexdir/ChangeLog index e49070fdf80..b64f203941a 100644 --- a/Build/source/texk/web2c/pdftexdir/ChangeLog +++ b/Build/source/texk/web2c/pdftexdir/ChangeLog @@ -1,3 +1,8 @@ +2015-02-16 Akira Kakuto + + * writejpg.c: support JPEG Exif in addition to JFIF. + (borrowed from dvipdfm-x). + 2014-12-12 Karl Berry * pdftoepdf.cc (read_pdf_info): do not even warn if diff --git a/Build/source/texk/web2c/pdftexdir/writejpg.c b/Build/source/texk/web2c/pdftexdir/writejpg.c index 39880063bfc..a0267238fe2 100644 --- a/Build/source/texk/web2c/pdftexdir/writejpg.c +++ b/Build/source/texk/web2c/pdftexdir/writejpg.c @@ -97,9 +97,154 @@ static JPG_UINT16 read2bytes(FILE * f) return (c << 8) + xgetc(f); } +static unsigned char +get_unsigned_byte (FILE *file) +{ + int ch; + ch = fgetc (file); + return (unsigned char) ch; +} + +static unsigned short +get_unsigned_pair (FILE *file) +{ + unsigned short pair = get_unsigned_byte(file); + pair = (pair << 8) | get_unsigned_byte(file); + return pair; +} + +static unsigned int +read_exif_bytes(unsigned char **p, int n, int b) +{ + unsigned int rval = 0; + unsigned char *pp = *p; + if (b) { + switch (n) { + case 4: + rval += *pp++; rval <<= 8; + rval += *pp++; rval <<= 8; + case 2: + rval += *pp++; rval <<= 8; + rval += *pp; + break; + } + } else { + pp += n; + switch (n) { + case 4: + rval += *--pp; rval <<= 8; + rval += *--pp; rval <<= 8; + case 2: + rval += *--pp; rval <<= 8; + rval += *--pp; + break; + } + } + *p += n; + return rval; +} + +#define NEW(n, t) (t*)xmalloc(n * sizeof(t)) + +static void +read_APP1_Exif (FILE *fp, unsigned short length, int *xx, int *yy) +{ + /* this doesn't save the data, just reads the tags we need */ + /* based on info from http://www.exif.org/Exif2-2.PDF */ + unsigned char *buffer = NEW(length, unsigned char); + unsigned char *p, *rp; + unsigned char *tiff_header; + char bigendian; + int i; + int num_fields, tag, type; + int value = 0, num = 0, den = 0; /* silence uninitialized warnings */ + double xres = 72.0; + double yres = 72.0; + double res_unit = 1.0; + fread(buffer, length, 1, fp); + p = buffer; + while ((p < buffer + length) && (*p == 0)) + ++p; + tiff_header = p; + if ((*p == 'M') && (*(p+1) == 'M')) + bigendian = 1; + else if ((*p == 'I') && (*(p+1) == 'I')) + bigendian = 0; + else + goto err; + p += 2; + i = read_exif_bytes(&p, 2, bigendian); + if (i != 42) + goto err; + i = read_exif_bytes(&p, 4, bigendian); + p = tiff_header + i; + num_fields = read_exif_bytes(&p, 2, bigendian); + while (num_fields-- > 0) { + tag = read_exif_bytes(&p, 2, bigendian); + type = read_exif_bytes(&p, 2, bigendian); + read_exif_bytes(&p, 4, bigendian); + switch (type) { + case 1: /* byte */ + value = *p++; + p += 3; + break; + case 3: /* short */ + value = read_exif_bytes(&p, 2, bigendian); + p += 2; + break; + case 4: /* long */ + case 9: /* slong */ + value = read_exif_bytes(&p, 4, bigendian); + break; + case 5: /* rational */ + case 10: /* srational */ + value = read_exif_bytes(&p, 4, bigendian); + rp = tiff_header + value; + num = read_exif_bytes(&rp, 4, bigendian); + den = read_exif_bytes(&rp, 4, bigendian); + break; + case 7: /* undefined */ + value = *p++; + p += 3; + break; + case 2: /* ascii */ + default: + p += 4; + break; + } + switch (tag) { + case 282: /* x res */ + if (den != 0) + xres = num / den; + break; + case 283: /* y res */ + if (den != 0) + yres = num / den; + break; + case 296: /* res unit */ + switch (value) { + case 2: + res_unit = 1.0; + break; + case 3: + res_unit = 2.54; + break; + } + } + } + + *xx = (int)(xres * res_unit); + *yy = (int)(yres * res_unit); + +err: + free(buffer); + return; +} + void read_jpg_info(integer img) { int i, units = 0; + unsigned short appmk, length; unsigned char jpg_id[] = "JFIF"; img_xres(img) = img_yres(img) = 0; jpg_ptr(img)->file = xfopen(img_name(img), FOPEN_RBIN_MODE); @@ -109,8 +254,9 @@ void read_jpg_info(integer img) xfseek(jpg_ptr(img)->file, 0, SEEK_SET, cur_file_name); if (read2bytes(jpg_ptr(img)->file) != 0xFFD8) pdftex_fail("reading JPEG image failed (no JPEG header found)"); - /* currently only true JFIF files allow extracting img_xres and img_yres */ - if (read2bytes(jpg_ptr(img)->file) == 0xFFE0) { /* check for JFIF */ + /* currently JFIF and Exif files allow extracting img_xres and img_yres */ + appmk = read2bytes(jpg_ptr(img)->file); + if (appmk == 0xFFE0) { /* check for JFIF */ (void) read2bytes(jpg_ptr(img)->file); for (i = 0; i < 5; i++) { if (xgetc(jpg_ptr(img)->file) != jpg_id[i]) @@ -133,13 +279,30 @@ void read_jpg_info(integer img) break; } } - /* if either xres or yres is 0 but the other isn't, set it to the value of the other */ + /* if either xres or yres is 0 but the other isn't, + set it to the value of the other */ if ((img_xres(img) == 0) && (img_yres(img) != 0)) { img_xres(img) = img_yres(img); } if ((img_yres(img) == 0) && (img_xres(img) != 0)) { img_yres(img) = img_xres(img); } + } else if (appmk == 0xFFE1) { /* check for Exif */ + FILE *fp = jpg_ptr(img)->file; + int xxres = 0; + int yyres = 0; + char app_sig[32]; + length = get_unsigned_pair(fp) - 2; + if (length > 5) { + if (fread(app_sig, sizeof(char), 5, fp) != 5) + return; + length -= 5; + if (!memcmp(app_sig, "Exif\000", 5)) { + read_APP1_Exif(fp, length, &xxres, &yyres); + } + } + img_xres(img) = xxres; + img_yres(img) = yyres; } xfseek(jpg_ptr(img)->file, 0, SEEK_SET, cur_file_name); while (1) { -- cgit v1.2.3