Coverage Report

Created: 2026-10-13 07:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mupdf/source/fitz/image.c
Line
Count
Source
1
// Copyright (C) 2004-2026 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 "context-imp.h"
26
#include "image-imp.h"
27
#include "pixmap-imp.h"
28
29
#include <string.h>
30
#include <math.h>
31
#include <assert.h>
32
33
/* TODO: here or public? */
34
static int
35
fz_key_storable_needs_reaping(fz_context *ctx, const fz_key_storable *ks)
36
64.8k
{
37
64.8k
  return ks == NULL ? 0 : (ks->store_key_refs == ks->storable.refs);
38
64.8k
}
39
40
8
#define SANE_DPI 72.0f
41
6
#define INSANE_DPI 4800.0f
42
43
0
#define SCALABLE_IMAGE_DPI 96
44
45
struct fz_compressed_image
46
{
47
  fz_image super;
48
  fz_compressed_buffer *buffer;
49
};
50
51
struct fz_pixmap_image
52
{
53
  fz_image super;
54
  fz_pixmap *tile;
55
};
56
57
typedef struct
58
{
59
  int refs;
60
  fz_image *image;
61
  int l2factor;
62
  fz_irect rect;
63
} fz_image_key;
64
65
fz_image *
66
fz_keep_image(fz_context *ctx, fz_image *image)
67
3.06k
{
68
3.06k
  if (image)
69
1.48k
    return fz_keep_key_storable(ctx, &image->key_storable);
70
1.57k
  return NULL;
71
3.06k
}
72
73
fz_image *
74
fz_keep_image_store_key(fz_context *ctx, fz_image *image)
75
3.06k
{
76
3.06k
  if (image)
77
3.06k
    return fz_keep_key_storable_key(ctx, &image->key_storable);
78
0
  return NULL;
79
3.06k
}
80
81
void
82
fz_drop_image_store_key(fz_context *ctx, fz_image *image)
83
3.06k
{
84
3.06k
  if (image)
85
3.06k
    fz_drop_key_storable_key(ctx, &image->key_storable);
86
3.06k
}
87
88
static int
89
fz_make_hash_image_key(fz_context *ctx, fz_store_hash *hash, void *key_)
90
16.3k
{
91
16.3k
  fz_image_key *key = (fz_image_key *)key_;
92
16.3k
  hash->u.pir.ptr = key->image;
93
16.3k
  hash->u.pir.i = key->l2factor;
94
16.3k
  hash->u.pir.r = key->rect;
95
16.3k
  return 1;
96
16.3k
}
97
98
static void *
99
fz_keep_image_key(fz_context *ctx, void *key_)
100
3.06k
{
101
3.06k
  fz_image_key *key = (fz_image_key *)key_;
102
3.06k
  return fz_keep_imp(ctx, key, &key->refs);
103
3.06k
}
104
105
static void
106
fz_drop_image_key(fz_context *ctx, void *key_)
107
6.12k
{
108
6.12k
  fz_image_key *key = (fz_image_key *)key_;
109
6.12k
  if (fz_drop_imp(ctx, key, &key->refs))
110
3.06k
  {
111
3.06k
    fz_drop_image_store_key(ctx, key->image);
112
3.06k
    fz_free(ctx, key);
113
3.06k
  }
114
6.12k
}
115
116
static int
117
fz_cmp_image_key(fz_context *ctx, void *k0_, void *k1_)
118
0
{
119
0
  fz_image_key *k0 = (fz_image_key *)k0_;
120
0
  fz_image_key *k1 = (fz_image_key *)k1_;
121
0
  return k0->image == k1->image && k0->l2factor == k1->l2factor && k0->rect.x0 == k1->rect.x0 && k0->rect.y0 == k1->rect.y0 && k0->rect.x1 == k1->rect.x1 && k0->rect.y1 == k1->rect.y1;
122
0
}
123
124
static void
125
fz_format_image_key(fz_context *ctx, char *s, size_t n, void *key_)
126
0
{
127
0
  fz_image_key *key = (fz_image_key *)key_;
128
0
  fz_snprintf(s, n, "(image %d x %d sf=%d)", key->image->w, key->image->h, key->l2factor);
129
0
}
130
131
static int
132
fz_needs_reap_image_key(fz_context *ctx, void *key_)
133
64.8k
{
134
64.8k
  fz_image_key *key = (fz_image_key *)key_;
135
136
64.8k
  return fz_key_storable_needs_reaping(ctx, &key->image->key_storable);
137
64.8k
}
138
139
void fz_image_digest(fz_context *ctx, fz_image *img, unsigned char digest[16])
140
0
{
141
0
  if (img->get_digest)
142
0
    img->get_digest(ctx, img, digest);
143
0
  else
144
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot checksum this type of image");
145
0
}
146
147
static const fz_store_type fz_image_store_type =
148
{
149
  "fz_image",
150
  fz_make_hash_image_key,
151
  fz_keep_image_key,
152
  fz_drop_image_key,
153
  fz_cmp_image_key,
154
  fz_format_image_key,
155
  fz_needs_reap_image_key
156
};
157
158
void
159
fz_drop_image(fz_context *ctx, fz_image *image)
160
9.96k
{
161
9.96k
  if (image)
162
6.58k
    fz_drop_key_storable(ctx, &image->key_storable);
163
9.96k
}
164
165
static void
166
fz_mask_color_key(fz_context *ctx, fz_pixmap *pix, int n, int bpc, const int *colorkey_in, int indexed)
167
0
{
168
0
  unsigned char *p = pix->samples;
169
0
  int w;
170
0
  int k, t;
171
0
  int h = pix->h;
172
0
  size_t stride = pix->stride - pix->w * (size_t)pix->n;
173
0
  int colorkey[FZ_MAX_COLORS * 2];
174
0
  int scale, shift, max;
175
176
0
  if (pix->w == 0)
177
0
    return;
178
179
0
  if (indexed)
180
0
  {
181
    /* no upscaling or downshifting needed for indexed images */
182
0
    scale = 1;
183
0
    shift = 0;
184
0
  }
185
0
  else
186
0
  {
187
0
    switch (bpc)
188
0
    {
189
0
    case 1: scale = 255; shift = 0; break;
190
0
    case 2: scale = 85; shift = 0; break;
191
0
    case 4: scale = 17; shift = 0; break;
192
0
    default:
193
0
    case 8: scale = 1; shift = 0; break;
194
0
    case 16: scale = 1; shift = 8; break;
195
0
    case 24: scale = 1; shift = 16; break;
196
0
    case 32: scale = 1; shift = 24; break;
197
0
    }
198
0
  }
199
200
0
  switch (bpc)
201
0
  {
202
0
  case 1: max = 1; break;
203
0
  case 2: max = 3; break;
204
0
  case 4: max = 15; break;
205
0
  default:
206
0
  case 8: max = 0xff; break;
207
0
  case 16: max = 0xffff; break;
208
0
  case 24: max = 0xffffff; break;
209
0
  case 32: max = 0xffffffff; break;
210
0
  }
211
212
0
  for (k = 0; k < 2 * n; k++)
213
0
  {
214
0
    colorkey[k] = colorkey_in[k];
215
216
0
    if (colorkey[k] > max)
217
0
    {
218
0
      if (indexed && bpc == 1)
219
0
      {
220
0
        if (k == 0)
221
0
        {
222
0
          fz_warn(ctx, "first color key masking value out of range in 1bpc indexed image, ignoring color key masking");
223
0
          return;
224
0
        }
225
0
        fz_warn(ctx, "later color key masking value out of range in 1bpc indexed image, assumed to be 1");
226
0
        colorkey[k] = 1;
227
0
      }
228
0
      else if (bpc != 1)
229
0
      {
230
0
        fz_warn(ctx, "color key masking value out of range, masking to valid range");
231
0
        colorkey[k] &= max;
232
0
      }
233
0
    }
234
235
0
    if (colorkey[k] < 0 || colorkey[k] > max)
236
0
    {
237
0
      fz_warn(ctx, "color key masking value out of range, clamping to valid range");
238
0
      colorkey[k] = fz_clampi(colorkey[k], 0, max);
239
0
    }
240
241
0
    if (scale > 1)
242
0
    {
243
      /* scale up color key masking value so it can be compared with samples. */
244
0
      colorkey[k] *= scale;
245
0
    }
246
0
    else if (shift > 0)
247
0
    {
248
      /* shifting down color key masking value so it can be compared with samples. */
249
0
      colorkey[k] >>= shift;
250
0
    }
251
0
  }
252
253
0
  while (h--)
254
0
  {
255
0
    w = pix->w;
256
0
    do
257
0
    {
258
0
      t = 1;
259
0
      for (k = 0; k < n; k++)
260
0
        if (p[k] < colorkey[k * 2] || p[k] > colorkey[k * 2 + 1])
261
0
          t = 0;
262
0
      if (t)
263
0
        for (k = 0; k < pix->n; k++)
264
0
          p[k] = 0;
265
0
      p += pix->n;
266
0
    }
267
0
    while (--w);
268
0
    p += stride;
269
0
  }
270
0
}
271
272
static void
273
fz_unblend_masked_tile(fz_context *ctx, fz_pixmap *tile, fz_image *image, const fz_irect *isa)
274
0
{
275
0
  fz_pixmap *mask;
276
0
  unsigned char *s, *d = tile->samples;
277
0
  int n = tile->n;
278
0
  int k;
279
0
  size_t sstride, dstride = tile->stride - tile->w * (size_t)tile->n;
280
0
  int h;
281
0
  fz_irect subarea;
282
283
  /* We need at least as much of the mask as there was of the tile. */
284
0
  if (isa)
285
0
    subarea = *isa;
286
0
  else
287
0
  {
288
0
    subarea.x0 = 0;
289
0
    subarea.y0 = 0;
290
0
    subarea.x1 = tile->w;
291
0
    subarea.y1 = tile->h;
292
0
  }
293
294
0
  mask = fz_get_pixmap_from_image(ctx, image->mask, &subarea, NULL, NULL, NULL);
295
0
  s = mask->samples;
296
  /* RJW: Urgh, bit of nastiness here. fz_pixmap_from_image will either return
297
   * an exact match for the subarea we asked for, or the full image, and the
298
   * normal way to know is that the matrix will be updated. That doesn't help
299
   * us here. */
300
0
  if (image->mask->w == mask->w && image->mask->h == mask->h) {
301
0
    subarea.x0 = 0;
302
0
    subarea.y0 = 0;
303
0
  }
304
0
  if (isa)
305
0
    s += (isa->x0 - subarea.x0) * (size_t)mask->n + (isa->y0 - subarea.y0) * (size_t)mask->stride;
306
0
  sstride = mask->stride - tile->w * (size_t)mask->n;
307
0
  h = tile->h;
308
309
0
  if (tile->w != 0)
310
0
  {
311
0
    while (h--)
312
0
    {
313
0
      int w = tile->w;
314
0
      do
315
0
      {
316
0
        if (*s == 0)
317
0
          for (k = 0; k < image->n; k++)
318
0
            d[k] = image->colorkey[k];
319
0
        else
320
0
          for (k = 0; k < image->n; k++)
321
0
            d[k] = fz_clampi(image->colorkey[k] + (d[k] - image->colorkey[k]) * 255 / *s, 0, 255);
322
0
        s++;
323
0
        d += n;
324
0
      }
325
0
      while (--w);
326
0
      s += sstride;
327
0
      d += dstride;
328
0
    }
329
0
  }
330
331
0
  fz_drop_pixmap(ctx, mask);
332
0
}
333
334
static void fz_adjust_image_subarea(fz_context *ctx, fz_image *image, fz_irect *subarea, int l2factor)
335
10.2k
{
336
10.2k
  int f = 1<<l2factor;
337
10.2k
  int bpp = image->bpc * image->n;
338
10.2k
  int mask;
339
340
10.2k
  switch (bpp)
341
10.2k
  {
342
0
  case 1: mask = 8*f; break;
343
0
  case 2: mask = 4*f; break;
344
0
  case 4: mask = 2*f; break;
345
10.2k
  default: mask = (bpp & 7) == 0 ? f : 0; break;
346
10.2k
  }
347
348
10.2k
  if (mask != 0)
349
10.2k
  {
350
10.2k
    subarea->x0 &= ~(mask - 1);
351
10.2k
    subarea->x1 = (subarea->x1 + mask - 1) & ~(mask - 1);
352
10.2k
  }
353
0
  else
354
0
  {
355
    /* Awkward case - mask cannot be a power of 2. */
356
0
    mask = bpp*f;
357
0
    switch (bpp)
358
0
    {
359
0
    case 3:
360
0
    case 5:
361
0
    case 7:
362
0
    case 9:
363
0
    case 11:
364
0
    case 13:
365
0
    case 15:
366
0
    default:
367
0
      mask *= 8;
368
0
      break;
369
0
    case 6:
370
0
    case 10:
371
0
    case 14:
372
0
      mask *= 4;
373
0
      break;
374
0
    case 12:
375
0
      mask *= 2;
376
0
      break;
377
0
    }
378
0
    subarea->x0 = (subarea->x0 / mask) * mask;
379
0
    subarea->x1 = ((subarea->x1 + mask - 1) / mask) * mask;
380
0
  }
381
382
10.2k
  subarea->y0 &= ~(f - 1);
383
10.2k
  if (subarea->x1 > image->w)
384
5.59k
    subarea->x1 = image->w;
385
10.2k
  subarea->y1 = (subarea->y1 + f - 1) & ~(f - 1);
386
10.2k
  if (subarea->y1 > image->h)
387
3.28k
    subarea->y1 = image->h;
388
10.2k
}
389
390
static void fz_compute_image_key(fz_context *ctx, fz_image *image, fz_matrix *ctm,
391
  fz_image_key *key, const fz_irect *subarea, int l2factor, int *w, int *h, int *dw, int *dh)
