Coverage Report

Created: 2024-05-20 06:23

/src/mupdf/source/fitz/load-jpeg.c
Line
Count
Source (jump to first uncovered line)
1
// Copyright (C) 2004-2023 Artifex Software, Inc.
2
//
3
// This file is part of MuPDF.
4
//
5
// MuPDF is free software: you can redistribute it and/or modify it under the
6
// terms of the GNU Affero General Public License as published by the Free
7
// Software Foundation, either version 3 of the License, or (at your option)
8
// any later version.
9
//
10
// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
// details.
14
//
15
// You should have received a copy of the GNU Affero General Public License
16
// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17
//
18
// Alternative licensing terms are available from the licensor.
19
// For commercial licensing, see <https://www.artifex.com/> or contact
20
// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21
// CA 94129, USA, for further information.
22
23
#include "mupdf/fitz.h"
24
25
#include <math.h>
26
#include <stdio.h>
27
#include <string.h>
28
#include <limits.h>
29
30
#include <jpeglib.h>
31
32
#ifdef SHARE_JPEG
33
34
#define JZ_CTX_FROM_CINFO(c) (fz_context *)((c)->client_data)
35
36
static void fz_jpg_mem_init(j_common_ptr cinfo, fz_context *ctx)
37
{
38
  cinfo->client_data = ctx;
39
}
40
41
#define fz_jpg_mem_term(cinfo)
42
43
#else /* SHARE_JPEG */
44
45
typedef void * backing_store_ptr;
46
#include "jmemcust.h"
47
48
8.41k
#define JZ_CTX_FROM_CINFO(c) (fz_context *)(GET_CUST_MEM_DATA(c)->priv)
49
50
static void *
51
fz_jpg_mem_alloc(j_common_ptr cinfo, size_t size)
52
3.59k
{
53
3.59k
  fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo);
54
3.59k
  return fz_malloc_no_throw(ctx, size);
55
3.59k
}
56
57
static void
58
fz_jpg_mem_free(j_common_ptr cinfo, void *object, size_t size)
59
3.59k
{
60
3.59k
  fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo);
61
3.59k
  fz_free(ctx, object);
62
3.59k
}
63
64
static void
65
fz_jpg_mem_init(j_common_ptr cinfo, fz_context *ctx)
66
1.01k
{
67
1.01k
  jpeg_cust_mem_data *custmptr;
68
1.01k
  custmptr = fz_malloc_struct(ctx, jpeg_cust_mem_data);
69
1.01k
  if (!jpeg_cust_mem_init(custmptr, (void *) ctx, NULL, NULL, NULL,
70
1.01k
        fz_jpg_mem_alloc, fz_jpg_mem_free,
71
1.01k
        fz_jpg_mem_alloc, fz_jpg_mem_free, NULL))
72
0
  {
73
0
    fz_free(ctx, custmptr);
74
0
    fz_throw(ctx, FZ_ERROR_LIBRARY, "cannot initialize custom JPEG memory handler");
75
0
  }
76
1.01k
  cinfo->client_data = custmptr;
77
1.01k
}
78
79
static void
80
fz_jpg_mem_term(j_common_ptr cinfo)
81
1.01k
{
82
1.01k
  if (cinfo->client_data)
83
1.01k
  {
84
1.01k
    fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo);
85
1.01k
    fz_free(ctx, cinfo->client_data);
86
1.01k
    cinfo->client_data = NULL;
87
1.01k
  }
88
1.01k
}
89
90
#endif /* SHARE_JPEG */
91
92
static void output_message(j_common_ptr cinfo)
93
0
{
94
  /* swallow message */
95
0
}
96
97
static void error_exit(j_common_ptr cinfo)
98
199
{
99
199
  char msg[JMSG_LENGTH_MAX];
100
199
  fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo);
101
102
199
  cinfo->err->format_message(cinfo, msg);
103
199
  fz_throw(ctx, FZ_ERROR_LIBRARY, "jpeg error: %s", msg);
