1#include "mupdf/fitz.h"
2
3#include <stdio.h>
4#include <string.h>
5#include <limits.h>
6
7#include <jpeglib.h>
8
9#ifdef SHARE_JPEG
10
11#define JZ_CTX_FROM_CINFO(c) (fz_context *)((c)->client_data)
12
13static void fz_jpg_mem_init(j_common_ptr cinfo, fz_context *ctx)
14{
15 cinfo->client_data = ctx;
16}
17
18#define fz_jpg_mem_term(cinfo)
19
20#else /* SHARE_JPEG */
21
22typedef void * backing_store_ptr;
23#include "jmemcust.h"
24
25#define JZ_CTX_FROM_CINFO(c) (fz_context *)(GET_CUST_MEM_DATA(c)->priv)
26
27static void *
28fz_jpg_mem_alloc(j_common_ptr cinfo, size_t size)
29{
30 fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo);
31 return fz_malloc_no_throw(ctx, size);
32}
33
34static void
35fz_jpg_mem_free(j_common_ptr cinfo, void *object, size_t size)
36{
37 fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo);
38 fz_free(ctx, object);
39}
40
41static void
42fz_jpg_mem_init(j_common_ptr cinfo, fz_context *ctx)
43{
44 jpeg_cust_mem_data *custmptr;
45 custmptr = fz_malloc_struct(ctx, jpeg_cust_mem_data);
46 if (!jpeg_cust_mem_init(custmptr, (void *) ctx, NULL, NULL, NULL,
47 fz_jpg_mem_alloc, fz_jpg_mem_free,
48 fz_jpg_mem_alloc, fz_jpg_mem_free, NULL))
49 {
50 fz_free(ctx, custmptr);
51 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot initialize custom JPEG memory handler");
52 }
53 cinfo->client_data = custmptr;
54}
55
56static void
57fz_jpg_mem_term(j_common_ptr cinfo)
58{
59 if (cinfo->client_data)
60 {
61 fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo);
62 fz_free(ctx, cinfo->client_data);
63 cinfo->client_data = NULL;
64 }
65}
66
67#endif /* SHARE_JPEG */
68
69static void error_exit(j_common_ptr cinfo)
70{
71 char msg[JMSG_LENGTH_MAX];
72 fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo);
73
74 cinfo->err->format_message(cinfo, msg);
75 fz_throw(ctx, FZ_ERROR_GENERIC, "jpeg error: %s", msg);
76}
77
78static void init_source(j_decompress_ptr cinfo)
79{
80 /* nothing to do */
81}
82
83static void term_source(j_decompress_ptr cinfo)
84{
85 /* nothing to do */
86}
87
88static boolean fill_input_buffer(j_decompress_ptr cinfo)
89{
90 static unsigned char eoi[2] = { 0xFF, JPEG_EOI };
91 struct jpeg_source_mgr *src = cinfo->src;
92 src->next_input_byte = eoi;
93 src->bytes_in_buffer = 2;
94 return 1;
95}
96
97static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
98{
99 struct jpeg_source_mgr *src = cinfo->src;
100 if (num_bytes > 0)
101 {
102 size_t skip = (size_t)num_bytes; /* size_t may be 64bit */
103 if (skip > src->bytes_in_buffer)
104 skip = (size_t)src->bytes_in_buffer;
105 src->next_input_byte += skip;
106 src->bytes_in_buffer -= skip;
107 }
108}
109
110static inline int read_value(const unsigned char *data, int bytes, int is_big_endian)
111{
112 int value = 0;
113 if (!is_big_endian)
114 data += bytes;
115 for (; bytes > 0; bytes--)
116 value = (value << 8) | (is_big_endian ? *data++ : *--data);
117 return value;
118}
119
120enum {
121 MAX_ICC_PARTS = 256
122};
123
124static fz_colorspace *extract_icc_profile(fz_context *ctx, jpeg_saved_marker_ptr init_marker, int output_components, fz_colorspace *colorspace)
125{
126#if FZ_ENABLE_ICC
127 const char idseq[] = { 'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I', 'L', 'E', '\0'};
128 jpeg_saved_marker_ptr marker = init_marker;
129 fz_buffer *buf = NULL;
130 fz_colorspace *icc;
131 int part = 1;
132 int parts = MAX_ICC_PARTS;
133 const unsigned char *data;
134 size_t size;
135
136 fz_var(buf);
137
138 if (init_marker == NULL)
139 return colorspace;
140
141 fz_try(ctx)
142 {
143 while (part < parts && marker != NULL)
144 {
145 for (marker = init_marker; marker != NULL; marker = marker->next)
146 {
147 if (marker->marker != JPEG_APP0 + 2)
148 continue;
149 if (marker->data_length < nelem(idseq) + 2)
150 continue;
151 if (memcmp(marker->data, idseq, nelem(idseq)))
152 continue;
153 if (marker->data[nelem(idseq)] != part)
154 continue;
155
156 if (parts == MAX_ICC_PARTS)
157 parts = marker->data[nelem(idseq) + 1];
158 else if (marker->data[nelem(idseq) + 1] != parts)
159 fz_warn(ctx, "inconsistent number of icc profile chunks in jpeg");
160 if (part > parts)
161 {
162 fz_warn(ctx, "skipping out of range icc profile chunk in jpeg");
163 continue;
164 }
165
166 data = marker->data + 14;
167 size = marker->data_length - 14;
168
169 if (!buf)
170 buf = fz_new_buffer_from_copied_data(ctx, data, size);
171 else
172 fz_append_data(ctx, buf, data, size);
173
174 part++;
175 break;
176 }
177 }
178
179 if (buf)
180 {
181 icc = fz_new_icc_colorspace(ctx, fz_colorspace_type(ctx, colorspace), 0, NULL, buf);
182 fz_drop_colorspace(ctx, colorspace);
183 colorspace = icc;
184 }
185 }
186 fz_always(ctx)
187 fz_drop_buffer(ctx, buf);
188 fz_catch(ctx)
189 fz_warn(ctx, "ignoring embedded ICC profile in JPEG");
190
191 return colorspace;
192#else
193 return colorspace;
194#endif
195}
196
197static int extract_exif_resolution(jpeg_saved_marker_ptr marker, int *xres, int *yres)
198{
199 int is_big_endian;
200 const unsigned char *data;
201 unsigned int offset, ifd_len, res_type = 0;
202 float x_res = 0, y_res = 0;
203
204 if (!marker || marker->marker != JPEG_APP0 + 1 || marker->data_length < 14)
205 return 0;
206 data = (const unsigned char *)marker->data;
207 if (read_value(data, 4, 1) != 0x45786966 /* Exif */ || read_value(data + 4, 2, 1) != 0x0000)
208 return 0;
209 if (read_value(data + 6, 4, 1) == 0x49492A00)
210 is_big_endian = 0;
211 else if (read_value(data + 6, 4, 1) == 0x4D4D002A)
212 is_big_endian = 1;
213 else
214 return 0;
215
216 offset = read_value(data + 10, 4, is_big_endian) + 6;
217 if (offset < 14 || offset > marker->data_length - 2)
218 return 0;
219 ifd_len = read_value(data + offset, 2, is_big_endian);
220 for (offset += 2; ifd_len > 0 && offset + 12 < marker->data_length; ifd_len--, offset += 12)
221 {
222 int tag = read_value(data + offset, 2, is_big_endian);
223 int type = read_value(data + offset + 2, 2, is_big_endian);
224 int count = read_value(data + offset + 4, 4, is_big_endian);
225 unsigned int value_off = read_value(data + offset + 8, 4, is_big_endian) + 6;
226 switch (tag)
227 {
228 case 0x11A:
229 if (type == 5 && value_off > offset && value_off <= marker->data_length - 8)
230 x_res = 1.0f * read_value(data + value_off, 4, is_big_endian) / read_value(data + value_off + 4, 4, is_big_endian);
231 break;
232 case 0x11B:
233 if (type == 5 && value_off > offset && value_off <= marker->data_length - 8)
234 y_res = 1.0f * read_value(data + value_off, 4, is_big_endian) / read_value(data + value_off + 4, 4, is_big_endian);
235 break;
236 case 0x128:
237 if (type == 3 && count == 1)
238 res_type = read_value(data + offset + 8, 2, is_big_endian);
239 break;
240 }
241 }
242
243 if (x_res <= 0 || x_res > INT_MAX || y_res <= 0 || y_res > INT_MAX)
244 return 0;
245 if (res_type == 2)
246 {
247 *xres = (int)x_res;
248 *yres = (int)y_res;
249 }
250 else if (res_type == 3)
251 {
252 *xres = (int)(x_res * 254 / 100);
253 *yres = (int)(y_res * 254 / 100);
254 }
255 else
256 {
257 *xres = 0;
258 *yres = 0;
259 }
260 return 1;
261}
262
263static int extract_app13_resolution(jpeg_saved_marker_ptr marker, int *xres, int *yres)
264{
265 const unsigned char *data, *data_end;
266
267 if (!marker || marker->marker != JPEG_APP0 + 13 || marker->data_length < 42 ||
268 strcmp((const char *)marker->data, "Photoshop 3.0") != 0)
269 {
270 return 0;
271 }
272
273 data = (const unsigned char *)marker->data;
274 data_end = data + marker->data_length;
275 for (data += 14; data + 12 < data_end; ) {
276 int data_size = -1;
277 int tag = read_value(data + 4, 2, 1);
278 int value_off = 11 + read_value(data + 6, 2, 1);
279 if (value_off % 2 == 1)
280 value_off++;
281 if (read_value(data, 4, 1) == 0x3842494D /* 8BIM */ && value_off <= data_end - data)
282 data_size = read_value(data + value_off - 4, 4, 1);
283 if (data_size < 0 || data_size > data_end - data - value_off)
284 return 0;
285 if (tag == 0x3ED && data_size == 16)
286 {
287 *xres = read_value(data + value_off, 2, 1);
288 *yres = read_value(data + value_off + 8, 2, 1);
289 return 1;
290 }
291 if (data_size % 2 == 1)
292 data_size++;
293 data += value_off + data_size;
294 }
295
296 return 0;
297}
298
299fz_pixmap *
300fz_load_jpeg(fz_context *ctx, const unsigned char *rbuf, size_t rlen)
301{
302 struct jpeg_decompress_struct cinfo;
303 struct jpeg_error_mgr err;
304 struct jpeg_source_mgr src;
305 unsigned char *row[1], *sp, *dp;
306 fz_colorspace *colorspace = NULL;
307 unsigned int x;
308 int k, stride;
309 fz_pixmap *image = NULL;
310
311 fz_var(colorspace);
312 fz_var(image);
313 fz_var(row);
314
315 row[0] = NULL;
316
317 cinfo.mem = NULL;
318 cinfo.global_state = 0;
319 cinfo.err = jpeg_std_error(&err);
320 err.error_exit = error_exit;
321
322 cinfo.client_data = NULL;
323 fz_jpg_mem_init((j_common_ptr)&cinfo, ctx);
324
325 fz_try(ctx)
326 {
327 jpeg_create_decompress(&cinfo);
328
329 cinfo.src = &src;
330 src.init_source = init_source;
331 src.fill_input_buffer = fill_input_buffer;
332 src.skip_input_data = skip_input_data;
333 src.resync_to_restart = jpeg_resync_to_restart;
334 src.term_source = term_source;
335 src.next_input_byte = rbuf;
336 src.bytes_in_buffer = rlen;
337
338 jpeg_save_markers(&cinfo, JPEG_APP0+1, 0xffff);
339 jpeg_save_markers(&cinfo, JPEG_APP0+13, 0xffff);
340
341 jpeg_read_header(&cinfo, 1);
342
343 jpeg_start_decompress(&cinfo);
344
345 if (cinfo.output_components == 1)
346 colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx));
347 else if (cinfo.output_components == 3)
348 colorspace = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
349 else if (cinfo.output_components == 4)
350 colorspace = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
351 colorspace = extract_icc_profile(ctx, cinfo.marker_list, cinfo.output_components, colorspace);
352 if (!colorspace)
353 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot determine colorspace");
354
355 image = fz_new_pixmap(ctx, colorspace, cinfo.output_width, cinfo.output_height, NULL, 0);
356
357 if (extract_exif_resolution(cinfo.marker_list, &image->xres, &image->yres))
358 /* XPS prefers EXIF resolution to JFIF density */;
359 else if (extract_app13_resolution(cinfo.marker_list, &image->xres, &image->yres))
360 /* XPS prefers APP13 resolution to JFIF density */;
361 else if (cinfo.density_unit == 1)
362 {
363 image->xres = cinfo.X_density;
364 image->yres = cinfo.Y_density;
365 }
366 else if (cinfo.density_unit == 2)
367 {
368 image->xres = cinfo.X_density * 254 / 100;
369 image->yres = cinfo.Y_density * 254 / 100;
370 }
371
372 if (image->xres <= 0) image->xres = 96;
373 if (image->yres <= 0) image->yres = 96;
374
375 fz_clear_pixmap(ctx, image);
376
377 row[0] = fz_malloc(ctx, cinfo.output_components * cinfo.output_width);
378 dp = image->samples;
379 stride = image->stride - image->w * image->n;
380 while (cinfo.output_scanline < cinfo.output_height)
381 {
382 jpeg_read_scanlines(&cinfo, row, 1);
383 sp = row[0];
384 for (x = 0; x < cinfo.output_width; x++)
385 {
386 for (k = 0; k < cinfo.output_components; k++)
387 *dp++ = *sp++;
388 }
389 dp += stride;
390 }
391 }
392 fz_always(ctx)
393 {
394 fz_drop_colorspace(ctx, colorspace);
395 fz_free(ctx, row[0]);
396 row[0] = NULL;
397
398 /* We call jpeg_abort rather than the more usual
399 * jpeg_finish_decompress here. This has the same effect,
400 * but doesn't spew warnings if we didn't read enough data etc.
401 * Annoyingly jpeg_abort can throw
402 */
403 fz_try(ctx)
404 jpeg_abort((j_common_ptr)&cinfo);
405 fz_catch(ctx)
406 {
407 /* Ignore any errors here */
408 }
409
410 jpeg_destroy_decompress(&cinfo);
411 fz_jpg_mem_term((j_common_ptr)&cinfo);
412 }
413 fz_catch(ctx)
414 {
415 fz_drop_pixmap(ctx, image);
416 fz_rethrow(ctx);
417 }
418
419 return image;
420}
421
422void
423fz_load_jpeg_info(fz_context *ctx, const unsigned char *rbuf, size_t rlen, int *xp, int *yp, int *xresp, int *yresp, fz_colorspace **cspacep)
424{
425 struct jpeg_decompress_struct cinfo;
426 struct jpeg_error_mgr err;
427 struct jpeg_source_mgr src;
428 fz_colorspace *icc = NULL;
429
430 *cspacep = NULL;
431
432 cinfo.mem = NULL;
433 cinfo.global_state = 0;
434 cinfo.err = jpeg_std_error(&err);
435 err.error_exit = error_exit;
436
437 cinfo.client_data = NULL;
438 fz_jpg_mem_init((j_common_ptr)&cinfo, ctx);
439
440 fz_try(ctx)
441 {
442 jpeg_create_decompress(&cinfo);
443
444 cinfo.src = &src;
445 src.init_source = init_source;
446 src.fill_input_buffer = fill_input_buffer;
447 src.skip_input_data = skip_input_data;
448 src.resync_to_restart = jpeg_resync_to_restart;
449 src.term_source = term_source;
450 src.next_input_byte = rbuf;
451 src.bytes_in_buffer = rlen;
452
453 jpeg_save_markers(&cinfo, JPEG_APP0+1, 0xffff);
454 jpeg_save_markers(&cinfo, JPEG_APP0+13, 0xffff);
455 jpeg_save_markers(&cinfo, JPEG_APP0+2, 0xffff);
456
457 jpeg_read_header(&cinfo, 1);
458
459 *xp = cinfo.image_width;
460 *yp = cinfo.image_height;
461
462 if (cinfo.num_components == 1)
463 *cspacep = fz_keep_colorspace(ctx, fz_device_gray(ctx));
464 else if (cinfo.num_components == 3)
465 *cspacep = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
466 else if (cinfo.num_components == 4)
467 *cspacep = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
468 *cspacep = extract_icc_profile(ctx, cinfo.marker_list, cinfo.num_components, *cspacep);
469 if (!*cspacep)
470 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot determine colorspace");
471
472 if (extract_exif_resolution(cinfo.marker_list, xresp, yresp))
473 /* XPS prefers EXIF resolution to JFIF density */;
474 else if (extract_app13_resolution(cinfo.marker_list, xresp, yresp))
475 /* XPS prefers APP13 resolution to JFIF density */;
476 else if (cinfo.density_unit == 1)
477 {
478 *xresp = cinfo.X_density;
479 *yresp = cinfo.Y_density;
480 }
481 else if (cinfo.density_unit == 2)
482 {
483 *xresp = cinfo.X_density * 254 / 100;
484 *yresp = cinfo.Y_density * 254 / 100;
485 }
486 else
487 {
488 *xresp = 0;
489 *yresp = 0;
490 }
491
492 if (*xresp <= 0) *xresp = 96;
493 if (*yresp <= 0) *yresp = 96;
494 }
495 fz_always(ctx)
496 {
497 jpeg_destroy_decompress(&cinfo);
498 fz_jpg_mem_term((j_common_ptr)&cinfo);
499 }
500 fz_catch(ctx)
501 {
502 fz_drop_colorspace(ctx, icc);
503 fz_rethrow(ctx);
504 }
505}
506