beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / image / writejpg.w
blob07c51f5e1d0c5ca92e27b7e23b9c0ef1cc5af94d
1 % writejpg.w
3 % Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
4 % Copyright 2006-2011 Taco Hoekwater <taco@@luatex.org>
6 % This file is part of LuaTeX.
8 % LuaTeX is free software; you can redistribute it and/or modify it under
9 % the terms of the GNU General Public License as published by the Free
10 % Software Foundation; either version 2 of the License, or (at your
11 % option) any later version.
13 % LuaTeX is distributed in the hope that it will be useful, but WITHOUT
14 % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 % FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 % License for more details.
18 % You should have received a copy of the GNU General Public License along
19 % with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
21 @ @c
23 #include "ptexlib.h"
24 #include <assert.h>
25 #include "image/image.h"
26 #include "image/writejpg.h"
28 @ @c
29 #define JPG_GRAY 1 /* Gray color space, use /DeviceGray */
30 #define JPG_RGB 3 /* RGB color space, use /DeviceRGB */
31 #define JPG_CMYK 4 /* CMYK color space, use /DeviceCMYK */
33 typedef enum {
34 M_SOF0 = 0xc0, /* baseline DCT */
35 M_SOF1 = 0xc1, /* extended sequential DCT */
36 M_SOF2 = 0xc2, /* progressive DCT */
37 M_SOF3 = 0xc3, /* lossless (sequential) */
39 M_SOF5 = 0xc5, /* differential sequential DCT */
40 M_SOF6 = 0xc6, /* differential progressive DCT */
41 M_SOF7 = 0xc7, /* differential lossless (sequential) */
43 M_JPG = 0xc8, /* reserved for JPEG extensions */
44 M_SOF9 = 0xc9, /* extended sequential DCT */
45 M_SOF10 = 0xca, /* progressive DCT */
46 M_SOF11 = 0xcb, /* lossless (sequential) */
48 M_SOF13 = 0xcd, /* differential sequential DCT */
49 M_SOF14 = 0xce, /* differential progressive DCT */
50 M_SOF15 = 0xcf, /* differential lossless (sequential) */
52 M_DHT = 0xc4, /* define Huffman table(s) */
54 M_DAC = 0xcc, /* define arithmetic conditioning table */
56 M_RST0 = 0xd0, /* restart */
57 M_RST1 = 0xd1, /* restart */
58 M_RST2 = 0xd2, /* restart */
59 M_RST3 = 0xd3, /* restart */
60 M_RST4 = 0xd4, /* restart */
61 M_RST5 = 0xd5, /* restart */
62 M_RST6 = 0xd6, /* restart */
63 M_RST7 = 0xd7, /* restart */
65 M_SOI = 0xd8, /* start of image */
66 M_EOI = 0xd9, /* end of image */
67 M_SOS = 0xda, /* start of scan */
68 M_DQT = 0xdb, /* define quantization tables */
69 M_DNL = 0xdc, /* define number of lines */
70 M_DRI = 0xdd, /* define restart interval */
71 M_DHP = 0xde, /* define hierarchical progression */
72 M_EXP = 0xdf, /* expand reference image(s) */
74 M_APP0 = 0xe0, /* application marker, used for JFIF */
75 M_APP1 = 0xe1, /* application marker */
76 M_APP2 = 0xe2, /* application marker */
77 M_APP3 = 0xe3, /* application marker */
78 M_APP4 = 0xe4, /* application marker */
79 M_APP5 = 0xe5, /* application marker */
80 M_APP6 = 0xe6, /* application marker */
81 M_APP7 = 0xe7, /* application marker */
82 M_APP8 = 0xe8, /* application marker */
83 M_APP9 = 0xe9, /* application marker */
84 M_APP10 = 0xea, /* application marker */
85 M_APP11 = 0xeb, /* application marker */
86 M_APP12 = 0xec, /* application marker */
87 M_APP13 = 0xed, /* application marker */
88 M_APP14 = 0xee, /* application marker, used by Adobe */
89 M_APP15 = 0xef, /* application marker */
91 M_JPG0 = 0xf0, /* reserved for JPEG extensions */
92 M_JPG13 = 0xfd, /* reserved for JPEG extensions */
93 M_COM = 0xfe, /* comment */
95 M_TEM = 0x01, /* temporary use */
97 M_ERROR = 0x100 /* dummy marker, internal use only */
98 } JPEG_MARKER;
100 @ @c
101 static unsigned char myget_unsigned_byte (FILE *file)
103 int ch;
104 ch = fgetc (file);
105 return (unsigned char) ch;
108 @ @c
109 static unsigned short myget_unsigned_pair (FILE *file)
111 unsigned short pair = myget_unsigned_byte(file);
112 pair = (pair << 8) | myget_unsigned_byte(file);
113 return pair;
116 @ @c
117 static unsigned int read_exif_bytes(unsigned char **p, int n, int b)
119 unsigned int rval = 0;
120 unsigned char *pp = *p;
121 if (b) {
122 switch (n) {
123 case 4:
124 rval += *pp++; rval <<= 8;
125 rval += *pp++; rval <<= 8;
126 case 2:
127 rval += *pp++; rval <<= 8;
128 rval += *pp;
129 break;
131 } else {
132 pp += n;
133 switch (n) {
134 case 4:
135 rval += *--pp; rval <<= 8;
136 rval += *--pp; rval <<= 8;
137 case 2:
138 rval += *--pp; rval <<= 8;
139 rval += *--pp;
140 break;
143 *p += n;
144 return rval;
147 @ @c
148 static void read_APP1_Exif (FILE *fp, unsigned short length, int *xx, int *yy)
150 /* this doesn't save the data, just reads the tags we need */
151 /* based on info from http://www.exif.org/Exif2-2.PDF */
152 unsigned char *buffer = (unsigned char *)xmalloc(length);
153 unsigned char *p, *rp;
154 unsigned char *tiff_header;
155 char bigendian;
156 int i;
157 int num_fields, tag, type;
158 int value = 0, num = 0, den = 0; /* silence uninitialized warnings */
159 double xres = 72.0;
160 double yres = 72.0;
161 double res_unit = 1.0;
162 size_t ret_len;
163 ret_len = fread(buffer, length, 1, fp);
164 if (ret_len != 1)
165 goto err ;
166 p = buffer;
167 while ((p < buffer + length) && (*p == 0))
168 ++p;
169 tiff_header = p;
170 if ((*p == 'M') && (*(p+1) == 'M'))
171 bigendian = 1;
172 else if ((*p == 'I') && (*(p+1) == 'I'))
173 bigendian = 0;
174 else
175 goto err;
176 p += 2;
177 i = read_exif_bytes(&p, 2, bigendian);
178 if (i != 42)
179 goto err;
180 i = read_exif_bytes(&p, 4, bigendian);
181 p = tiff_header + i;
182 num_fields = read_exif_bytes(&p, 2, bigendian);
183 while (num_fields-- > 0) {
184 tag = read_exif_bytes(&p, 2, bigendian);
185 type = read_exif_bytes(&p, 2, bigendian);
186 read_exif_bytes(&p, 4, bigendian);
187 switch (type) {
188 case 1: /* byte */
189 value = *p++;
190 p += 3;
191 break;
192 case 3: /* short */
193 value = read_exif_bytes(&p, 2, bigendian);
194 p += 2;
195 break;
196 case 4: /* long */
197 case 9: /* slong */
198 value = read_exif_bytes(&p, 4, bigendian);
199 break;
200 case 5: /* rational */
201 case 10: /* srational */
202 value = read_exif_bytes(&p, 4, bigendian);
203 rp = tiff_header + value;
204 num = read_exif_bytes(&rp, 4, bigendian);
205 den = read_exif_bytes(&rp, 4, bigendian);
206 break;
207 case 7: /* undefined */
208 value = *p++;
209 p += 3;
210 break;
211 case 2: /* ascii */
212 default:
213 p += 4;
214 break;
216 switch (tag) {
217 case 282: /* x res */
218 if (den != 0)
219 xres = num / den;
220 break;
221 case 283: /* y res */
222 if (den != 0)
223 yres = num / den;
224 break;
225 case 296: /* res unit */
226 switch (value) {
227 case 2:
228 res_unit = 1.0;
229 break;
230 case 3:
231 res_unit = 2.54;
232 break;
237 *xx = (int)(xres * res_unit);
238 *yy = (int)(yres * res_unit);
239 err:
240 free(buffer);
241 return;
246 Contrary to pdf where several parallel usage can happen (epdf, tex, lua) with
247 bitmaps we care less about keeping files open. So, we can keep files open in
248 the img lib but then they are closed after inclusion anyway.
252 @ @c
253 static void close_and_cleanup_jpg(image_dict * idict)
255 /* if one of then is not NULL we already cleaned up */
256 if (img_file(idict) != NULL) {
257 xfclose(img_file(idict), img_filepath(idict));
258 img_file(idict) = NULL;
260 if (img_jpg_ptr(idict) != NULL) {
261 xfree(img_jpg_ptr(idict));
265 @ @c
266 void flush_jpg_info(image_dict * idict)
268 close_and_cleanup_jpg(idict);
271 @ @c
272 void read_jpg_info(image_dict * idict)
274 int i, units = 0;
275 unsigned short appmk, length;
276 unsigned char jpg_id[] = "JFIF";
277 if (img_type(idict) != IMG_TYPE_JPG) {
278 normal_error("readjpg","conflicting image dictionary");
280 if (img_file(idict) != NULL) {
281 normal_error("readjpg","image data already read");
283 img_totalpages(idict) = 1;
284 img_pagenum(idict) = 1;
285 img_xres(idict) = img_yres(idict) = 0;
286 img_file(idict) = xfopen(img_filepath(idict), FOPEN_RBIN_MODE);
287 if (img_file(idict) == NULL) {
288 normal_error("readjpg","unable to read image file");
290 img_jpg_ptr(idict) = xtalloc(1, jpg_img_struct);
291 xfseek(img_file(idict), 0, SEEK_END, img_filepath(idict));
292 img_jpg_ptr(idict)->length = xftell(img_file(idict), img_filepath(idict));
293 xfseek(img_file(idict), 0, SEEK_SET, img_filepath(idict));
294 if ((unsigned int) read2bytes(img_file(idict)) != 0xFFD8) {
295 normal_error("readjpg","no header found");
297 /* currently JFIF and Exif files allow extracting |img_xres| and |img_yres| */
298 appmk = read2bytes(img_file(idict));
299 if (appmk == 0xFFE0) {
300 /* check for JFIF */
301 (void) read2bytes(img_file(idict));
302 for (i = 0; i < 5; i++) {
303 if (xgetc(img_file(idict)) != jpg_id[i])
304 break;
306 if (i == 5) {
307 /* it's JFIF */
308 (void) read2bytes(img_file(idict));
309 units = xgetc(img_file(idict));
310 img_xres(idict) = (int) read2bytes(img_file(idict));
311 img_yres(idict) = (int) read2bytes(img_file(idict));
312 switch (units) {
313 case 1:
314 /* pixels per inch */
315 if ((img_xres(idict) == 1) || (img_yres(idict) == 1)) {
316 formatted_warning("readjpg","unusual resolution of %ddpi by %ddpi", img_xres(idict), img_yres(idict));
318 break;
319 case 2:
320 /* pixels per cm */
321 img_xres(idict) = (int) ((double) img_xres(idict) * 2.54);
322 img_yres(idict) = (int) ((double) img_yres(idict) * 2.54);
323 break;
324 default:
325 img_xres(idict) = img_yres(idict) = 0;
326 break;
329 /* if either xres or yres is 0 but the other isn't, set it to the value of the other */
330 if ((img_xres(idict) == 0) && (img_yres(idict) != 0)) {
331 img_xres(idict) = img_yres(idict);
333 if ((img_yres(idict) == 0) && (img_xres(idict) != 0)) {
334 img_yres(idict) = img_xres(idict);
336 } else if (appmk == 0xFFE1) {
337 /* check for Exif */
338 FILE *fp = img_file(idict);
339 int xxres = 0;
340 int yyres = 0;
341 char app_sig[32];
342 length = myget_unsigned_pair(fp) - 2;
343 if (length > 5) {
344 if (fread(app_sig, sizeof(char), 5, fp) != 5)
345 return;
346 length -= 5;
347 if (!memcmp(app_sig, "Exif\000", 5)) {
348 read_APP1_Exif(fp, length, &xxres, &yyres);
351 img_xres(idict) = xxres;
352 img_yres(idict) = yyres;
354 xfseek(img_file(idict), 0, SEEK_SET, img_filepath(idict));
355 while (1) {
356 if (feof(img_file(idict))) {
357 normal_error("readjpg","premature file end");
358 } else if (fgetc(img_file(idict)) != 0xFF) {
359 normal_error("readjpg","no marker found");
361 i = xgetc(img_file(idict));
362 switch (i) {
363 case M_SOF3: /* lossless */
364 case M_SOF5:
365 case M_SOF6:
366 case M_SOF7: /* lossless */
367 case M_SOF9:
368 case M_SOF10:
369 case M_SOF11: /* lossless */
370 case M_SOF13:
371 case M_SOF14:
372 case M_SOF15: /* lossless */
373 formatted_error("readjpg","unsupported compression SOF_%d", i - M_SOF0);
374 break;
375 case M_SOF2:
376 if (img_pdfminorversion(idict) <= 2) {
377 normal_error("readjpg","progressive DCT with PDF-1.2 is not permitted");
379 case M_SOF0:
380 case M_SOF1:
381 (void) read2bytes(img_file(idict)); /* read segment length */
382 img_colordepth(idict) = xgetc(img_file(idict));
383 img_ysize(idict) = (int) read2bytes(img_file(idict));
384 img_xsize(idict) = (int) read2bytes(img_file(idict));
385 img_jpg_color(idict) = xgetc(img_file(idict));
386 xfseek(img_file(idict), 0, SEEK_SET, img_filepath(idict));
387 switch (img_jpg_color(idict)) {
388 case JPG_GRAY:
389 img_procset(idict) |= PROCSET_IMAGE_B;
390 break;
391 case JPG_RGB:
392 img_procset(idict) |= PROCSET_IMAGE_C;
393 break;
394 case JPG_CMYK:
395 img_procset(idict) |= PROCSET_IMAGE_C;
396 break;
397 default:
398 formatted_error("readjpg","unsupported color space %i", (int) img_jpg_color(idict));
401 So we can optionally keep open a file in img.
403 if (! img_keepopen(idict)) {
404 close_and_cleanup_jpg(idict);
406 return;
407 /* ignore markers without parameters */
408 case M_SOI:
409 case M_EOI:
410 case M_TEM:
411 case M_RST0:
412 case M_RST1:
413 case M_RST2:
414 case M_RST3:
415 case M_RST4:
416 case M_RST5:
417 case M_RST6:
418 case M_RST7:
419 break;
420 default:
421 /* skip variable length markers */
422 xfseek(img_file(idict), (int) read2bytes(img_file(idict)) - 2, SEEK_CUR, img_filepath(idict));
423 break;
426 normal_error("readjpg","unknown fatal error");
429 @ @c
430 static void reopen_jpg(image_dict * idict)
432 int width = img_xsize(idict);
433 int height = img_ysize(idict);
434 int xres = img_xres(idict);
435 int yres = img_yres(idict);
437 we need to make sure that the file kept open
439 img_keepopen(idict) = 1;
440 read_jpg_info(idict);
441 if (width != img_xsize(idict) || height != img_ysize(idict) || xres != img_xres(idict) || yres != img_yres(idict)) {
442 normal_error("writejpg","image dimensions have changed");
446 @ @c
447 void write_jpg(PDF pdf, image_dict * idict)
449 size_t l;
450 if (img_file(idict) == NULL) {
451 reopen_jpg(idict);
453 pdf_begin_obj(pdf, img_objnum(idict), OBJSTM_NEVER);
454 pdf_begin_dict(pdf);
455 pdf_dict_add_name(pdf, "Type", "XObject");
456 pdf_dict_add_name(pdf, "Subtype", "Image");
457 pdf_dict_add_img_filename(pdf, idict);
458 if (img_attr(idict) != NULL && strlen(img_attr(idict)) > 0) {
459 pdf_printf(pdf, "\n%s\n", img_attr(idict));
461 pdf_dict_add_int(pdf, "Width", (int) img_xsize(idict));
462 pdf_dict_add_int(pdf, "Height", (int) img_ysize(idict));
463 pdf_dict_add_int(pdf, "BitsPerComponent", (int) img_colordepth(idict));
464 pdf_dict_add_int(pdf, "Length", (int) img_jpg_ptr(idict)->length);
465 if (img_colorspace(idict) != 0) {
466 pdf_dict_add_ref(pdf, "ColorSpace", (int) img_colorspace(idict));
467 } else {
468 switch (img_jpg_color(idict)) {
469 case JPG_GRAY:
470 pdf_dict_add_name(pdf, "ColorSpace", "DeviceGray");
471 break;
472 case JPG_RGB:
473 pdf_dict_add_name(pdf, "ColorSpace", "DeviceRGB");
474 break;
475 case JPG_CMYK:
476 pdf_dict_add_name(pdf, "ColorSpace", "DeviceCMYK");
477 pdf_add_name(pdf, "Decode");
478 pdf_begin_array(pdf);
479 pdf_add_int(pdf, 1);
480 pdf_add_int(pdf, 0);
481 pdf_add_int(pdf, 1);
482 pdf_add_int(pdf, 0);
483 pdf_add_int(pdf, 1);
484 pdf_add_int(pdf, 0);
485 pdf_add_int(pdf, 1);
486 pdf_add_int(pdf, 0);
487 pdf_end_array(pdf);
488 break;
489 default:
490 formatted_error("writejpg","unsupported JPEG color space %i", (int) img_jpg_color(idict));
493 pdf_dict_add_name(pdf, "Filter", "DCTDecode");
494 pdf_end_dict(pdf);
495 pdf_begin_stream(pdf);
496 l = (size_t) img_jpg_ptr(idict)->length;
497 xfseek(img_file(idict), 0, SEEK_SET, img_filepath(idict));
498 if (read_file_to_buf(pdf, img_file(idict), l) != l) {
499 normal_error("writejpg","fread failed");
501 pdf_end_stream(pdf);
502 pdf_end_obj(pdf);
503 /* always */
504 close_and_cleanup_jpg(idict);