392
13.3k
{
393
13.3k
  key->refs = 1;
394
13.3k
  key->image = image;
395
13.3k
  key->l2factor = l2factor;
396
397
13.3k
  if (subarea == NULL)
398
3.13k
  {
399
3.13k
    key->rect.x0 = 0;
400
3.13k
    key->rect.y0 = 0;
401
3.13k
    key->rect.x1 = image->w;
402
3.13k
    key->rect.y1 = image->h;
403
3.13k
  }
404
10.2k
  else
405
10.2k
  {
406
10.2k
    key->rect = *subarea;
407
10.2k
    ctx->tuning->image_decode(ctx->tuning->image_decode_arg, image->w, image->h, key->l2factor, &key->rect);
408
10.2k
    fz_adjust_image_subarea(ctx, image, &key->rect, key->l2factor);
409
10.2k
  }
410
411
  /* Based on that subarea, recalculate the extents */
412
13.3k
  if (ctm)
413
13.3k
  {
414
13.3k
    float frac_w = (float) (key->rect.x1 - key->rect.x0) / image->w;
415
13.3k
    float frac_h = (float) (key->rect.y1 - key->rect.y0) / image->h;
416
13.3k
    float a = ctm->a * frac_w;
417
13.3k
    float b = ctm->b * frac_w;
418
13.3k
    float c = ctm->c * frac_h;
419
13.3k
    float d = ctm->d * frac_h;
420
13.3k
    *w = sqrtf(a * a + b * b);
421
13.3k
    *h = sqrtf(c * c + d * d);
422
13.3k
  }
423
0
  else
424
0
  {
425
0
    *w = image->w;
426
0
    *h = image->h;
427
0
  }
428
429
  /* Return the true sizes to the caller */
430
13.3k
  if (dw)
431
13.3k
    *dw = *w;
432
13.3k
  if (dh)
433
13.3k
    *dh = *h;
434
13.3k
  if (*w > image->w)
435
0
    *w = image->w;
436
13.3k
  if (*h > image->h)
437
0
    *h = image->h;
438
439
13.3k
  if (*w == 0 || *h == 0)
440
0
    key->l2factor = 0;
441
13.3k
}
442
443
typedef struct {
444
  fz_stream *src;
445
  size_t l_skip; /* Number of bytes to skip on the left. */
446
  size_t r_skip; /* Number of bytes to skip on the right. */
447
  size_t b_skip; /* Number of bytes to skip on the bottom. */
448
  int lines; /* Number of lines left to copy. */
449
  size_t stride; /* Number of bytes to read in the image. */
450
  size_t nskip; /* Number of bytes left to skip on this line. */
451
  size_t nread; /* Number of bytes left to read on this line. */
452
} subarea_state;
453
454
static int
455
subarea_next(fz_context *ctx, fz_stream *stm, size_t len)
456
0
{
457
0
  subarea_state *state = stm->state;
458
0
  size_t n;
459
460
0
  stm->wp = stm->rp = NULL;
461
462
0
  while (state->nskip > 0)
463
0
  {
464
0
    n = fz_skip(ctx, state->src, state->nskip);
465
0
    if (n == 0)
466
0
      return EOF;
467
0
    state->nskip -= n;
468
0
  }
469
0
  if (state->lines == 0)
470
0
    return EOF;
471
0
  n = fz_available(ctx, state->src, state->nread);
472
0
  if (n > state->nread)
473
0
    n = state->nread;
474
0
  if (n == 0)
475
0
    return EOF;
476
0
  stm->rp = state->src->rp;
477
0
  stm->wp = stm->rp + n;
478
0
  stm->pos += n;
479
0
  state->src->rp = stm->wp;
480
0
  state->nread -= n;
481
0
  if (state->nread == 0)
482
0
  {
483
0
    state->lines--;
484
0
    if (state->lines == 0)
485
0
      state->nskip = state->r_skip + state->b_skip;
486
0
    else
487
0
      state->nskip = state->l_skip + state->r_skip;
488
0
    state->nread = state->stride;
489
0
  }
490
0
  return *stm->rp++;
491
0
}
492
493
static void
494
subarea_drop(fz_context *ctx, void *state)
495
0
{
496
0
  fz_free(ctx, state);
497
0
}
498
499
static fz_stream *
500
subarea_stream(fz_context *ctx, fz_stream *stm, fz_image *image, const fz_irect *subarea, int l2factor)
501
0
{
502
0
  subarea_state *state;
503
0
  int f = 1<<l2factor;
504
0
  int stream_w = (image->w + f - 1)>>l2factor;
505
0
  size_t stream_stride = (stream_w * (size_t)image->n * image->bpc + 7) / 8;
506
0
  int l_margin = subarea->x0 >> l2factor;
507
0
  int t_margin = subarea->y0 >> l2factor;
508
0
  int r_margin = (image->w + f - 1 - subarea->x1) >> l2factor;
509
0
  int b_margin = (image->h + f - 1 - subarea->y1) >> l2factor;
510
0
  size_t l_skip = (l_margin * (size_t)image->n * image->bpc)/8;
511
0
  size_t r_skip = (r_margin * (size_t)image->n * image->bpc + 7)/8;
512
0
  size_t t_skip = t_margin * stream_stride;
513
0
  size_t b_skip = b_margin * stream_stride;
514
0
  int h = (subarea->y1 - subarea->y0 + f - 1) >> l2factor;
515
0
  int w = (subarea->x1 - subarea->x0 + f - 1) >> l2factor;
516
0
  size_t stride = (w * (size_t)image->n * image->bpc + 7) / 8;
517
518
0
  state = fz_malloc_struct(ctx, subarea_state);
519
0
  state->src = stm;
520
0
  state->l_skip = l_skip;
521
0
  state->r_skip = r_skip;
522
0
  state->b_skip = b_skip;
523
0
  state->lines = h;
524
0
  state->nskip = l_skip+t_skip;
525
0
  state->stride = stride;
526
0
  state->nread = stride;
527
528
0
  return fz_new_stream(ctx, state, subarea_next, subarea_drop);
529
0
}
530
531
typedef struct
532
{
533
  fz_stream *src;
534
  int w; /* Width in source pixels. */
535
  int h; /* Height (remaining) in scanlines. */
536
  int n; /* Number of components. */
537
  int f; /* Fill level (how many scanlines we've copied in). */
538
  size_t r; /* How many samples Remain to be filled in this line. */
539
  int l2; /* The amount of subsampling we're doing. */
540
  unsigned char data[1];
541
} l2sub_state;
542
543
static void
544
subsample_drop(fz_context *ctx, void *state)
545
3.03k
{
546
3.03k
  fz_free(ctx, state);
547
3.03k
}
548
549
static int
550
subsample_next(fz_context *ctx, fz_stream *stm, size_t len)
551
217k
{
552
217k
  l2sub_state *state = (l2sub_state *)stm->state;
553
217k
  size_t fill;
554
555
217k
  stm->rp = stm->wp = &state->data[0];
556
217k
  if (state->h == 0)
557
0
    return EOF;
558
559
  /* Copy in data */
560
217k
  do
561
437k
  {
562
437k
    if (state->r == 0)
563
437k
      state->r = state->w * (size_t)state->n;
564
565
888k
    while (state->r > 0)
566
450k
    {
567
450k
      size_t a;
568
450k
      a = fz_available(ctx, state->src, state->r);
569
450k
      if (a == 0)
570
11
        return EOF;
571
450k
      if (a > state->r)
572
434k
        a = state->r;
573
450k
      memcpy(&state->data[state->w * (size_t)state->n * (state->f+1) - state->r],
574
450k
        state->src->rp, a);
575
450k
      state->src->rp += a;
576
450k
      state->r -= a;
577
450k
    }
578
437k
    state->f++;
579
437k
    state->h--;
580
437k
  }
581
437k
  while (state->h > 0 && state->f != (1<<state->l2));
582
583
  /* Perform the subsample */
584
217k
  fz_subsample_pixblock(state->data, state->w, state->f, state->n, state->l2, state->w * (size_t)state->n);
585
217k
  state->f = 0;
586
587
  /* Update data pointers. */
588
217k
  fill = ((state->w + (1<<state->l2) - 1)>>state->l2) * (size_t)state->n;
589
217k
  stm->pos += fill;
590
217k
  stm->rp = &state->data[0];
591
217k
  stm->wp = &state->data[fill];
592
593
217k
  return *stm->rp++;
594
217k
}
595
596
static fz_stream *
597
subsample_stream(fz_context *ctx, fz_stream *src, int w, int h, int n, int l2extra)
598
3.03k
{
599
3.03k
  int stride;
600
3.03k
  l2sub_state *state;
601
602
3.03k
  if (fz_ckd_mul_int(&stride, w, n << l2extra))
603
0
    fz_throw(ctx, FZ_ERROR_LIMIT, "integer overflow in image");
604
605
3.03k
  state = fz_malloc(ctx, sizeof(l2sub_state) + stride);
606
3.03k
  state->src = src;
607
3.03k
  state->w = w;
608
3.03k
  state->h = h;
609
3.03k
  state->n = n;
610
3.03k
  state->f = 0;
611
3.03k
  state->r = 0;
612
3.03k
  state->l2 = l2extra;
613
614
3.03k
  return fz_new_stream(ctx, state, subsample_next, subsample_drop);
615
3.03k
}
616
617
/* l2factor is the amount of subsampling that the decoder is going to be
618
 * doing for us already. (So for JPEG 0,1,2,3 corresponding to 1, 2, 4,
619
 * 8. For other formats, probably 0.). l2extra is the additional amount
620
 * of subsampling we should perform here. */
