Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7640 views
1
#include "mupdf/fitz.h"
2
3
#define SANE_DPI 72.0f
4
5
fz_pixmap *
6
fz_new_pixmap_from_image(fz_context *ctx, fz_image *image, int w, int h)
7
{
8
if (image == NULL)
9
return NULL;
10
return image->get_pixmap(ctx, image, w, h);
11
}
12
13
fz_image *
14
fz_keep_image(fz_context *ctx, fz_image *image)
15
{
16
return (fz_image *)fz_keep_storable(ctx, &image->storable);
17
}
18
19
void
20
fz_drop_image(fz_context *ctx, fz_image *image)
21
{
22
fz_drop_storable(ctx, &image->storable);
23
}
24
25
typedef struct fz_image_key_s fz_image_key;
26
27
struct fz_image_key_s {
28
int refs;
29
fz_image *image;
30
int l2factor;
31
};
32
33
static int
34
fz_make_hash_image_key(fz_context *ctx, fz_store_hash *hash, void *key_)
35
{
36
fz_image_key *key = (fz_image_key *)key_;
37
hash->u.pi.ptr = key->image;
38
hash->u.pi.i = key->l2factor;
39
return 1;
40
}
41
42
static void *
43
fz_keep_image_key(fz_context *ctx, void *key_)
44
{
45
fz_image_key *key = (fz_image_key *)key_;
46
return fz_keep_imp(ctx, key, &key->refs);
47
}
48
49
static void
50
fz_drop_image_key(fz_context *ctx, void *key_)
51
{
52
fz_image_key *key = (fz_image_key *)key_;
53
if (fz_drop_imp(ctx, key, &key->refs))
54
{
55
fz_drop_image(ctx, key->image);
56
fz_free(ctx, key);
57
}
58
}
59
60
static int
61
fz_cmp_image_key(fz_context *ctx, void *k0_, void *k1_)
62
{
63
fz_image_key *k0 = (fz_image_key *)k0_;
64
fz_image_key *k1 = (fz_image_key *)k1_;
65
return k0->image == k1->image && k0->l2factor == k1->l2factor;
66
}
67
68
#ifndef NDEBUG
69
static void
70
fz_debug_image(fz_context *ctx, FILE *out, void *key_)
71
{
72
fz_image_key *key = (fz_image_key *)key_;
73
74
fprintf(out, "(image %d x %d sf=%d) ", key->image->w, key->image->h, key->l2factor);
75
}
76
#endif
77
78
static fz_store_type fz_image_store_type =
79
{
80
fz_make_hash_image_key,
81
fz_keep_image_key,
82
fz_drop_image_key,
83
fz_cmp_image_key,
84
#ifndef NDEBUG
85
fz_debug_image
86
#endif
87
};
88
89
static void
90
fz_mask_color_key(fz_pixmap *pix, int n, int *colorkey)
91
{
92
unsigned char *p = pix->samples;
93
int len = pix->w * pix->h;
94
int k, t;
95
while (len--)
96
{
97
t = 1;
98
for (k = 0; k < n; k++)
99
if (p[k] < colorkey[k * 2] || p[k] > colorkey[k * 2 + 1])
100
t = 0;
101
if (t)
102
for (k = 0; k < pix->n; k++)
103
p[k] = 0;
104
p += pix->n;
105
}
106
}
107
108
static void
109
fz_unblend_masked_tile(fz_context *ctx, fz_pixmap *tile, fz_image *image)
110
{
111
fz_pixmap *mask = image->mask->get_pixmap(ctx, image->mask, tile->w, tile->h);
112
unsigned char *s = mask->samples, *end = s + mask->w * mask->h;
113
unsigned char *d = tile->samples;
114
int k;
115
116
if (tile->w != mask->w || tile->h != mask->h)
117
{
118
fz_warn(ctx, "mask must be of same size as image for /Matte");
119
fz_drop_pixmap(ctx, mask);
120
return;
121
}
122
123
for (; s < end; s++, d += tile->n)
124
{
125
if (*s == 0)
126
for (k = 0; k < image->n; k++)
127
d[k] = image->colorkey[k];
128
else
129
for (k = 0; k < image->n; k++)
130
d[k] = fz_clampi(image->colorkey[k] + (d[k] - image->colorkey[k]) * 255 / *s, 0, 255);
131
}
132
133
fz_drop_pixmap(ctx, mask);
134
}
135
136
fz_pixmap *
137
fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_image *image, int indexed, int l2factor, int native_l2factor)
138
{
139
fz_pixmap *tile = NULL;
140
int stride, len, i;
141
unsigned char *samples = NULL;
142
int f = 1<<native_l2factor;
143
int w = (image->w + f-1) >> native_l2factor;
144
int h = (image->h + f-1) >> native_l2factor;
145
146
fz_var(tile);
147
fz_var(samples);
148
149
fz_try(ctx)
150
{
151
tile = fz_new_pixmap(ctx, image->colorspace, w, h);
152
tile->interpolate = image->interpolate;
153
154
stride = (w * image->n * image->bpc + 7) / 8;
155
156
samples = fz_malloc_array(ctx, h, stride);
157
158
len = fz_read(ctx, stm, samples, h * stride);
159
160
/* Pad truncated images */
161
if (len < stride * h)
162
{
163
fz_warn(ctx, "padding truncated image");
164
memset(samples + len, 0, stride * h - len);
165
}
166
167
/* Invert 1-bit image masks */
168
if (image->imagemask)
169
{
170
/* 0=opaque and 1=transparent so we need to invert */
171
unsigned char *p = samples;
172
len = h * stride;
173
for (i = 0; i < len; i++)
174
p[i] = ~p[i];
175
}
176
177
fz_unpack_tile(ctx, tile, samples, image->n, image->bpc, stride, indexed);
178
179
fz_free(ctx, samples);
180
samples = NULL;
181
182
/* color keyed transparency */
183
if (image->usecolorkey && !image->mask)
184
fz_mask_color_key(tile, image->n, image->colorkey);
185
186
if (indexed)
187
{
188
fz_pixmap *conv;
189
fz_decode_indexed_tile(ctx, tile, image->decode, (1 << image->bpc) - 1);
190
conv = fz_expand_indexed_pixmap(ctx, tile);
191
fz_drop_pixmap(ctx, tile);
192
tile = conv;
193
}
194
else
195
{
196
fz_decode_tile(ctx, tile, image->decode);
197
}
198
199
/* pre-blended matte color */
200
if (image->usecolorkey && image->mask)
201
fz_unblend_masked_tile(ctx, tile, image);
202
}
203
fz_always(ctx)
204
{
205
fz_drop_stream(ctx, stm);
206
}
207
fz_catch(ctx)
208
{
209
if (tile)
210
fz_drop_pixmap(ctx, tile);
211
fz_free(ctx, samples);
212
213
fz_rethrow(ctx);
214
}
215
216
/* Now apply any extra subsampling required */
217
if (l2factor - native_l2factor > 0)
218
{
219
if (l2factor - native_l2factor > 8)
220
l2factor = native_l2factor + 8;
221
fz_subsample_pixmap(ctx, tile, l2factor - native_l2factor);
222
}
223
224
return tile;
225
}
226
227
void
228
fz_drop_image_imp(fz_context *ctx, fz_storable *image_)
229
{
230
fz_image *image = (fz_image *)image_;
231
232
if (image == NULL)
233
return;
234
fz_drop_pixmap(ctx, image->tile);
235
fz_drop_compressed_buffer(ctx, image->buffer);
236
fz_drop_colorspace(ctx, image->colorspace);
237
fz_drop_image(ctx, image->mask);
238
fz_free(ctx, image);
239
}
240
241
fz_pixmap *
242
fz_image_get_pixmap(fz_context *ctx, fz_image *image, int w, int h)
243
{
244
fz_pixmap *tile;
245
fz_stream *stm;
246
int l2factor;
247
fz_image_key key;
248
int native_l2factor;
249
int indexed;
250
fz_image_key *keyp;
251
252
/* Check for 'simple' images which are just pixmaps */
253
if (image->buffer == NULL)
254
{
255
tile = image->tile;
256
if (!tile)
257
return NULL;
258
return fz_keep_pixmap(ctx, tile); /* That's all we can give you! */
259
}
260
261
/* Ensure our expectations for tile size are reasonable */
262
if (w < 0 || w > image->w)
263
w = image->w;
264
if (h < 0 || h > image->h)
265
h = image->h;
266
267
/* What is our ideal factor? We search for the largest factor where
268
* we can subdivide and stay larger than the required size. We add
269
* a fudge factor of +2 here to allow for the possibility of
270
* expansion due to grid fitting. */
271
if (w == 0 || h == 0)
272
l2factor = 0;
273
else
274
for (l2factor=0; image->w>>(l2factor+1) >= w+2 && image->h>>(l2factor+1) >= h+2 && l2factor < 8; l2factor++);
275
276
/* Can we find any suitable tiles in the cache? */
277
key.refs = 1;
278
key.image = image;
279
key.l2factor = l2factor;
280
do
281
{
282
tile = fz_find_item(ctx, fz_drop_pixmap_imp, &key, &fz_image_store_type);
283
if (tile)
284
return tile;
285
key.l2factor--;
286
}
287
while (key.l2factor >= 0);
288
289
/* We need to make a new one. */
290
/* First check for ones that we can't decode using streams */
291
switch (image->buffer->params.type)
292
{
293
case FZ_IMAGE_PNG:
294
tile = fz_load_png(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
295
break;
296
case FZ_IMAGE_TIFF:
297
tile = fz_load_tiff(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
298
break;
299
case FZ_IMAGE_JXR:
300
tile = fz_load_jxr(ctx, image->buffer->buffer->data, image->buffer->buffer->len);
301
break;
302
case FZ_IMAGE_JPEG:
303
/* Scan JPEG stream and patch missing height values in header */
304
{
305
unsigned char *s = image->buffer->buffer->data;
306
unsigned char *e = s + image->buffer->buffer->len;
307
unsigned char *d;
308
for (d = s + 2; s < d && d < e - 9 && d[0] == 0xFF; d += (d[2] << 8 | d[3]) + 2)
309
{
310
if (d[1] < 0xC0 || (0xC3 < d[1] && d[1] < 0xC9) || 0xCB < d[1])
311
continue;
312
if ((d[5] == 0 && d[6] == 0) || ((d[5] << 8) | d[6]) > image->h)
313
{
314
d[5] = (image->h >> 8) & 0xFF;
315
d[6] = image->h & 0xFF;
316
}
317
}
318
}
319
/* fall through */
320
321
default:
322
native_l2factor = l2factor;
323
stm = fz_open_image_decomp_stream_from_buffer(ctx, image->buffer, &native_l2factor);
324
325
indexed = fz_colorspace_is_indexed(ctx, image->colorspace);
326
tile = fz_decomp_image_from_stream(ctx, stm, image, indexed, l2factor, native_l2factor);
327
328
/* CMYK JPEGs in XPS documents have to be inverted */
329
if (image->invert_cmyk_jpeg &&
330
image->buffer->params.type == FZ_IMAGE_JPEG &&
331
image->colorspace == fz_device_cmyk(ctx) &&
332
image->buffer->params.u.jpeg.color_transform)
333
{
334
fz_invert_pixmap(ctx, tile);
335
}
336
337
break;
338
}
339
340
/* Now we try to cache the pixmap. Any failure here will just result
341
* in us not caching. */
342
fz_var(keyp);
343
fz_try(ctx)
344
{
345
fz_pixmap *existing_tile;
346
347
keyp = fz_malloc_struct(ctx, fz_image_key);
348
keyp->refs = 1;
349
keyp->image = fz_keep_image(ctx, image);
350
keyp->l2factor = l2factor;
351
existing_tile = fz_store_item(ctx, keyp, tile, fz_pixmap_size(ctx, tile), &fz_image_store_type);
352
if (existing_tile)
353
{
354
/* We already have a tile. This must have been produced by a
355
* racing thread. We'll throw away ours and use that one. */
356
fz_drop_pixmap(ctx, tile);
357
tile = existing_tile;
358
}
359
}
360
fz_always(ctx)
361
{
362
fz_drop_image_key(ctx, keyp);
363
}
364
fz_catch(ctx)
365
{
366
/* Do nothing */
367
}
368
369
return tile;
370
}
371
372
fz_image *
373
fz_new_image_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, fz_image *mask)
374
{
375
fz_image *image;
376
377
assert(mask == NULL || mask->mask == NULL);
378
379
fz_try(ctx)
380
{
381
image = fz_malloc_struct(ctx, fz_image);
382
FZ_INIT_STORABLE(image, 1, fz_drop_image_imp);
383
image->w = pixmap->w;
384
image->h = pixmap->h;
385
image->n = pixmap->n;
386
image->colorspace = fz_keep_colorspace(ctx, pixmap->colorspace);
387
image->bpc = 8;
388
image->buffer = NULL;
389
image->get_pixmap = fz_image_get_pixmap;
390
image->xres = pixmap->xres;
391
image->yres = pixmap->yres;
392
image->tile = fz_keep_pixmap(ctx, pixmap);
393
image->mask = mask;
394
}
395
fz_catch(ctx)
396
{
397
fz_drop_image(ctx, mask);
398
fz_rethrow(ctx);
399
}
400
return image;
401
}
402
403
fz_image *
404
fz_new_image(fz_context *ctx, int w, int h, int bpc, fz_colorspace *colorspace,
405
int xres, int yres, int interpolate, int imagemask, float *decode,
406
int *colorkey, fz_compressed_buffer *buffer, fz_image *mask)
407
{
408
fz_image *image;
409
410
assert(mask == NULL || mask->mask == NULL);
411
412
fz_try(ctx)
413
{
414
image = fz_malloc_struct(ctx, fz_image);
415
FZ_INIT_STORABLE(image, 1, fz_drop_image_imp);
416
image->get_pixmap = fz_image_get_pixmap;
417
image->w = w;
418
image->h = h;
419
image->xres = xres;
420
image->yres = yres;
421
image->bpc = bpc;
422
image->n = (colorspace ? colorspace->n : 1);
423
image->colorspace = colorspace;
424
image->interpolate = interpolate;
425
image->imagemask = imagemask;
426
image->usecolorkey = (colorkey != NULL);
427
if (colorkey)
428
memcpy(image->colorkey, colorkey, sizeof(int)*image->n*2);
429
if (decode)
430
memcpy(image->decode, decode, sizeof(float)*image->n*2);
431
else
432
{
433
float maxval = fz_colorspace_is_indexed(ctx, colorspace) ? (1 << bpc) - 1 : 1;
434
int i;
435
for (i = 0; i < image->n; i++)
436
{
437
image->decode[2*i] = 0;
438
image->decode[2*i+1] = maxval;
439
}
440
}
441
image->mask = mask;
442
image->buffer = buffer;
443
}
444
fz_catch(ctx)
445
{
446
fz_drop_compressed_buffer(ctx, buffer);
447
fz_rethrow(ctx);
448
}
449
450
return image;
451
}
452
453
fz_image *
454
fz_new_image_from_data(fz_context *ctx, unsigned char *data, int len)
455
{
456
fz_buffer *buffer = NULL;
457
fz_image *image;
458
459
fz_var(buffer);
460
fz_var(data);
461
462
fz_try(ctx)
463
{
464
buffer = fz_new_buffer_from_data(ctx, data, len);
465
data = NULL;
466
image = fz_new_image_from_buffer(ctx, buffer);
467
}
468
fz_always(ctx)
469
{
470
fz_drop_buffer(ctx, buffer);
471
}
472
fz_catch(ctx)
473
{
474
fz_free(ctx, data);
475
fz_rethrow(ctx);
476
}
477
478
return image;
479
}
480
481
fz_image *
482
fz_new_image_from_buffer(fz_context *ctx, fz_buffer *buffer)
483
{
484
fz_compressed_buffer *bc = NULL;
485
int w, h, xres, yres;
486
fz_colorspace *cspace;
487
int len = buffer->len;
488
unsigned char *buf = buffer->data;
489
490
fz_var(bc);
491
492
fz_try(ctx)
493
{
494
if (len < 8)
495
fz_throw(ctx, FZ_ERROR_GENERIC, "unknown image file format");
496
497
bc = fz_malloc_struct(ctx, fz_compressed_buffer);
498
bc->buffer = fz_keep_buffer(ctx, buffer);
499
500
if (buf[0] == 0xff && buf[1] == 0xd8)
501
{
502
bc->params.type = FZ_IMAGE_JPEG;
503
bc->params.u.jpeg.color_transform = -1;
504
fz_load_jpeg_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
505
}
506
else if (memcmp(buf, "\211PNG\r\n\032\n", 8) == 0)
507
{
508
bc->params.type = FZ_IMAGE_PNG;
509
fz_load_png_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
510
}
511
else if (memcmp(buf, "II", 2) == 0 && buf[2] == 0xBC)
512
{
513
bc->params.type = FZ_IMAGE_JXR;
514
fz_load_jxr_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
515
}
516
else if (memcmp(buf, "MM", 2) == 0 || memcmp(buf, "II", 2) == 0)
517
{
518
bc->params.type = FZ_IMAGE_TIFF;
519
fz_load_tiff_info(ctx, buf, len, &w, &h, &xres, &yres, &cspace);
520
}
521
else
522
fz_throw(ctx, FZ_ERROR_GENERIC, "unknown image file format");
523
}
524
fz_catch(ctx)
525
{
526
fz_drop_compressed_buffer(ctx, bc);
527
fz_rethrow(ctx);
528
}
529
530
return fz_new_image(ctx, w, h, 8, cspace, xres, yres, 0, 0, NULL, NULL, bc, NULL);
531
}
532
533
void
534
fz_image_get_sanitised_res(fz_image *image, int *xres, int *yres)
535
{
536
*xres = image->xres;
537
*yres = image->yres;
538
if (*xres < 0 || *yres < 0 || (*xres == 0 && *yres == 0))
539
{
540
/* If neither xres or yres is sane, pick a sane value */
541
*xres = SANE_DPI; *yres = SANE_DPI;
542
}
543
else if (*xres == 0)
544
{
545
*xres = *yres;
546
}
547
else if (*yres == 0)
548
{
549
*yres = *xres;
550
}
551
552
/* Scale xres and yres up until we get beleivable values */
553
if (*xres < SANE_DPI || *yres < SANE_DPI)
554
{
555
if (*xres == *yres)
556
{
557
*xres = SANE_DPI;
558
*yres = SANE_DPI;
559
}
560
else if (*xres < *yres)
561
{
562
*yres = *yres * SANE_DPI / *xres;
563
*xres = SANE_DPI;
564
}
565
else
566
{
567
*xres = *xres * SANE_DPI / *yres;
568
*yres = SANE_DPI;
569
}
570
}
571
}
572
573