104
199
}
105
106
static void init_source(j_decompress_ptr cinfo)
107
1.01k
{
108
  /* nothing to do */
109
1.01k
}
110
111
static void term_source(j_decompress_ptr cinfo)
112
0
{
113
  /* nothing to do */
114
0
}
115
116
static boolean fill_input_buffer(j_decompress_ptr cinfo)
117
149k
{
118
149k
  static unsigned char eoi[2] = { 0xFF, JPEG_EOI };
119
149k
  struct jpeg_source_mgr *src = cinfo->src;
120
149k
  src->next_input_byte = eoi;
121
149k
  src->bytes_in_buffer = 2;
122
149k
  return 1;
123
149k
}
124
125
static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
126
1.19k
{
127
1.19k
  struct jpeg_source_mgr *src = cinfo->src;
128
1.19k
  if (num_bytes > 0)
129
1.19k
  {
130
1.19k
    size_t skip = (size_t)num_bytes; /* size_t may be 64bit */
131
1.19k
    if (skip > src->bytes_in_buffer)
132
39
      skip = (size_t)src->bytes_in_buffer;
133
1.19k
    src->next_input_byte += skip;
134
1.19k
    src->bytes_in_buffer -= skip;
135
1.19k
  }
136
1.19k
}
137
138
static inline int read_value(const unsigned char *data, int bytes, int is_big_endian)
139
82.5k
{
140
82.5k
  int value = 0;
141
82.5k
  if (!is_big_endian)
142
24.2k
    data += bytes;
143
330k
  for (; bytes > 0; bytes--)
144
247k
    value = (value << 8) | (is_big_endian ? *data++ : *--data);
145
82.5k
  return value;
146
82.5k
}
147
148
enum {
149
  MAX_ICC_PARTS = 256
150
};
151
152
static fz_colorspace *extract_icc_profile(fz_context *ctx, jpeg_saved_marker_ptr init_marker, int output_components, fz_colorspace *colorspace)
153
819
{
154
819
#if FZ_ENABLE_ICC
155
819
  const char idseq[] = { 'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I', 'L', 'E', '\0'};
156
819
  jpeg_saved_marker_ptr marker = init_marker;
157
819
  fz_buffer *buf = NULL;
158
819
  fz_colorspace *icc;
159
819
  int part = 1;
160
819
  int parts = MAX_ICC_PARTS;
161
819
  const unsigned char *data;
162
819
  size_t size;
163
164
819
  fz_var(buf);
165
166
819
  if (init_marker == NULL)
167
754
    return colorspace;
168
169
130
  fz_try(ctx)
170
130
  {
171
133
    while (part < parts && marker != NULL)
172
68
    {
173
557
      for (marker = init_marker; marker != NULL; marker = marker->next)
174
498
      {
175
498
        if (marker->marker != JPEG_APP0 + 2)
176
44
          continue;
177
454
        if (marker->data_length < nelem(idseq) + 2)
178
64
          continue;
179
390
        if (memcmp(marker->data, idseq, nelem(idseq)))
180
152
          continue;
181
238
        if (marker->data[nelem(idseq)] != part)
182
229
          continue;
183
184
9
        if (parts == MAX_ICC_PARTS)
185
9
          parts = marker->data[nelem(idseq) + 1];
186
0
        else if (marker->data[nelem(idseq) + 1] != parts)
187
0
          fz_warn(ctx, "inconsistent number of icc profile chunks in jpeg");
188
9
        if (part > parts)
189
0
        {
190
0
          fz_warn(ctx, "skipping out of range icc profile chunk in jpeg");
191
0
          continue;
192
0
        }
193
194
9
        data = marker->data + 14;
195
9
        size = marker->data_length - 14;
196
197
9
        if (!buf)
198
9
          buf = fz_new_buffer_from_copied_data(ctx, data, size);
199
0
        else
200
0
          fz_append_data(ctx, buf, data, size);
201
202
9
        part++;
203
9
        break;
204
9
      }
205
68
    }
206
207
65
    if (buf)
208
9
    {
209
9
      icc = fz_new_icc_colorspace(ctx, fz_colorspace_type(ctx, colorspace), 0, NULL, buf);
210
9
      fz_drop_colorspace(ctx, colorspace);
211
9
      colorspace = icc;
212
9
    }
213
65
  }
214
130
  fz_always(ctx)
215
65
    fz_drop_buffer(ctx, buf);
216
65
  fz_catch(ctx)
217
3
  {
218
3
    fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
219
3
    fz_report_error(ctx);
220
3
    fz_warn(ctx, "ignoring embedded ICC profile in JPEG");
221
3
  }
222
223
65
  return colorspace;
224
#else
225
  return colorspace;
226
#endif
227
819
}
228
229
/* Returns true if <x> can be represented as an integer without overflow.
230
 *
231
 * We can't use comparisons such as 'return x < INT_MAX' because INT_MAX is
232
 * not safely convertible to float - it ends up as INT_MAX+1 so the comparison
233
 * doesn't do what we want.
234
 *
235
 * Instead we do a round-trip conversion and return true if this differs by
236
 * less than 1. This relies on high adjacent float values that differ by more
237
 * than 1, actually being exact integers, so the round-trip doesn't change the
238
 * value.
239
 */