621
fz_pixmap *
622
fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_compressed_image *cimg, fz_irect *subarea, int indexed, int l2factor, int *l2extra)
623
3.06k
{
624
3.06k
  fz_image *image = &cimg->super;
625
3.06k
  fz_pixmap *tile = NULL;
626
3.06k
  size_t stride, len, i;
627
3.06k
  unsigned char *samples = NULL;
628
3.06k
  int f = 1<<l2factor;
629
3.06k
  int w = image->w;
630
3.06k
  int h = image->h;
631
3.06k
  int matte = image->use_colorkey && image->mask;
632
3.06k
  fz_stream *read_stream = stm;
633
3.06k
  fz_stream *sstream = NULL;
634
3.06k
  fz_stream *l2stream = NULL;
635
3.06k
  fz_stream *unpstream = NULL;
636
637
3.06k
  if (matte)
638
0
  {
639
    /* Can't do l2factor decoding */
640
0
    if (image->w != image->mask->w || image->h != image->mask->h)
641
0
    {
642
0
      fz_warn(ctx, "mask must be of same size as image for /Matte");
643
0
      matte = 0;
644
0
    }
645
0
    assert(l2factor == 0);
646
0
  }
647
3.06k
  if (subarea)
648
3.06k
  {
649
3.06k
    if (subarea->x0 == 0 && subarea->x1 == image->w &&
650
3.06k
      subarea->y0 == 0 && subarea->y1 == image->h)
651
3.06k
      subarea = NULL;
652
0
    else
653
0
    {
654
0
      fz_adjust_image_subarea(ctx, image, subarea, l2factor);
655
0
      w = (subarea->x1 - subarea->x0);
656
0
      h = (subarea->y1 - subarea->y0);
657
0
    }
658
3.06k
  }
659
3.06k
  w = (w + f - 1) >> l2factor;
660
3.06k
  h = (h + f - 1) >> l2factor;
661
662
3.06k
  fz_var(tile);
663
3.06k
  fz_var(samples);
664
3.06k
  fz_var(sstream);
665
3.06k
  fz_var(unpstream);
666
3.06k
  fz_var(l2stream);
667
668
6.12k
  fz_try(ctx)
669
6.12k
  {
670
3.06k
    int alpha = (image->colorspace == NULL);
671
3.06k
    if (image->use_colorkey)
672
0
      alpha = 1;
673
674
3.06k
    if (subarea)
675
0
      read_stream = sstream = subarea_stream(ctx, stm, image, subarea, l2factor);
676
3.06k
    if (image->bpc != 8 || image->use_colorkey)
677
0
      read_stream = unpstream = fz_unpack_stream(ctx, read_stream, image->bpc, w, h, image->n, indexed, image->use_colorkey, 0);
678
3.06k
    if (l2extra && *l2extra && !indexed)
679
3.03k
    {
680
3.03k
      read_stream = l2stream = subsample_stream(ctx, read_stream, w, h, image->n + image->use_colorkey, *l2extra);
681
3.03k
      w = (w + (1<<*l2extra) - 1)>>*l2extra;
682
3.03k
      h = (h + (1<<*l2extra) - 1)>>*l2extra;
683
3.03k
      *l2extra = 0;
684
3.03k
    }
685
686
3.06k
    tile = fz_new_pixmap(ctx, image->colorspace, w, h, NULL, alpha);
687
3.06k
    if (image->interpolate & FZ_PIXMAP_FLAG_INTERPOLATE)
688
2.79k
      tile->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
689
263
    else
690
263
      tile->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
691
692
3.06k
    samples = tile->samples;
693
3.06k
    stride = tile->stride;
694
695
3.06k
    len = fz_read(ctx, read_stream, samples, h * stride);
696
697
    /* Pad truncated images */
698
3.06k
    if (len < stride * h)
699
11
    {
700
11
      fz_warn(ctx, "padding truncated image");
701
11
      memset(samples + len, 0, stride * h - len);
702
11
    }
703
704
    /* Invert 1-bit image masks */
705
3.06k
    if (image->imagemask)
706
0
    {
707
      /* 0=opaque and 1=transparent so we need to invert */
708
0
      unsigned char *p = samples;
709
0
      len = h * stride;
710
0
      for (i = 0; i < len; i++)
711
0
        p[i] = ~p[i];
712
0
    }
713
714
    /* color keyed transparency */
715
3.06k
    if (image->use_colorkey && !image->mask)
716
0
      fz_mask_color_key(ctx, tile, image->n, image->bpc, image->colorkey, indexed);
717
718
3.06k
    if (indexed)
719
0
    {
720
0
      fz_pixmap *conv;
721
0
      fz_decode_indexed_tile(ctx, tile, image->decode, (1 << image->bpc) - 1);
722
0
      conv = fz_convert_indexed_pixmap_to_base(ctx, tile);
723
0
      fz_drop_pixmap(ctx, tile);
724
0
      tile = conv;
725
0
    }
726
3.06k
    else if (image->use_decode)
727
6
    {
728
6
      fz_decode_tile(ctx, tile, image->decode);
729
6
    }
730
731
    /* pre-blended matte color */
732
3.06k
    if (matte)
733
0
      fz_unblend_masked_tile(ctx, tile, image, subarea);
734
3.06k
  }
735
6.12k
  fz_always(ctx)
736
3.06k
  {
737
3.06k
    fz_drop_stream(ctx, sstream);
738
3.06k
    fz_drop_stream(ctx, unpstream);
739
3.06k
    fz_drop_stream(ctx, l2stream);
740
3.06k
  }
741
3.06k
  fz_catch(ctx)
742
0
  {
743
0
    fz_drop_pixmap(ctx, tile);
744
0
    fz_rethrow(ctx);
745
0
  }
746
747
3.06k
  return tile;
748
3.06k
}
749
750
void
751
fz_drop_image_base(fz_context *ctx, fz_image *image)
752
3.06k
{
753
3.06k
  fz_drop_colorspace(ctx, image->colorspace);
754
3.06k
  fz_drop_image(ctx, image->mask);
755
3.06k
  fz_free(ctx, image);
756
3.06k
}
757
758
void
759
fz_drop_image_imp(fz_context *ctx, fz_storable *image_)
760
3.06k
{
761
3.06k
  fz_image *image = (fz_image *)image_;
762
763
3.06k
  image->drop_image(ctx, image);
764
3.06k
  fz_drop_image_base(ctx, image);
765
3.06k
}
766
767
static void
768
drop_compressed_image(fz_context *ctx, fz_image *image_)
769
3.06k
{
770
3.06k
  fz_compressed_image *image = (fz_compressed_image *)image_;
771
772
3.06k
  fz_drop_compressed_buffer(ctx, image->buffer);
773
3.06k
}
774
775
static void
776
drop_pixmap_image(fz_context *ctx, fz_image *image_)
777
0
{
778
0
  fz_pixmap_image *image = (fz_pixmap_image *)image_;
779
780
0
  fz_drop_pixmap(ctx, image->tile);
781
0
}
782
783
int
784
fz_is_lossy_image(fz_context *ctx, fz_image *image)
785
0
{
786
0
  fz_compressed_buffer *cbuf = fz_compressed_image_buffer(ctx, image);
787
0
  if (cbuf)
788
0
  {
789
0
    switch (cbuf->params.type)
790
0
    {
791
0
    case FZ_IMAGE_JPEG:
792
0
    case FZ_IMAGE_JPX:
793
0
    case FZ_IMAGE_JXR:
794
0
      return 1;
795
0
    }
796
0
  }
797
0
  return 0;
798
0
}
799
800
static fz_pixmap *
801
compressed_image_get_pixmap(fz_context *ctx, fz_image *image_, fz_irect *subarea, int w, int h, int *l2factor)
802
3.06k
{
803
3.06k
  fz_compressed_image *image = (fz_compressed_image *)image_;
804
3.06k
  int native_l2factor;
805
3.06k
  fz_stream *stm;
806
3.06k
  int indexed;
807
3.06k
  fz_pixmap *tile;
808
3.06k
  int can_sub = 0;
809
3.06k
  int local_l2factor;
810
811
  /* If we are using matte, then the decode code requires both image and tile sizes
812
   * to match. The simplest way to ensure this is to do no native l2factor decoding.
813
   */
814
3.06k
  if (image->super.use_colorkey && image->super.mask)
815
0
  {
816
0
    local_l2factor = 0;
817
0
    l2factor = &local_l2factor;
818
0
  }
819
820
  /* We need to make a new one. */
821
  /* First check for ones that we can't decode using streams */
822
3.06k
  switch (image->buffer->params.type)
823
3.06k
  {
824
0
  case FZ_IMAGE_PNG:
825
0
    tile = fz_load_png(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
826
0
    break;
827
0
  case FZ_IMAGE_GIF:
828
0
    tile = fz_load_gif(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
829
0
    break;
830
0
  case FZ_IMAGE_BMP:
831
0
    tile = fz_load_bmp(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
832
0
    break;
833
0
  case FZ_IMAGE_TIFF:
834
0
    tile = fz_load_tiff(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
835
0
    break;
836
0
  case FZ_IMAGE_PNM:
837
0
    tile = fz_load_pnm(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
838
0
    break;
839
0
  case FZ_IMAGE_JXR:
840
0
    tile = fz_load_jxr(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
841
0
    break;
842
4
  case FZ_IMAGE_JPX:
843
4
    tile = fz_load_jpx(ctx, image->buffer->buffer->data, image->buffer->buffer->len, image->super.colorspace);
844
4
    if (image->super.use_colorkey)
845
0
    {
846
0
      size_t len;
847
0
      fz_pixmap *keyed = NULL;
848
0
      fz_stream *sample_stream = NULL;
849
0
      fz_stream *unpstream = NULL;
850
851
0
      fz_var(keyed);
852
0
      fz_var(sample_stream);
853
0
      fz_var(unpstream);
854
855
0
      fz_try(ctx)
856
0
      {
857
0
        indexed = fz_colorspace_is_indexed(ctx, image->super.colorspace);
858
0
        keyed = fz_new_pixmap(ctx, tile->colorspace, tile->w, tile->h, NULL, 1);
859
0
        sample_stream = fz_open_memory(ctx, tile->samples, tile->stride * tile->h);
860
0
        unpstream = fz_unpack_stream(ctx, sample_stream, 8, tile->w, tile->h, tile->n, indexed, 1, 0);
861
862
0
        len = fz_read(ctx, unpstream, keyed->samples, keyed->stride * keyed->h);
863
0
        assert(len == (size_t) keyed->stride * keyed->h);
864
0
        (void) len; /* Silence warning in release builds */
865
866
0
        fz_mask_color_key(ctx, keyed, tile->n, 8, image->super.colorkey, indexed);
867
0
      }
868
0
      fz_always(ctx)
869
0
      {
870
0
        fz_drop_stream(ctx, unpstream);
871
0
        fz_drop_stream(ctx, sample_stream);
872
0
      }
873
0
      fz_catch(ctx)
874
0
      {
875
0
        fz_drop_pixmap(ctx, keyed);
876
0
        fz_rethrow(ctx);
877
0
      }
878
879
0
      fz_drop_pixmap(ctx, tile);
880
0
      tile = keyed;
881
0
    }
882
4
    if (image->super.use_decode &&
883
0
      !fz_colorspace_is_indexed(ctx, image->super.colorspace) &&
884
0
      !fz_colorspace_is_lab(ctx, image->super.colorspace)
885
4
    )
886
0
      fz_decode_tile(ctx, tile, image->super.decode);
887
4
    break;
888
0
  case FZ_IMAGE_PSD:
889
0
    tile = fz_load_psd(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
890
0
    break;
891
24
  case FZ_IMAGE_JPEG:
892
    /* Scan JPEG stream and patch missing height values in header */
893
24
    {
894
24
      unsigned char *s = image->buffer->buffer->data;
895
24
      unsigned char *e = s + image->buffer->buffer->len;
896
24
      unsigned char *d;
897
212
      for (d = s + 2; s < d && d + 9 < e && d[0] == 0xFF; d += (d[2] << 8 | d[3]) + 2)
898
188
      {
899
188
        if (d[1] < 0xC0 || (0xC3 < d[1] && d[1] < 0xC9) || 0xCB < d[1])
900
164
          continue;
901
24
        if ((d[5] == 0 && d[6] == 0) || ((d[5] << 8) | d[6]) > image->super.h)
902
0
        {
903
0
          d[5] = (image->super.h >> 8) & 0xFF;
904
0
          d[6] = image->super.h & 0xFF;
905
0
        }
906
24
      }
907
24
    }
908
    /* fall through */
909
910
3.06k
  default:
911
3.06k
    native_l2factor = l2factor ? *l2factor : 0;
912
3.06k
    stm = fz_open_image_decomp_stream_from_buffer(ctx, image->buffer, l2factor);
913
6.12k
    fz_try(ctx)
914
6.12k
    {
915
3.06k
      if (l2factor)
916
3.06k
        native_l2factor -= *l2factor;
917
3.06k
      indexed = fz_colorspace_is_indexed(ctx, image->super.colorspace);
918
3.06k
      can_sub = 1;
919
3.06k
      tile = fz_decomp_image_from_stream(ctx, stm, image, subarea, indexed, native_l2factor, l2factor);
920
3.06k
    }
921
6.12k
    fz_always(ctx)
922
3.06k
      fz_drop_stream(ctx, stm);
923
3.06k
    fz_catch(ctx)
924
0
      fz_rethrow(ctx);
925
926
3.06k
    break;
927
3.06k
  }
928
929
3.06k
  if (can_sub == 0 && subarea != NULL)
930
1
  {
931
1
    subarea->x0 = 0;
932
1
    subarea->y0 = 0;
933
1
    subarea->x1 = image->super.w;
934
1
    subarea->y1 = image->super.h;
935
1
  }
936
937
3.06k
  return tile;
938
3.06k
}
939
940
static fz_pixmap *
941
pixmap_image_get_pixmap(fz_context *ctx, fz_image *image_, fz_irect *subarea, int w, int h, int *l2factor)
942
0
{
943
0
  fz_pixmap_image *image = (fz_pixmap_image *)image_;
944
945
  /* 'Simple' images created direct from pixmaps will have no buffer
946
   * of compressed data. We cannot do any better than just returning
947
   * a pointer to the original 'tile'.
948
   */
949
0
  return fz_keep_pixmap(ctx, image->tile); /* That's all we can give you! */
950
0
}
951
952
static void
953
update_ctm_for_subarea(fz_matrix *ctm, const fz_irect *subarea, int w, int h)
954
7.13k
{
955
7.13k
  fz_matrix m;
956
957
7.13k
  if (ctm == NULL || (subarea->x0 == 0 && subarea->y0 == 0 && subarea->x1 == w && subarea->y1 == h))
958
7.13k
    return;
959
960
0
  m.a = (float) (subarea->x1 - subarea->x0) / w;
961
0
  m.b = 0;
962
0
  m.c = 0;
963
0
  m.d = (float) (subarea->y1 - subarea->y0) / h;
964
0
  m.e = (float) subarea->x0 / w;
965
0
  m.f = (float) subarea->y0 / h;
966
0
  *ctm = fz_concat(m, *ctm);
967
0
}
968
969
void fz_default_image_decode(void *arg, int w, int h, int l2factor, fz_irect *subarea)
970
10.2k
{
971
10.2k
  (void)arg;
972
973
10.2k
  if ((subarea->x1-subarea->x0)*(subarea->y1-subarea->y0) >= (w*h/10)*9)
974
10.1k
  {
975
    /* Either no subarea specified, or a subarea 90% or more of the
976
     * whole area specified. Use the whole image. */
977
10.1k
    subarea->x0 = 0;
978
10.1k
    subarea->y0 = 0;
979
10.1k
    subarea->x1 = w;
980
10.1k
    subarea->y1 = h;
981
10.1k
  }
982
72
  else
983
72
  {
984
    /* Clip to the edges if they are within 1% */
985
72
    int w_1pc = w / 100;
986
72
    int h_1pc = h / 100;
987
72
    if (subarea->x0 <= w_1pc)
988
72
      subarea->x0 = 0;
989
72
    if (subarea->y0 <= h_1pc)
990
72
      subarea->y0 = 0;
991
72
    if (subarea->x1 >= w - w_1pc)
992
0
      subarea->x1 = w;
993
72
    if (subarea->y1 >= h - h_1pc)
994
72
      subarea->y1 = h;
995
72
  }
996
10.2k
}
997
998
static fz_pixmap *
999
fz_find_image_tile(fz_context *ctx, fz_image *image, fz_image_key *key, fz_matrix *ctm)
1000
10.2k
{
1001
10.2k
  fz_pixmap *tile;
1002
10.2k
  do
1003
10.2k
  {
1004
10.2k
    tile = fz_find_item(ctx, fz_drop_pixmap_imp, key, &fz_image_store_type);
1005
10.2k
    if (tile)
1006
4.07k
    {
1007
4.07k
      update_ctm_for_subarea(ctm, &key->rect, image->w, image->h);
1008
4.07k
      return tile;
1009
4.07k
    }
1010
6.20k
    if (ctx->tuning->image_rendering != FZ_IMAGE_RENDERING_SPEED)
1011
6.20k
      break;
1012
0
    key->l2factor--;
1013
0
  }
1014
10.2k
  while (key->l2factor >= 0);
1015
6.20k
  return NULL;
1016
10.2k
}
1017
1018
fz_pixmap *
1019
fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, const fz_irect *subarea, fz_matrix *ctm, int *dw, int *dh)
1020
7.13k
{
1021
7.13k
  fz_pixmap *tile = NULL;
1022
7.13k
  int l2factor, l2factor_remaining;
1023
7.13k
  fz_image_key key;
1024
7.13k
  fz_image_key *keyp = NULL;
1025
7.13k
  int w;
1026
7.13k
  int h;
1027
1028
7.13k
  fz_var(keyp);
1029
7.13k
  fz_var(tile);
1030
1031
7.13k
  if (!image)
1032
0
    return NULL;
1033
1034
  /* Figure out the extent. */
1035
7.13k
  if (ctm)
1036
7.13k
  {
1037
7.13k
    w = sqrtf(ctm->a * ctm->a + ctm->b * ctm->b);
1038
7.13k
    h = sqrtf(ctm->c * ctm->c + ctm->d * ctm->d);
1039
7.13k
  }
1040
0
  else
1041
0
  {
1042
0
    w = image->w;
1043
0
    h = image->h;
1044
0
  }
1045
1046
7.13k
  if (image->scalable)
1047
0
  {
1048
    /* If the image is scalable, we always want to re-render and never cache. */
1049
0
    fz_irect subarea_copy;
1050
0
    if (subarea)
1051
0
      subarea_copy = *subarea;
1052
0
    l2factor_remaining = 0;
1053
0
    if (dw) *dw = w;
1054
0
    if (dh) *dh = h;
1055
0
    return image->get_pixmap(ctx, image, subarea ? &subarea_copy : NULL, image->w, image->h, &l2factor_remaining);
1056
0
  }
1057
1058
  /* Clamp requested image size, since we never want to magnify images here. */
1059
7.13k
  if (w > image->w)
1060
0
    w = image->w;
1061
7.13k
  if (h > image->h)
1062
0
    h = image->h;
1063
1064
7.13k
  if (image->decoded)
1065
0
  {
1066
    /* If the image is already decoded, then we can't offer a subarea,
1067
     * or l2factor, and we don't want to cache. */
1068
0
    l2factor_remaining = 0;
1069
0
    if (dw) *dw = w;
1070
0
    if (dh) *dh = h;
1071
0
    return image->get_pixmap(ctx, image, NULL, image->w, image->h, &l2factor_remaining);
1072
0
  }
1073
1074
  /* What is our ideal factor? We search for the largest factor where
1075
   * we can subdivide and stay larger than the required size. We add
1076
   * a fudge factor of +2 here to allow for the possibility of
1077
   * expansion due to grid fitting. */
1078
7.13k
  l2factor = 0;
1079
7.13k
  if (ctx->tuning->image_rendering != FZ_IMAGE_RENDERING_QUALITY && w > 0 && h > 0)
1080
7.13k
  {
1081
22.5k
    while (image->w>>(l2factor+1) >= w+2 && image->h>>(l2factor+1) >= h+2 && l2factor < 6)
1082
15.3k
      l2factor++;
1083
7.13k
  }
1084
1085
  /* First, look through the store for existing tiles */
1086
7.13k
  if (subarea)
1087
7.13k
  {
1088
7.13k
    fz_compute_image_key(ctx, image, ctm, &key, subarea, l2factor, &w, &h, dw, dh);
1089
7.13k
    tile = fz_find_image_tile(ctx, image, &key, ctm);
1090
7.13k
    if (tile)
1091
4.00k
      return tile;
1092
7.13k
  }
1093
1094
  /* No subarea given, or no tile for subarea found; try entire image */
1095
3.13k
  fz_compute_image_key(ctx, image, ctm, &key, NULL, l2factor, &w, &h, dw, dh);
1096
3.13k
  tile = fz_find_image_tile(ctx, image, &key, ctm);
1097
3.13k
  if (tile)
1098
72
    return tile;
1099
1100
  /* Neither subarea nor full image tile found; prepare the subarea key again */
1101
3.06k
  if (subarea)
1102
3.06k
    fz_compute_image_key(ctx, image, ctm, &key, subarea, l2factor, &w, &h, dw, dh);
1103
1104
  /* We'll have to decode the image; request the correct amount of downscaling. */
1105
3.06k
  l2factor_remaining = l2factor;
1106
3.06k
  tile = image->get_pixmap(ctx, image, &key.rect, w, h, &l2factor_remaining);
1107
1108
  /* Update the ctm to allow for subareas. */
1109
3.06k
  update_ctm_for_subarea(ctm, &key.rect, image->w, image->h);
1110
1111
  /* l2factor_remaining is updated to the amount of subscaling left to do */
1112
3.06k
  assert(l2factor_remaining >= 0 && l2factor_remaining <= 6);
1113
3.06k
  if (l2factor_remaining)
1114
0
  {
1115
0
    fz_try(ctx)
1116
0
      fz_subsample_pixmap(ctx, tile, l2factor_remaining);
1117
0
    fz_catch(ctx)
1118
0
    {
1119
0
      fz_drop_pixmap(ctx, tile);
1120
0
      fz_rethrow(ctx);
1121
0
    }
1122
0
  }
1123
1124
6.12k
  fz_try(ctx)
1125
6.12k
  {
1126
3.06k
    fz_pixmap *existing_tile;
1127
1128
    /* Now we try to cache the pixmap. Any failure here will just result
1129
     * in us not caching. */
1130
3.06k
    keyp = fz_malloc_struct(ctx, fz_image_key);
1131
3.06k
    keyp->refs = 1;
1132
3.06k
    keyp->image = fz_keep_image_store_key(ctx, image);
1133
3.06k
    keyp->l2factor = l2factor;
1134
3.06k
    keyp->rect = key.rect;
1135
1136
3.06k
    existing_tile = fz_store_item(ctx, keyp, tile, fz_pixmap_size(ctx, tile), &fz_image_store_type);
1137
3.06k
    if (existing_tile)
1138
0
    {
1139
      /* We already have a tile. This must have been produced by a
1140
       * racing thread. We'll throw away ours and use that one. */
1141
0
      fz_drop_pixmap(ctx, tile);
1142
0
      tile = existing_tile;
1143
0
    }
1144
3.06k
  }
1145
6.12k
  fz_always(ctx)
1146
3.06k
  {
1147
3.06k
    fz_drop_image_key(ctx, keyp);
1148
3.06k
  }
1149
3.06k
  fz_catch(ctx)
1150
0
  {
1151
    /* Do nothing */
1152
0
    if (fz_caught(ctx) == FZ_ERROR_SYSTEM)
1153
0
      fz_drop_pixmap(ctx, tile);
1154
0
    fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
1155
0
    fz_report_error(ctx);
1156
0
  }
1157
1158
3.06k
  return tile;
1159
3.06k
}
1160
1161
fz_pixmap *
1162
fz_get_pixmap_mask_from_image(fz_context *ctx, fz_image *image, const fz_irect *subarea, fz_matrix *ctm, int *dw, int *dh, int in_smask)
1163
3.52k
{
1164
3.52k
  fz_pixmap *pix1, *pix2;
1165
1166
3.52k
  pix1 = fz_get_pixmap_from_image(ctx, image, subarea, ctm, dw, dh);
1167
3.52k
  if (pix1->n == 1 && pix1->alpha)
1168
3.52k
    return pix1;
1169
1170
0
  if (pix1->n == 1)
1171
0
  {
1172
0
    fz_warn(ctx, "convert gray to alpha for image mask");
1173
0
    fz_try(ctx)
1174
0
      pix2 = fz_alpha_from_gray(ctx, pix1);
1175
0
    fz_always(ctx)
1176
0
      fz_drop_pixmap(ctx, pix1);
1177
0
    fz_catch(ctx)
1178
0
      fz_rethrow(ctx);
1179
0
    return pix2;
1180
0
  }
1181
0
  else if (pix1->n == 3)
1182
0
  {
1183
0
    fz_warn(ctx, "convert rgb to alpha for image mask");
1184
0
    fz_try(ctx)
1185
0
      pix2 = fz_alpha_from_rgb(ctx, pix1);
1186
0
    fz_always(ctx)
1187
0
      fz_drop_pixmap(ctx, pix1);
1188
0
    fz_catch(ctx)
1189
0
      fz_rethrow(ctx);
1190
0
    return pix2;
1191
0
  }
1192
0
  else
1193
0
  {
1194
0
    fz_color_params cp = fz_default_color_params;
1195
1196
0
    if (in_smask)
1197
0
      cp.ri |= FZ_RI_IN_SOFTMASK;
1198
1199
0
    fz_warn(ctx, "strange colorspace for image mask (%s)", pix1->colorspace->name);
1200
0
    fz_try(ctx)
1201
0
      pix2 = fz_convert_pixmap(ctx, pix1, fz_device_gray(ctx), NULL, NULL, cp, 0);
1202
0
    fz_always(ctx)
1203
0
      fz_drop_pixmap(ctx, pix1);
1204
0
    fz_catch(ctx)
1205
0
      fz_rethrow(ctx);
1206
0
    fz_drop_colorspace(ctx, pix2->colorspace);
1207
0
    pix2->colorspace = NULL;
1208
0
    pix2->alpha = 1;
1209
0
    return pix2;
1210
0
  }
1211
0
}
1212
1213
fz_pixmap *
1214
fz_get_unscaled_pixmap_from_image(fz_context *ctx, fz_image *image)
1215
0
{
1216
0
  return fz_get_pixmap_from_image(ctx, image, NULL /*subarea*/, NULL /*ctm*/, NULL /*dw*/, NULL /*dh*/);
1217
0
}
1218
1219
static size_t
1220
pixmap_image_get_size(fz_context *ctx, fz_image *image)
1221
0
{
1222
0
  fz_pixmap_image *im = (fz_pixmap_image *)image;
1223
1224
0
  if (image == NULL)
1225
0
    return 0;
1226
1227
0
  return sizeof(fz_pixmap_image) + fz_pixmap_size(ctx, im->tile);
1228
0
}
1229
1230
static void
1231
pixmap_image_get_digest(fz_context *ctx, fz_image *image, unsigned char digest[16])
1232
0
{
1233
0
  fz_pixmap_image *im = (fz_pixmap_image *)image;
1234
0
  fz_md5_pixmap(ctx, im->tile, digest);
1235
0
}
1236
1237
size_t fz_image_size(fz_context *ctx, fz_image *im)
1238
1.57k
{
1239
1.57k
  if (im == NULL)
1240
0
    return 0;
1241
1242
1.57k
  return im->get_size(ctx, im);
1243
1.57k
}
1244
1245
fz_image *
1246
fz_new_image_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, fz_image *mask)
1247
0
{
1248
0
  fz_pixmap_image *image;
1249
1250
0
  image = fz_new_derived_image(ctx, pixmap->w, pixmap->h, 8, pixmap->colorspace,
1251
0
        pixmap->xres, pixmap->yres, 0, 0,
1252
0
        NULL, NULL, mask, fz_pixmap_image,
1253
0
        pixmap_image_get_pixmap,
1254
0
        pixmap_image_get_size,
1255
0
        pixmap_image_get_digest,
1256
0
        drop_pixmap_image);
1257
0
  image->tile = fz_keep_pixmap(ctx, pixmap);
1258
0
  image->super.decoded = 1;
1259
1260
0
  return &image->super;
1261
0
}
1262
1263
fz_image *
1264
fz_new_image_of_size(fz_context *ctx, int w, int h, int bpc, fz_colorspace *colorspace,
1265
    int xres, int yres, int interpolate, int imagemask, const float *decode,
1266
    const int *colorkey, fz_image *mask, size_t size,
1267
    fz_image_get_pixmap_fn *get_pixmap,
1268
    fz_image_get_size_fn *get_size,
1269
    fz_image_get_digest_fn *get_digest,
1270
    fz_drop_image_fn *drop)
1271
3.06k
{
1272
3.06k
  fz_image *image;
1273
3.06k
  int i;
1274
1275
3.06k
  assert(mask == NULL || mask->mask == NULL);
1276
3.06k
  assert(size >= sizeof(fz_image));
1277
1278
3.06k
  image = Memento_label(fz_calloc(ctx, 1, size), "fz_image");
1279
3.06k
  FZ_INIT_KEY_STORABLE(image, 1, fz_drop_image_imp);
1280
3.06k
  image->drop_image = drop;
1281
3.06k
  image->get_pixmap = get_pixmap;
1282
3.06k
  image->get_size = get_size;
1283
3.06k
  image->get_digest = get_digest;
1284
3.06k
  image->w = w;
1285
3.06k
  image->h = h;
1286
3.06k
  image->xres = xres;
1287
3.06k
  image->yres = yres;
1288
3.06k
  image->bpc = bpc;
1289
3.06k
  image->n = (colorspace ? fz_colorspace_n(ctx, colorspace) : 1);
1290
3.06k
  image->colorspace = fz_keep_colorspace(ctx, colorspace);
1291
3.06k
  image->interpolate = interpolate;
1292
3.06k
  image->imagemask = imagemask;
1293
3.06k
  image->intent = 0;
1294
3.06k
  image->has_intent = 0;
1295
1296
3.06k
  image->use_colorkey = (colorkey != NULL);
1297
3.06k
  if (colorkey)
1298
0
    memcpy(image->colorkey, colorkey, sizeof(int)*image->n*2);
1299
1300
3.06k
  image->use_decode = 0;
1301
3.06k
  if (decode)
1302
3.06k
  {
1303
3.06k
    memcpy(image->decode, decode, sizeof(float)*image->n*2);
1304
3.06k
  }
1305
4
  else
1306
4
  {
1307
4
    float maxval = fz_colorspace_is_indexed(ctx, colorspace) ? (1 << bpc) - 1 : 1;
1308
132
    for (i = 0; i < FZ_MAX_COLORS; i++)
1309
128
    {
1310
128
      image->decode[2*i] = 0;
1311
128
      image->decode[2*i+1] = maxval;
1312
128
    }
1313
4
  }
1314
1315
  /* ICC spaces have the default decode arrays pickled into them.
1316
   * For most spaces this is fine, because [ 0 1 0 1 0 1 ] is
1317
   * idempotent. For Lab, however, we need to adjust it. */
1318
3.06k
  if (fz_colorspace_is_lab_icc(ctx, colorspace))
1319
0
  {
1320
    /* Undo the default decode array of [0 100 -128 127 -128 127] */
1321
0
    image->decode[0] = image->decode[0]/100.0f;
1322
0
    image->decode[1] = image->decode[1]/100.0f;
1323
0
    image->decode[2] = (image->decode[2]+128)/255.0f;
1324
0
    image->decode[3] = (image->decode[3]+128)/255.0f;
1325
0
    image->decode[4] = (image->decode[4]+128)/255.0f;
1326
0
    image->decode[5] = (image->decode[5]+128)/255.0f;
1327
0
  }
1328
9.28k
  for (i = 0; i < image->n; i++)
1329
6.22k
  {
1330
6.22k
    if (image->decode[i * 2] != 0 || image->decode[i * 2 + 1] != 1)
1331
6
      break;
1332
6.22k
  }
1333
3.06k
  if (i != image->n)
1334
6
    image->use_decode = 1;
1335
3.06k
  image->mask = fz_keep_image(ctx, mask);
1336
1337
3.06k
  return image;
1338
3.06k
}
1339
1340
static size_t
1341
compressed_image_get_size(fz_context *ctx, fz_image *image)
1342
1.57k
{
1343
1.57k
  fz_compressed_image *im = (fz_compressed_image *)image;
1344
1345
1.57k
  if (image == NULL)
1346
0
    return 0;
1347
1348
1.57k
  return sizeof(fz_pixmap_image) + (im->buffer && im->buffer->buffer ? im->buffer->buffer->cap : 0);
1349
1.57k
}
1350
1351
static void
1352
compressed_image_get_digest(fz_context *ctx, fz_image *image, unsigned char digest[16])
1353
0
{
1354
0
  fz_compressed_image *im = (fz_compressed_image *)image;
1355
0
  fz_md5_buffer(ctx, im->buffer->buffer, digest);
1356
0
}
1357
1358
fz_image *
1359
fz_new_image_from_compressed_buffer(fz_context *ctx, int w, int h,
1360
  int bpc, fz_colorspace *colorspace,
1361
  int xres, int yres, int interpolate, int imagemask, const float *decode,
1362
  const int *colorkey, fz_compressed_buffer *buffer, fz_image *mask)
1363
3.06k
{
1364
3.06k
  fz_compressed_image *image;
1365
1366
6.13k
  fz_try(ctx)
1367
6.13k
  {
1368
3.06k
    image = fz_new_derived_image(ctx, w, h, bpc,
1369
3.06k
          colorspace, xres, yres,
1370
3.06k
          interpolate, imagemask, decode,
1371
3.06k
          colorkey, mask, fz_compressed_image,
1372
3.06k
          compressed_image_get_pixmap,
1373
3.06k
          compressed_image_get_size,
1374
3.06k
          compressed_image_get_digest,
1375
3.06k
          drop_compressed_image);
1376
3.06k
    image->buffer = buffer;
1377
3.06k
  }
1378
6.13k
  fz_catch(ctx)
1379
0
  {
1380
0
    fz_drop_compressed_buffer(ctx, buffer);
1381
0
    fz_rethrow(ctx);
1382
0
  }
1383
1384
3.06k
  return &image->super;
1385
3.06k
}
1386
1387
fz_compressed_buffer *fz_compressed_image_buffer(fz_context *ctx, fz_image *image)
1388
0
{
1389
0
  if (image == NULL || image->get_pixmap != compressed_image_get_pixmap)
1390
0
    return NULL;
1391
0
  return ((fz_compressed_image *)image)->buffer;
1392
0
}
1393
1394
void fz_set_compressed_image_buffer(fz_context *ctx, fz_compressed_image *image, fz_compressed_buffer *buf)
1395
0
{
1396
0
  assert(image != NULL && image->super.get_pixmap == compressed_image_get_pixmap);
1397
0
  ((fz_compressed_image *)image)->buffer = buf; /* Note: compressed buffers are not reference counted */
1398
0
}
1399
1400
fz_pixmap *fz_pixmap_image_tile(fz_context *ctx, fz_pixmap_image *image)
1401
0
{
1402
0
  if (image == NULL || image->super.get_pixmap != pixmap_image_get_pixmap)
1403
0
    return NULL;
1404
0
  return ((fz_pixmap_image *)image)->tile;
1405
0
}
1406
1407
void fz_set_pixmap_image_tile(fz_context *ctx, fz_pixmap_image *image, fz_pixmap *pix)
1408
0
{
1409
0
  assert(image != NULL && image->super.get_pixmap == pixmap_image_get_pixmap);
1410
0
  ((fz_pixmap_image *)image)->tile = pix;
1411
0
}
1412
1413
const char *
1414
fz_image_type_name(int type)
1415
0
{
1416
0
  switch (type)
1417
0
  {
1418
0
  default:
1419
0
  case FZ_IMAGE_UNKNOWN: return "unknown";
1420
0
  case FZ_IMAGE_RAW: return "raw";
1421
0
  case FZ_IMAGE_FAX: return "fax";
1422
0
  case FZ_IMAGE_FLATE: return "flate";
1423
0
  case FZ_IMAGE_LZW: return "lzw";
1424
0
  case FZ_IMAGE_RLD: return "rld";
1425
0
  case FZ_IMAGE_BROTLI: return "brotli";
1426
0
  case FZ_IMAGE_BMP: return "bmp";
1427
0
  case FZ_IMAGE_GIF: return "gif";
1428
0
  case FZ_IMAGE_JBIG2: return "jbig2";
1429
0
  case FZ_IMAGE_JPEG: return "jpeg";
1430
0
  case FZ_IMAGE_JPX: return "jpx";
1431
0
  case FZ_IMAGE_JXR: return "jxr";
1432
0
  case FZ_IMAGE_PNG: return "png";
1433
0
  case FZ_IMAGE_PNM: return "pnm";
1434
0
  case FZ_IMAGE_TIFF: return "tiff";
1435
0
  }
1436
0
}
1437
1438
int
1439
fz_lookup_image_type(const char *type)
1440
0
{
1441
0
  if (type == NULL) return FZ_IMAGE_UNKNOWN;
1442
0
  if (!strcmp(type, "raw")) return FZ_IMAGE_RAW;
1443
0
  if (!strcmp(type, "fax")) return FZ_IMAGE_FAX;
1444
0
  if (!strcmp(type, "flate")) return FZ_IMAGE_FLATE;
1445
0
  if (!strcmp(type, "lzw")) return FZ_IMAGE_LZW;
1446
0
  if (!strcmp(type, "rld")) return FZ_IMAGE_RLD;
1447
0
  if (!strcmp(type, "brotli")) return FZ_IMAGE_BROTLI;
1448
0
  if (!strcmp(type, "bmp")) return FZ_IMAGE_BMP;
1449
0
  if (!strcmp(type, "gif")) return FZ_IMAGE_GIF;
1450
0
  if (!strcmp(type, "jbig2")) return FZ_IMAGE_JBIG2;
1451
0
  if (!strcmp(type, "jpeg")) return FZ_IMAGE_JPEG;
1452
0
  if (!strcmp(type, "jpx")) return FZ_IMAGE_JPX;
1453
0
  if (!strcmp(type, "jxr")) return FZ_IMAGE_JXR;
1454
0
  if (!strcmp(type, "png")) return FZ_IMAGE_PNG;
1455
0
  if (!strcmp(type, "pnm")) return FZ_IMAGE_PNM;
1456
0
  if (!strcmp(type, "tiff")) return FZ_IMAGE_TIFF;
1457
0
  return FZ_IMAGE_UNKNOWN;
1458
0
}
1459
1460
int
1461
fz_recognize_image_format(fz_context *ctx, unsigned char p[8])
1462
74
{
1463
74
  if (p[0] == 'P' && p[1] >= '1' && p[1] <= '7')
1464
0
    return FZ_IMAGE_PNM;
1465
74
  if (p[0] == 'P' && (p[1] == 'F' || p[1] == 'f'))
1466
0
    return FZ_IMAGE_PNM;
1467
74
  if (p[0] == 0xff && p[1] == 0x4f)
1468
0
    return FZ_IMAGE_JPX;
1469
74
  if (p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x00 && p[3] == 0x0c &&
1470
3
      p[4] == 0x6a && p[5] == 0x50 && p[6] == 0x20 && p[7] == 0x20)
1471
3
    return FZ_IMAGE_JPX;
1472
71
  if (p[0] == 0xff && p[1] == 0xd8)
1473
0
    return FZ_IMAGE_JPEG;
1474
71
  if (p[0] == 137 && p[1] == 80 && p[2] == 78 && p[3] == 71 &&
1475
0
      p[4] == 13 && p[5] == 10 && p[6] == 26 && p[7] == 10)
1476
0
    return FZ_IMAGE_PNG;
1477
71
  if (p[0] == 'I' && p[1] == 'I' && p[2] == 0xBC)
1478
0
    return FZ_IMAGE_JXR;
1479
71
  if (p[0] == 'I' && p[1] == 'I' && p[2] == 42 && p[3] == 0)
1480
0
    return FZ_IMAGE_TIFF;
1481
71
  if (p[0] == 'M' && p[1] == 'M' && p[2] == 0 && p[3] == 42)
1482
0
    return FZ_IMAGE_TIFF;
1483
71
  if (p[0] == 'G' && p[1] == 'I' && p[2] == 'F')
1484
0
    return FZ_IMAGE_GIF;
1485
71
  if (p[0] == 'B' && p[1] == 'M')
1486
0
    return FZ_IMAGE_BMP;
1487
71
  if (p[0] == 'B' && p[1] == 'A')
1488
0
    return FZ_IMAGE_BMP;
1489
71
  if (p[0] == 0x97 && p[1] == 'J' && p[2] == 'B' && p[3] == '2' &&
1490
0
    p[4] == '\r' && p[5] == '\n'  && p[6] == 0x1a && p[7] == '\n')
1491
0
    return FZ_IMAGE_JBIG2;
1492
71
  if (p[0] == '8' && p[1] == 'B' && p[2] == 'P' && p[3] == 'S')
1493
0
    return FZ_IMAGE_PSD;
1494
71
  return FZ_IMAGE_UNKNOWN;
1495
71
}
1496
1497
fz_image *
1498
fz_new_image_from_buffer(fz_context *ctx, fz_buffer *buffer)
1499
1
{
1500
1
  fz_compressed_buffer *bc;
1501
1
  int w, h, xres, yres;
1502
1
  fz_colorspace *cspace = NULL;
1503
1
  size_t len = buffer->len;
1504
1
  unsigned char *buf = buffer->data;
1505
1
  fz_image *image = NULL;
1506
1
  int type;
1507
1
  int bpc;
1508
1
  uint8_t orientation = 0;
1509
1510
1
  if (len < 8)
1511
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "unknown image file format");
1512
1513
1
  type = fz_recognize_image_format(ctx, buf);
1514
1
  bpc = 8;
1515
1
  switch (type)
1516
1
  {
1517
0
  case FZ_IMAGE_PNM:
1518
0
    fz_load_pnm_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
1519
0
    break;
1520
1
  case FZ_IMAGE_JPX:
1521
1
    fz_load_jpx_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace, NULL);
1522
1
    break;
1523
0
  case FZ_IMAGE_JPEG:
1524
0
    fz_load_jpeg_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace, &orientation);
1525
0
    break;
1526
0
  case FZ_IMAGE_PNG:
1527
0
    fz_load_png_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
1528
0
    break;
1529
0
  case FZ_IMAGE_PSD:
1530
0
    fz_load_psd_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
1531
0
    break;
1532
0
  case FZ_IMAGE_JXR:
1533
0
    fz_load_jxr_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
1534
0
    break;
1535
0
  case FZ_IMAGE_TIFF:
1536
0
    fz_load_tiff_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
1537
0
    break;
1538
0
  case FZ_IMAGE_GIF:
1539
0
    fz_load_gif_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
1540
0
    break;
1541
0
  case FZ_IMAGE_BMP:
1542
0
    fz_load_bmp_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
1543
0
    break;
1544
0
  case FZ_IMAGE_JBIG2:
1545
0
    fz_load_jbig2_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
1546
0
    bpc = 1;
1547
0
    break;
1548
0
  default:
1549
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "unknown image file format");
1550
1
  }
1551
1552
2
  fz_try(ctx)
1553
2
  {
1554
1
    bc = fz_new_compressed_buffer(ctx);
1555
1
    bc->buffer = fz_keep_buffer(ctx, buffer);
1556
1
    bc->params.type = type;
1557
1
    if (type == FZ_IMAGE_JPEG)
1558
0
    {
1559
0
      bc->params.u.jpeg.color_transform = -1;
1560
0
      bc->params.u.jpeg.invert_cmyk = 1;
1561
0
    }
1562
1
    image = fz_new_image_from_compressed_buffer(ctx, w, h, bpc, cspace, xres, yres, 0, 0, NULL, NULL, bc, NULL);
1563
1
    image->orientation = orientation;
1564
1
  }
1565
2
  fz_always(ctx)
1566
1
    fz_drop_colorspace(ctx, cspace);
1567
1
  fz_catch(ctx)
1568
0
    fz_rethrow(ctx);
1569
1570
1
  return image;
1571
1
}
1572
1573
fz_image *
1574
fz_new_jpx_image_from_buffer(fz_context *ctx, fz_buffer *buffer, fz_colorspace *defcs)
1575
3
{
1576
3
  fz_compressed_buffer *bc;
1577
3
  fz_colorspace *cs = NULL;
1578
3
  int w, h, xres, yres;
1579
3
  fz_image *img = NULL;
1580
1581
3
  fz_load_jpx_info(ctx, buffer->data, buffer->len, &w, &h, &xres, &yres, &cs, defcs);
1582
1583
6
  fz_try(ctx)
1584
6
  {
1585
3
    bc = fz_new_compressed_buffer(ctx);
1586
3
    bc->buffer = fz_keep_buffer(ctx, buffer);
1587
3
    bc->params.type = FZ_IMAGE_JPX;
1588
1589
3
    img =  fz_new_image_from_compressed_buffer(ctx, w, h, 8, cs, xres, yres, 0, 0, NULL, NULL, bc, NULL);
1590
3
  }
1591
6
  fz_always(ctx)
1592
3
    fz_drop_colorspace(ctx, cs);
1593
3
  fz_catch(ctx)
1594
0
    fz_rethrow(ctx);
1595
1596
3
  return img;
1597
3
}
1598
1599
int
1600
fz_compressed_image_type(fz_context *ctx, fz_image *image)
1601
0
{
1602
0
  fz_compressed_image *cim;
1603
1604
0
  if (image == NULL || image->drop_image != drop_compressed_image)
1605
0
    return FZ_IMAGE_UNKNOWN;
1606
1607
0
  cim = (fz_compressed_image *)image;
1608
1609
0
  return cim->buffer->params.type;
1610
0
}
1611
1612
fz_image *
1613
fz_new_image_from_file(fz_context *ctx, const char *path)
1614
0
{
1615
0
  fz_buffer *buffer;
1616
0
  fz_image *image = NULL;
1617
1618
0
  buffer = fz_read_file(ctx, path);
1619
0
  fz_try(ctx)
1620
0
    image = fz_new_image_from_buffer(ctx, buffer);
1621
0
  fz_always(ctx)
1622
0
    fz_drop_buffer(ctx, buffer);
1623
0
  fz_catch(ctx)
1624
0
    fz_rethrow(ctx);
1625
1626
0
  return image;
1627
0
}
1628
1629
void
1630
fz_image_resolution(fz_image *image, int *xres, int *yres)
1631
2
{
1632
2
  *xres = image->xres;
1633
2
  *yres = image->yres;
1634
2
  if (*xres < 0 || *yres < 0 || (*xres == 0 && *yres == 0))
1635
0
  {
1636
    /* If neither xres or yres is sane, pick a sane value */
1637
0
    *xres = SANE_DPI; *yres = SANE_DPI;
1638
0
  }
1639
2
  else if (*xres == 0)
1640
0
  {
1641
0
    *xres = *yres;
1642
0
  }
1643
2
  else if (*yres == 0)
1644
0
  {
1645
0
    *yres = *xres;
1646
0
  }
1647
1648
  /* Scale xres and yres up until we get believable values */
1649
2
  if (*xres < SANE_DPI || *yres < SANE_DPI || *xres > INSANE_DPI || *yres > INSANE_DPI)
1650
0
  {
1651
0
    if (*xres < *yres)
1652
0
    {
1653
0
      *yres = *yres * SANE_DPI / *xres;
1654
0
      *xres = SANE_DPI;
1655
0
    }
1656
0
    else
1657
0
    {
1658
0
      *xres = *xres * SANE_DPI / *yres;
1659
0
      *yres = SANE_DPI;
1660
0
    }
1661
1662
0
    if (*xres == *yres || *xres < SANE_DPI || *yres < SANE_DPI || *xres > INSANE_DPI || *yres > INSANE_DPI)
1663
0
    {
1664
0
      *xres = SANE_DPI;
1665
0
      *yres = SANE_DPI;
1666
0
    }
1667
0
  }
1668
2
}
1669
1670
uint8_t fz_image_orientation(fz_context *ctx, fz_image *image)
1671
2
{
1672
2
  return image ? image->orientation : 0;
1673
2
}
1674
1675
fz_matrix fz_image_orientation_matrix(fz_context *ctx, fz_image *image)
1676
1
{
1677
1
  fz_matrix m;
1678
1679
1
  switch (image ? image->orientation : 0)
1680
1
  {
1681
1
  case 0:
1682
1
  case 1: /* 0 degree rotation */
1683
1
    m.a =  1; m.b =  0;
1684
1
    m.c =  0; m.d =  1;
1685
1
    m.e =  0; m.f =  0;
1686
1
    break;
1687
0
  case 2: /* 90 degree ccw */
1688
0
    m.a =  0; m.b = -1;
1689
0
    m.c =  1; m.d =  0;
1690
0
    m.e =  0; m.f =  1;
1691
0
    break;
1692
0
  case 3: /* 180 degree ccw */
1693
0
    m.a = -1; m.b =  0;
1694
0
    m.c =  0; m.d = -1;
1695
0
    m.e =  1; m.f =  1;
1696
0
    break;
1697
0
  case 4: /* 270 degree ccw */
1698
0
    m.a =  0; m.b =  1;
1699
0
    m.c = -1; m.d =  0;
1700
0
    m.e =  1; m.f =  0;
1701
0
    break;
1702
0
  case 5: /* flip on X */
1703
0
    m.a = -1; m.b = 0;
1704
0
    m.c =  0; m.d = 1;
1705
0
    m.e =  1; m.f = 0;
1706
0
    break;
1707
0
  case 6: /* flip on X, then rotate ccw by 90 degrees */
1708
0
    m.a =  0; m.b =  1;
1709
0
    m.c =  1; m.d =  0;
1710
0
    m.e =  0; m.f =  0;
1711
0
    break;
1712
0
  case 7: /* flip on X, then rotate ccw by 180 degrees */
1713
0
    m.a =  1; m.b =  0;
1714
0
    m.c =  0; m.d = -1;
1715
0
    m.e =  0; m.f =  1;
1716
0
    break;
1717
0
  case 8: /* flip on X, then rotate ccw by 270 degrees */
1718
0
    m.a =  0; m.b = -1;
1719
0
    m.c = -1; m.d =  0;
1720
0
    m.e =  1; m.f =  1;
1721
0
    break;
1722
1
  }
1723
1724
1
  return m;
1725
1
}
1726
1727
typedef struct fz_display_list_image
1728
{
1729
  fz_image super;
1730
  fz_matrix transform;
1731
  fz_display_list *list;
1732
} fz_display_list_image;
1733
1734
static fz_pixmap *
1735
display_list_image_get_pixmap(fz_context *ctx, fz_image *image_, fz_irect *subarea, int w, int h, int *l2factor)
1736
0
{
1737
0
  fz_display_list_image *image = (fz_display_list_image *)image_;
1738
0
  fz_matrix ctm;
1739
0
  fz_device *dev = NULL;
1740
0
  fz_pixmap *pix;
1741
1742
0
  fz_var(dev);
1743
1744
0
  if (subarea)
1745
0
  {
1746
    /* So, the whole image should be scaled to w * h, but we only want the
1747
     * given subarea of it. */
1748
0
    int l = (subarea->x0 * w) / image->super.w;
1749
0
    int t = (subarea->y0 * h) / image->super.h;
1750
0
    int r = (subarea->x1 * w + image->super.w - 1) / image->super.w;
1751
0
    int b = (subarea->y1 * h + image->super.h - 1) / image->super.h;
1752
1753
0
    pix = fz_new_pixmap(ctx, image->super.colorspace, r-l, b-t, NULL, 0);
1754
0
    pix->x = l;
1755
0
    pix->y = t;
1756
0
  }
1757
0
  else
1758
0
  {
1759
0
    pix = fz_new_pixmap(ctx, image->super.colorspace, w, h, NULL, 0);
1760
0
  }
1761
1762
  /* If we render the display list into pix with the image matrix, we'll get a unit
1763
   * square result. Therefore scale by w, h. */
1764
0
  ctm = fz_pre_scale(image->transform, w, h);
1765
1766
0
  fz_clear_pixmap(ctx, pix); /* clear to transparent */
1767
0
  fz_try(ctx)
1768
0
  {
1769
0
    dev = fz_new_draw_device(ctx, ctm, pix);
1770
0
    fz_run_display_list(ctx, image->list, dev, fz_identity, fz_infinite_rect, NULL);
1771
0
    fz_close_device(ctx, dev);
1772
0
  }
1773
0
  fz_always(ctx)
1774
0
    fz_drop_device(ctx, dev);
1775
0
  fz_catch(ctx)
1776
0
  {
1777
0
    fz_drop_pixmap(ctx, pix);
1778
0
    fz_rethrow(ctx);
1779
0
  }
1780
1781
  /* Never do more subsampling, cos we've already given them the right size */
1782
0
  if (l2factor)
1783
0
    *l2factor = 0;
1784
1785
0
  return pix;
1786
0
}
1787
1788
static void drop_display_list_image(fz_context *ctx, fz_image *image_)
1789
0
{
1790
0
  fz_display_list_image *image = (fz_display_list_image *)image_;
1791
1792
0
  if (image == NULL)
1793
0
    return;
1794
0
  fz_drop_display_list(ctx, image->list);
1795
0
}
1796
1797
static size_t
1798
display_list_image_get_size(fz_context *ctx, fz_image *image_)
1799
0
{
1800
0
  fz_display_list_image *image = (fz_display_list_image *)image_;
1801
1802
0
  if (image == NULL)
1803
0
    return 0;
1804
1805
0
  return sizeof(fz_display_list_image) + 4096; /* FIXME */
1806
0
}
1807
1808
static void
1809
display_list_image_get_digest(fz_context *ctx, fz_image *image_, unsigned char digest[16])
1810
0
{
1811
  /* ugly hack: checksum transform and display list pointer */
1812
0
  fz_display_list_image *image = (fz_display_list_image *)image_;
1813
0
  fz_md5 state;
1814
0
  fz_md5_init(&state);
1815
0
  fz_md5_update(&state, (unsigned char *) &image->transform, sizeof (image->transform));
1816
0
  fz_md5_update(&state, (unsigned char *) &image->list, sizeof (image->list));
1817
0
  fz_md5_final(&state, digest);
1818
0
}
1819
1820
fz_image *fz_new_image_from_display_list(fz_context *ctx, float w, float h, fz_display_list *list)
1821
0
{
1822
0
  fz_display_list_image *image;
1823
0
  int iw, ih;
1824
1825
0
  iw = w * SCALABLE_IMAGE_DPI / 72;
1826
0
  ih = h * SCALABLE_IMAGE_DPI / 72;
1827
1828
0
  image = fz_new_derived_image(ctx, iw, ih, 8, fz_device_rgb(ctx),
1829
0
        SCALABLE_IMAGE_DPI, SCALABLE_IMAGE_DPI, 0, 0,
1830
0
        NULL, NULL, NULL, fz_display_list_image,
1831
0
        display_list_image_get_pixmap,
1832
0
        display_list_image_get_size,
1833
0
        display_list_image_get_digest,
1834
0
        drop_display_list_image);
1835
0
  image->super.scalable = 1;
1836
0
  image->transform = fz_scale(1 / w, 1 / h);
1837
0
  image->list = fz_keep_display_list(ctx, list);
1838
1839
0
  return &image->super;
1840
0
}