summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkira Kakuto <kakuto@fuk.kindai.ac.jp>2015-02-16 14:04:13 +0000
committerAkira Kakuto <kakuto@fuk.kindai.ac.jp>2015-02-16 14:04:13 +0000
commitb99e22bb614c3ff22ace371cbd9cb0575f4df20b (patch)
tree5d271d01ea310ee0b6ec41b78f066024cba83c5c
parentfc4a269b1e7e288838aa2508ae615b130268eac4 (diff)
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
-rw-r--r--Build/source/texk/web2c/pdftexdir/ChangeLog5
-rw-r--r--Build/source/texk/web2c/pdftexdir/writejpg.c169
2 files changed, 171 insertions, 3 deletions
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 <kakuto@fuk.kindai.ac.jp>
+
+ * writejpg.c: support JPEG Exif in addition to JFIF.
+ (borrowed from dvipdfm-x).
+
2014-12-12 Karl Berry <karl@gnu.org>
* 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) {