240
static int float_can_be_int(float x)
241
3
{
242
3
  return fabsf(x - (float)(int) x) < 1;
243
3
}
244
245
static uint8_t exif_orientation_to_mupdf[9] = { 0, 1, 5, 3, 7, 6, 4, 8, 2 };
246
247
static int extract_exif_resolution(jpeg_saved_marker_ptr marker,
248
  int *xres, int *yres, uint8_t *orientation)
249
819
{
250
819
  int is_big_endian, orient;
251
819
  const unsigned char *data;
252
819
  unsigned int offset, ifd_len, res_type = 0;
253
819
  float x_res = 0, y_res = 0;
254
255
819
  if (!marker || marker->marker != JPEG_APP0 + 1 || marker->data_length < 14)
256
780
    return 0;
257
39
  data = (const unsigned char *)marker->data;
258
39
  if (read_value(data, 4, 1) != 0x45786966 /* Exif */ || read_value(data + 4, 2, 1) != 0x0000)
259
3
    return 0;
260
36
  if (read_value(data + 6, 4, 1) == 0x49492A00)
261
20
    is_big_endian = 0;
262
16
  else if (read_value(data + 6, 4, 1) == 0x4D4D002A)
263
9
    is_big_endian = 1;
264
7
  else
265
7
    return 0;
266
267
29
  offset = read_value(data + 10, 4, is_big_endian) + 6;
268
29
  if (offset < 14 || offset > marker->data_length - 2)
269
1
    return 0;
270
28
  ifd_len = read_value(data + offset, 2, is_big_endian);
271
20.6k
  for (offset += 2; ifd_len > 0 && offset + 12 < marker->data_length; ifd_len--, offset += 12)
272
20.5k
  {
273
20.5k
    int tag = read_value(data + offset, 2, is_big_endian);
274
20.5k
    int type = read_value(data + offset + 2, 2, is_big_endian);
275
20.5k
    int count = read_value(data + offset + 4, 4, is_big_endian);
276
20.5k
    unsigned int value_off = read_value(data + offset + 8, 4, is_big_endian) + 6;
277
20.5k
    switch (tag)
278
20.5k
    {
279
33
    case 0x112:
280
33
      if (type == 3 && count == 1) {
281
24
        orient = read_value(data + offset + 8, 2, is_big_endian);
282
24
        if (orient >= 1 && orient <= 8 && orientation)
283
17
          *orientation = exif_orientation_to_mupdf[orient];
284
24
      }
285
33
      break;
286
28
    case 0x11A:
287
28
      if (type == 5 && value_off > offset && value_off <= marker->data_length - 8)
288
2
        x_res = 1.0f * read_value(data + value_off, 4, is_big_endian) / read_value(data + value_off + 4, 4, is_big_endian);
289
28
      break;
290
35
    case 0x11B:
291
35
      if (type == 5 && value_off > offset && value_off <= marker->data_length - 8)
292
2
        y_res = 1.0f * read_value(data + value_off, 4, is_big_endian) / read_value(data + value_off + 4, 4, is_big_endian);
293
35
      break;
294
25
    case 0x128:
295
25
      if (type == 3 && count == 1)
296
4
        res_type = read_value(data + offset + 8, 2, is_big_endian);
297
25
      break;
298
20.5k
    }
299
20.5k
  }
300
301
28
  if (x_res <= 0 || !float_can_be_int(x_res) || y_res <= 0 || !float_can_be_int(y_res))
302
27
    return 0;
303
1
  if (res_type == 2)
304
0
  {
305
0
    *xres = (int)x_res;
306
0
    *yres = (int)y_res;
307
0
  }
308
1
  else if (res_type == 3)
309
0
  {
310
0
    *xres = (int)(x_res * 254 / 100);
311
0
    *yres = (int)(y_res * 254 / 100);
312
0
  }
313
1
  else
314
1
  {
315
1
    *xres = 0;
316
1
    *yres = 0;
317
1
  }
318
1
  return 1;
319
28
}
320
321
static int extract_app13_resolution(jpeg_saved_marker_ptr marker, int *xres, int *yres)
322
818
{
323
818
  const unsigned char *data, *data_end;
324
325
818
  if (!marker || marker->marker != JPEG_APP0 + 13 || marker->data_length < 42 ||
326
818
    strcmp((const char *)marker->data, "Photoshop 3.0") != 0)
327
818
  {
328
818
    return 0;
329
818
  }
330
331
0
  data = (const unsigned char *)marker->data;
332
0
  data_end = data + marker->data_length;
333
0
  for (data += 14; data + 12 < data_end; ) {
334
0
    int data_size = -1;
335
0
    int tag = read_value(data + 4, 2, 1);
336
0
    int value_off = 11 + read_value(data + 6, 2, 1);
337
0
    if (value_off % 2 == 1)
338
0
      value_off++;
339
0
    if (read_value(data, 4, 1) == 0x3842494D /* 8BIM */ && value_off <= data_end - data)
340
0
      data_size = read_value(data + value_off - 4, 4, 1);
341
0
    if (data_size < 0 || data_size > data_end - data - value_off)
342
0
      return 0;
343
0
    if (tag == 0x3ED && data_size == 16)
344
0
    {
345
0
      *xres = read_value(data + value_off, 2, 1);
346
0
      *yres = read_value(data + value_off + 8, 2, 1);
347
0
      return 1;
348
0
    }
349
0
    if (data_size % 2 == 1)
350
0
      data_size++;
351
0
    data += value_off + data_size;
352
0
  }
353
354
0
  return 0;
355
0
}
356
357
static void invert_cmyk(unsigned char *p, int n)
358
0
{
359
0
  int i;
360
0
  for (i = 0; i < n; ++i)
361
0
    p[i] = 255 - p[i];
362
0
}
363
364
fz_pixmap *
365
fz_load_jpeg(fz_context *ctx, const unsigned char *rbuf, size_t rlen)
366
0
{
367
0
  struct jpeg_decompress_struct cinfo;
368
0
  struct jpeg_error_mgr err;
369
0
  struct jpeg_source_mgr src;
370
0
  unsigned char *row[1], *sp, *dp;
371
0
  fz_colorspace *colorspace = NULL;
372
0
  unsigned int x;
373
0
  int k;
374
0
  size_t stride;
375
0
  fz_pixmap *image = NULL;
376
377
0
  fz_var(colorspace);
378
0
  fz_var(image);
379
0
  fz_var(row);
380
381
0
  row[0] = NULL;
382
383
0
  cinfo.mem = NULL;
384
0
  cinfo.global_state = 0;
385
0
  cinfo.err = jpeg_std_error(&err);
386
0
  err.output_message = output_message;
387
0
  err.error_exit = error_exit;
388
389
0
  cinfo.client_data = NULL;
390
0
  fz_jpg_mem_init((j_common_ptr)&cinfo, ctx);
391
392
0
  fz_try(ctx)
393
0
  {
394
0
    jpeg_create_decompress(&cinfo);
395
396
0
    cinfo.src = &src;
397
0
    src.init_source = init_source;
398
0
    src.fill_input_buffer = fill_input_buffer;
399
0
    src.skip_input_data = skip_input_data;
400
0
    src.resync_to_restart = jpeg_resync_to_restart;
401
0
    src.term_source = term_source;
402
0
    src.next_input_byte = rbuf;
403
0
    src.bytes_in_buffer = rlen;
404
405
0
    jpeg_save_markers(&cinfo, JPEG_APP0+1, 0xffff);
406
0
    jpeg_save_markers(&cinfo, JPEG_APP0+13, 0xffff);
407
0
    jpeg_save_markers(&cinfo, JPEG_APP0+2, 0xffff);
408
409
0
    jpeg_read_header(&cinfo, 1);
410
411
0
    jpeg_start_decompress(&cinfo);
412
413
0
    if (cinfo.output_components == 1)
414
0
      colorspace = fz_keep_colorspace(ctx, fz_device_gray(ctx));
415
0
    else if (cinfo.output_components == 3)
416
0
      colorspace = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
417
0
    else if (cinfo.output_components == 4)
418
0
      colorspace = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
419
0
    colorspace = extract_icc_profile(ctx, cinfo.marker_list, cinfo.output_components, colorspace);
420
0
    if (!colorspace)
421
0
      fz_throw(ctx, FZ_ERROR_FORMAT, "cannot determine colorspace");
422
423
0
    image = fz_new_pixmap(ctx, colorspace, cinfo.output_width, cinfo.output_height, NULL, 0);
424
425
0
    if (extract_exif_resolution(cinfo.marker_list, &image->xres, &image->yres, NULL))
426
0
      /* XPS prefers EXIF resolution to JFIF density */;
427
0
    else if (extract_app13_resolution(cinfo.marker_list, &image->xres, &image->yres))
428
0
      /* XPS prefers APP13 resolution to JFIF density */;
429
0
    else if (cinfo.density_unit == 1)
430
0
    {
431
0
      image->xres = cinfo.X_density;
432
0
      image->yres = cinfo.Y_density;
433
0
    }
434
0
    else if (cinfo.density_unit == 2)
435
0
    {
436
0
      image->xres = cinfo.X_density * 254 / 100;
437
0
      image->yres = cinfo.Y_density * 254 / 100;
438
0
    }
439
440
0
    if (image->xres <= 0) image->xres = 96;
441
0
    if (image->yres <= 0) image->yres = 96;
442
443
0
    fz_clear_pixmap(ctx, image);
444
445
0
    row[0] = fz_malloc(ctx, (size_t)cinfo.output_components * cinfo.output_width);
446
0
    dp = image->samples;
447
0
    stride = image->stride - image->w * (size_t)image->n;
448
0
    while (cinfo.output_scanline < cinfo.output_height)
449
0
    {
450
0
      jpeg_read_scanlines(&cinfo, row, 1);
451
452
      // Invert CMYK polarity for some CMYK images (see comment in filter-dct for details).
453
0
      if (cinfo.out_color_space == JCS_CMYK && cinfo.Adobe_transform == 2)
454
0
        invert_cmyk(row[0], image->stride);
455
456
0
      sp = row[0];
457
0
      for (x = 0; x < cinfo.output_width; x++)
458
0
      {
459
0
        for (k = 0; k < cinfo.output_components; k++)
460
0
          *dp++ = *sp++;
461
0
      }
462
0
      dp += stride;
463
0
    }
464
0
  }
465
0
  fz_always(ctx)
466
0
  {
467
0
    fz_drop_colorspace(ctx, colorspace);
468
0
    fz_free(ctx, row[0]);
469
0
    row[0] = NULL;
470
471
    /* We call jpeg_abort rather than the more usual
472
     * jpeg_finish_decompress here. This has the same effect,
473
     * but doesn't spew warnings if we didn't read enough data etc.
474
     * Annoyingly jpeg_abort can throw
475
     */
476
0
    fz_try(ctx)
477
0
      jpeg_abort((j_common_ptr)&cinfo);
478
0
    fz_catch(ctx)
479
0
    {
480
      /* Ignore any errors here */
481
0
    }
482
483
0
    jpeg_destroy_decompress(&cinfo);
484
0
    fz_jpg_mem_term((j_common_ptr)&cinfo);
485
0
  }
486
0
  fz_catch(ctx)
487
0
  {
488
0
    fz_drop_pixmap(ctx, image);
489
0
    fz_rethrow(ctx);
490
0
  }
491
492
0
  return image;
493
0
}
494
495
void
496
fz_load_jpeg_info(fz_context *ctx, const unsigned char *rbuf, size_t rlen, int *xp, int *yp, int *xresp, int *yresp, fz_colorspace **cspacep, uint8_t *orientation)
497
1.01k
{
498
1.01k
  struct jpeg_decompress_struct cinfo;
499
1.01k
  struct jpeg_error_mgr err;
500
1.01k
  struct jpeg_source_mgr src;
501
1.01k
  fz_colorspace *icc = NULL;
502
503
1.01k
  *cspacep = NULL;
504
1.01k
  if (orientation)
505
1.01k
    *orientation = 0;
506
507
1.01k
  cinfo.mem = NULL;
508
1.01k
  cinfo.global_state = 0;
509
1.01k
  cinfo.err = jpeg_std_error(&err);
510
1.01k
  err.error_exit = error_exit;
511
512
1.01k
  cinfo.client_data = NULL;
513
1.01k
  fz_jpg_mem_init((j_common_ptr)&cinfo, ctx);
514
515
2.03k
  fz_try(ctx)
516
2.03k
  {
517
1.01k
    jpeg_create_decompress(&cinfo);
518
519
1.01k
    cinfo.src = &src;
520
1.01k
    src.init_source = init_source;
521
1.01k
    src.fill_input_buffer = fill_input_buffer;
522
1.01k
    src.skip_input_data = skip_input_data;
523
1.01k
    src.resync_to_restart = jpeg_resync_to_restart;
524
1.01k
    src.term_source = term_source;
525
1.01k
    src.next_input_byte = rbuf;
526
1.01k
    src.bytes_in_buffer = rlen;
527
528
1.01k
    jpeg_save_markers(&cinfo, JPEG_APP0+1, 0xffff);
529
1.01k
    jpeg_save_markers(&cinfo, JPEG_APP0+13, 0xffff);
530
1.01k
    jpeg_save_markers(&cinfo, JPEG_APP0+2, 0xffff);
531
532
1.01k
    jpeg_read_header(&cinfo, 1);
533
534
1.01k
    *xp = cinfo.image_width;
535
1.01k
    *yp = cinfo.image_height;
536
537
1.01k
    if (cinfo.num_components == 1)
538
393
      *cspacep = fz_keep_colorspace(ctx, fz_device_gray(ctx));
539
625
    else if (cinfo.num_components == 3)
540
332
      *cspacep = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
541
293
    else if (cinfo.num_components == 4)
542
94
      *cspacep = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
543
1.01k
    *cspacep = extract_icc_profile(ctx, cinfo.marker_list, cinfo.num_components, *cspacep);
544
1.01k
    if (!*cspacep)
545
0
      fz_throw(ctx, FZ_ERROR_FORMAT, "cannot determine colorspace");
546
547
1.01k
    if (extract_exif_resolution(cinfo.marker_list, xresp, yresp, orientation))
548
1
      /* XPS prefers EXIF resolution to JFIF density */;
549
1.01k
    else if (extract_app13_resolution(cinfo.marker_list, xresp, yresp))
550
0
      /* XPS prefers APP13 resolution to JFIF density */;
551
1.01k
    else if (cinfo.density_unit == 1)
552
1
    {
553
1
      *xresp = cinfo.X_density;
554
1
      *yresp = cinfo.Y_density;
555
1
    }
556
1.01k
    else if (cinfo.density_unit == 2)
557
16
    {
558
16
      *xresp = cinfo.X_density * 254 / 100;
559
16
      *yresp = cinfo.Y_density * 254 / 100;
560
16
    }
561
1.00k
    else
562
1.00k
    {
563
1.00k
      *xresp = 0;
564
1.00k
      *yresp = 0;
565
1.00k
    }
566
567
1.01k
    if (*xresp <= 0) *xresp = 96;
568
1.01k
    if (*yresp <= 0) *yresp = 96;
569
1.01k
  }
570
2.03k
  fz_always(ctx)
571
1.01k
  {
572
1.01k
    jpeg_destroy_decompress(&cinfo);
573
1.01k
    fz_jpg_mem_term((j_common_ptr)&cinfo);
574
1.01k
  }
575
1.01k
  fz_catch(ctx)
576
199
  {
577
199
    fz_drop_colorspace(ctx, icc);
578
199
    fz_rethrow(ctx);
579
199
  }
580
1.01k
}