comparison mupdf-source/source/pdf/pdf-image.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2004-2025 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 #include "mupdf/pdf.h"
25
26 #include <string.h>
27
28 static fz_image *pdf_load_jpx(fz_context *ctx, pdf_document *doc, pdf_obj *dict, int forcemask);
29
30 static fz_image *
31 pdf_load_jpx_imp(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask)
32 {
33 fz_image *image = pdf_load_jpx(ctx, doc, dict, forcemask);
34
35 if (forcemask)
36 {
37 fz_pixmap_image *cimg = (fz_pixmap_image *)image;
38 fz_pixmap *mask_pixmap;
39 fz_pixmap *tile = fz_pixmap_image_tile(ctx, cimg);
40
41 if (tile->n != 1)
42 {
43 fz_pixmap *gray = fz_convert_pixmap(ctx, tile, fz_device_gray(ctx), NULL, NULL, fz_default_color_params, 0);
44 fz_drop_pixmap(ctx, tile);
45 tile = gray;
46 }
47
48 mask_pixmap = fz_alpha_from_gray(ctx, tile);
49 fz_drop_pixmap(ctx, tile);
50 fz_set_pixmap_image_tile(ctx, cimg, mask_pixmap);
51 }
52
53 return image;
54 }
55
56 static fz_image *
57 pdf_load_image_imp(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask)
58 {
59 fz_image *image = NULL;
60 pdf_obj *obj, *res;
61
62 int w, h, bpc, n;
63 int imagemask;
64 int interpolate;
65 int indexed;
66 fz_image *mask = NULL; /* explicit mask/soft mask image */
67 int use_colorkey = 0;
68 fz_colorspace *colorspace = NULL;
69 float decode[FZ_MAX_COLORS * 2];
70 int colorkey[FZ_MAX_COLORS * 2];
71 int stride;
72 pdf_obj *intent;
73
74 int i;
75 fz_compressed_buffer *buffer;
76
77 /* special case for JPEG2000 images */
78 if (pdf_is_jpx_image(ctx, dict))
79 return pdf_load_jpx_imp(ctx, doc, rdb, dict, cstm, forcemask);
80
81 w = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Width), PDF_NAME(W)));
82 h = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Height), PDF_NAME(H)));
83 bpc = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(BitsPerComponent), PDF_NAME(BPC)));
84 if (bpc == 0)
85 bpc = 8;
86 imagemask = pdf_to_bool(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(ImageMask), PDF_NAME(IM)));
87 interpolate = pdf_to_bool(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Interpolate), PDF_NAME(I)));
88 intent = pdf_dict_get(ctx, dict, PDF_NAME(Intent));
89
90 indexed = 0;
91 use_colorkey = 0;
92
93 if (imagemask)
94 bpc = 1;
95
96 if (w <= 0)
97 fz_throw(ctx, FZ_ERROR_SYNTAX, "image width is zero (or less)");
98 if (h <= 0)
99 fz_throw(ctx, FZ_ERROR_SYNTAX, "image height is zero (or less)");
100 if (bpc <= 0)
101 fz_throw(ctx, FZ_ERROR_SYNTAX, "image depth is zero (or less)");
102 if (bpc > 16)
103 fz_throw(ctx, FZ_ERROR_SYNTAX, "image depth is too large: %d", bpc);
104 if (SIZE_MAX / w < (size_t)(bpc+7)/8)
105 fz_throw(ctx, FZ_ERROR_SYNTAX, "image is too large");
106 if (SIZE_MAX / h < w * (size_t)((bpc+7)/8))
107 fz_throw(ctx, FZ_ERROR_SYNTAX, "image is too large");
108
109 fz_var(mask);
110 fz_var(image);
111 fz_var(colorspace);
112
113 fz_try(ctx)
114 {
115 obj = pdf_dict_geta(ctx, dict, PDF_NAME(ColorSpace), PDF_NAME(CS));
116 if (obj && !imagemask && !forcemask)
117 {
118 /* colorspace resource lookup is only done for inline images */
119 if (pdf_is_name(ctx, obj))
120 {
121 res = pdf_dict_get(ctx, pdf_dict_get(ctx, rdb, PDF_NAME(ColorSpace)), obj);
122 if (res)
123 obj = res;
124 }
125
126 colorspace = pdf_load_colorspace(ctx, obj);
127 indexed = fz_colorspace_is_indexed(ctx, colorspace);
128
129 n = fz_colorspace_n(ctx, colorspace);
130 }
131 else
132 {
133 n = 1;
134 }
135
136 if (SIZE_MAX / n < h * ((size_t)w) * ((bpc+7)/8))
137 fz_throw(ctx, FZ_ERROR_SYNTAX, "image is too large");
138
139 obj = pdf_dict_geta(ctx, dict, PDF_NAME(Decode), PDF_NAME(D));
140 if (obj)
141 {
142 for (i = 0; i < n * 2; i++)
143 decode[i] = pdf_array_get_real(ctx, obj, i);
144 }
145 else if (fz_colorspace_is_lab(ctx, colorspace))
146 {
147 decode[0] = 0;
148 decode[1] = 100;
149 decode[2] = -128;
150 decode[3] = 127;
151 decode[4] = -128;
152 decode[5] = 127;
153 }
154 else
155 {
156 float maxval = indexed ? (1 << bpc) - 1 : 1;
157 for (i = 0; i < n * 2; i++)
158 decode[i] = i & 1 ? maxval : 0;
159 }
160
161 obj = pdf_dict_get(ctx, dict, PDF_NAME(SMask));
162 if (!pdf_is_dict(ctx, obj))
163 obj = pdf_dict_get(ctx, dict, PDF_NAME(Mask));
164 if (pdf_is_dict(ctx, obj))
165 {
166 /* Not allowed for inline images or soft masks */
167 if (cstm)
168 fz_warn(ctx, "Ignoring invalid inline image soft mask");
169 else if (forcemask)
170 fz_warn(ctx, "Ignoring recursive image soft mask");
171 else
172 {
173 mask = pdf_load_image_imp(ctx, doc, rdb, obj, NULL, 1);
174 obj = pdf_dict_get(ctx, obj, PDF_NAME(Matte));
175 if (pdf_is_array(ctx, obj))
176 {
177 use_colorkey = 1;
178 for (i = 0; i < n; i++)
179 colorkey[i] = fz_clamp(pdf_array_get_real(ctx, obj, i), 0, 1) * 255;
180 }
181 }
182 }
183 else if (pdf_is_array(ctx, obj))
184 {
185 use_colorkey = 1;
186 for (i = 0; i < n * 2; i++)
187 {
188 if (!pdf_is_int(ctx, pdf_array_get(ctx, obj, i)))
189 {
190 fz_warn(ctx, "invalid value in color key mask");
191 use_colorkey = 0;
192 }
193 colorkey[i] = pdf_array_get_int(ctx, obj, i);
194 }
195 }
196
197 /* Do we load from a ref, or do we load an inline stream? */
198 if (cstm == NULL)
199 {
200 /* Just load the compressed image data now and we can decode it on demand. */
201 size_t worst_case = w * (size_t)h;
202 worst_case = (worst_case * bpc + 7) >> 3;
203 if (colorspace)
204 worst_case *= colorspace->n;
205 buffer = pdf_load_compressed_stream(ctx, doc, pdf_to_num(ctx, dict), worst_case);
206 image = fz_new_image_from_compressed_buffer(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, use_colorkey ? colorkey : NULL, buffer, mask);
207 }
208 else
209 {
210 /* Inline stream */
211 stride = (w * n * bpc + 7) / 8;
212 image = fz_new_image_from_compressed_buffer(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, use_colorkey ? colorkey : NULL, NULL, mask);
213 pdf_load_compressed_inline_image(ctx, doc, dict, stride * h, cstm, indexed, (fz_compressed_image *)image);
214 }
215 if (pdf_name_eq(ctx, intent, PDF_NAME(Perceptual)))
216 image->has_intent = 1, image->intent = FZ_RI_PERCEPTUAL;
217 else if (pdf_name_eq(ctx, intent, PDF_NAME(AbsoluteColorimetric)))
218 image->has_intent = 1, image->intent = FZ_RI_ABSOLUTE_COLORIMETRIC;
219 else if (pdf_name_eq(ctx, intent, PDF_NAME(RelativeColorimetric)))
220 image->has_intent = 1, image->intent = FZ_RI_RELATIVE_COLORIMETRIC;
221 else if (pdf_name_eq(ctx, intent, PDF_NAME(Saturation)))
222 image->has_intent = 1, image->intent = FZ_RI_SATURATION;
223 }
224 fz_always(ctx)
225 {
226 fz_drop_colorspace(ctx, colorspace);
227 fz_drop_image(ctx, mask);
228 }
229 fz_catch(ctx)
230 {
231 fz_drop_image(ctx, image);
232 fz_rethrow(ctx);
233 }
234 return image;
235 }
236
237 fz_image *
238 pdf_load_inline_image(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *file)
239 {
240 return pdf_load_image_imp(ctx, doc, rdb, dict, file, 0);
241 }
242
243 int
244 pdf_is_jpx_image(fz_context *ctx, pdf_obj *dict)
245 {
246 pdf_obj *filter;
247 int i, n;
248
249 filter = pdf_dict_get(ctx, dict, PDF_NAME(Filter));
250 if (pdf_name_eq(ctx, filter, PDF_NAME(JPXDecode)))
251 return 1;
252 n = pdf_array_len(ctx, filter);
253 for (i = 0; i < n; i++)
254 if (pdf_name_eq(ctx, pdf_array_get(ctx, filter, i), PDF_NAME(JPXDecode)))
255 return 1;
256 return 0;
257 }
258
259 static fz_image *
260 pdf_load_jpx(fz_context *ctx, pdf_document *doc, pdf_obj *dict, int forcemask)
261 {
262 fz_buffer *buf = NULL;
263 fz_colorspace *colorspace = NULL;
264 fz_pixmap *pix = NULL;
265 pdf_obj *obj;
266 fz_image *mask = NULL;
267 fz_image *img = NULL;
268
269 fz_var(pix);
270 fz_var(buf);
271 fz_var(colorspace);
272 fz_var(mask);
273
274 buf = pdf_load_stream(ctx, dict);
275
276 /* FIXME: We can't handle decode arrays for indexed images currently */
277 fz_try(ctx)
278 {
279 unsigned char *data;
280 size_t len;
281
282 obj = pdf_dict_get(ctx, dict, PDF_NAME(ColorSpace));
283 if (obj)
284 colorspace = pdf_load_colorspace(ctx, obj);
285
286 len = fz_buffer_storage(ctx, buf, &data);
287 pix = fz_load_jpx(ctx, data, len, colorspace);
288
289 obj = pdf_dict_geta(ctx, dict, PDF_NAME(SMask), PDF_NAME(Mask));
290 if (pdf_is_dict(ctx, obj))
291 {
292 if (forcemask)
293 fz_warn(ctx, "Ignoring recursive JPX soft mask");
294 else
295 mask = pdf_load_image_imp(ctx, doc, NULL, obj, NULL, 1);
296 }
297
298 obj = pdf_dict_geta(ctx, dict, PDF_NAME(Decode), PDF_NAME(D));
299 if (obj && !fz_colorspace_is_indexed(ctx, colorspace))
300 {
301 float decode[FZ_MAX_COLORS * 2];
302 int i;
303
304 for (i = 0; i < pix->n * 2; i++)
305 decode[i] = pdf_array_get_real(ctx, obj, i);
306
307 fz_decode_tile(ctx, pix, decode);
308 }
309
310 img = fz_new_image_from_pixmap(ctx, pix, mask);
311 }
312 fz_always(ctx)
313 {
314 fz_drop_image(ctx, mask);
315 fz_drop_pixmap(ctx, pix);
316 fz_drop_colorspace(ctx, colorspace);
317 fz_drop_buffer(ctx, buf);
318 }
319 fz_catch(ctx)
320 {
321 fz_morph_error(ctx, FZ_ERROR_FORMAT, FZ_ERROR_SYNTAX);
322 fz_morph_error(ctx, FZ_ERROR_LIBRARY, FZ_ERROR_SYNTAX);
323 fz_rethrow(ctx);
324 }
325
326 return img;
327 }
328
329 fz_image *
330 pdf_load_image(fz_context *ctx, pdf_document *doc, pdf_obj *dict)
331 {
332 fz_image *image;
333
334 if ((image = pdf_find_item(ctx, fz_drop_image_imp, dict)) != NULL)
335 return image;
336
337 image = pdf_load_image_imp(ctx, doc, NULL, dict, NULL, 0);
338 pdf_store_item(ctx, dict, image, fz_image_size(ctx, image));
339 return image;
340 }
341
342 struct jbig2_segment_header {
343 int number;
344 int flags;
345 /* referred-to-segment numbers */
346 int page;
347 uint32_t length;
348 };
349
350 /* coverity[-tainted_data_return] */
351 static uint32_t getu32(const unsigned char *data)
352 {
353 return ((uint32_t)data[0]<<24) | ((uint32_t)data[1]<<16) | ((uint32_t)data[2]<<8) | (uint32_t)data[3];
354 }
355
356 static size_t
357 pdf_parse_jbig2_segment_header(fz_context *ctx,
358 const unsigned char *data, const unsigned char *end,
359 struct jbig2_segment_header *info)
360 {
361 uint32_t rts;
362 size_t n = 5;
363
364 if (data + 11 > end) return 0;
365
366 info->number = getu32(data);
367 info->flags = data[4];
368
369 rts = (data[5] >> 5) & 0x7;
370 if (rts == 7)
371 {
372 rts = getu32(data+5) & 0x1FFFFFFF;
373 n += 4 + (rts + 1) / 8;
374 }
375 else
376 {
377 n += 1;
378 }
379
380 if (info->number <= 256)
381 n += rts;
382 else if (info->number <= 65536)
383 n += rts * 2;
384 else
385 n += rts * 4;
386
387 if (info->flags & 0x40)
388 {
389 if (data + n + 4 > end) return 0;
390 info->page = getu32(data+n);
391 n += 4;
392 }
393 else
394 {
395 if (data + n + 1 > end) return 0;
396 info->page = data[n];
397 n += 1;
398 }
399
400 if (data + n + 4 > end) return 0;
401 info->length = getu32(data+n);
402 return n + 4;
403 }
404
405 static void
406 pdf_copy_jbig2_segments(fz_context *ctx, fz_buffer *output, const unsigned char *data, size_t size, int page)
407 {
408 struct jbig2_segment_header info;
409 const unsigned char *end = data + size;
410 size_t n;
411 int type;
412
413 while (data < end)
414 {
415 n = pdf_parse_jbig2_segment_header(ctx, data, end, &info);
416 if (n == 0)
417 fz_throw(ctx, FZ_ERROR_FORMAT, "truncated jbig2 segment header");
418
419 /* omit end of page, end of file, and segments for other pages */
420 type = (info.flags & 63);
421 if (type == 49 || type == 51 || (info.page > 0 && info.page != page))
422 {
423 data += n;
424 data += info.length;
425 }
426 else
427 {
428 fz_append_data(ctx, output, data, n);
429 data += n;
430 if (data + info.length > end)
431 fz_throw(ctx, FZ_ERROR_FORMAT, "truncated jbig2 segment data");
432 fz_append_data(ctx, output, data, info.length);
433 data += info.length;
434 }
435 }
436 }
437
438 static void
439 pdf_copy_jbig2_random_segments(fz_context *ctx, fz_buffer *output, const unsigned char *data, size_t size, int page)
440 {
441 struct jbig2_segment_header info;
442 const unsigned char *header = data;
443 const unsigned char *header_end;
444 const unsigned char *end = data + size;
445 size_t n;
446 int type;
447
448 /* Skip headers until end-of-file segment is found. */
449 while (data < end)
450 {
451 n = pdf_parse_jbig2_segment_header(ctx, data, end, &info);
452 if (n == 0)
453 fz_throw(ctx, FZ_ERROR_FORMAT, "truncated jbig2 segment header");
454 data += n;
455 if ((info.flags & 63) == 51)
456 break;
457 }
458 if (data >= end)
459 fz_throw(ctx, FZ_ERROR_FORMAT, "truncated jbig2 segment header");
460
461 /* Copy segment headers and segment data */
462 header_end = data;
463 while (data < end && header < header_end)
464 {
465 n = pdf_parse_jbig2_segment_header(ctx, header, header_end, &info);
466 if (n == 0)
467 fz_throw(ctx, FZ_ERROR_FORMAT, "truncated jbig2 segment header");
468
469 /* omit end of page, end of file, and segments for other pages */
470 type = (info.flags & 63);
471 if (type == 49 || type == 51 || (info.page > 0 && info.page != page))
472 {
473 header += n;
474 data += info.length;
475 }
476 else
477 {
478 fz_append_data(ctx, output, header, n);
479 header += n;
480 if (data + info.length > end)
481 fz_throw(ctx, FZ_ERROR_FORMAT, "truncated jbig2 segment data");
482 fz_append_data(ctx, output, data, info.length);
483 data += info.length;
484 }
485 }
486 }
487
488 static fz_buffer *
489 pdf_jbig2_stream_from_file(fz_context *ctx, fz_buffer *input, fz_jbig2_globals *globals_, int page)
490 {
491 fz_buffer *globals = fz_jbig2_globals_data(ctx, globals_);
492 size_t globals_size = globals ? globals->len : 0;
493 fz_buffer *output;
494 int flags;
495 size_t header = 9;
496
497 if (input->len < 9)
498 return NULL; /* not enough data! */
499 flags = input->data[8];
500 if ((flags & 2) == 0)
501 {
502 if (input->len < 13)
503 return NULL; /* not enough data! */
504 header = 13;
505 }
506
507 output = fz_new_buffer(ctx, input->len + globals_size);
508 fz_try(ctx)
509 {
510 if (globals_size > 0)
511 fz_append_buffer(ctx, output, globals);
512 if ((flags & 1) == 0)
513 pdf_copy_jbig2_random_segments(ctx, output, input->data + header, input->len - header, page);
514 else
515 pdf_copy_jbig2_segments(ctx, output, input->data + header, input->len - header, page);
516 }
517 fz_catch(ctx)
518 {
519 fz_drop_buffer(ctx, output);
520 fz_rethrow(ctx);
521 }
522
523 return output;
524 }
525
526 pdf_obj *
527 pdf_add_image(fz_context *ctx, pdf_document *doc, fz_image *image)
528 {
529 fz_pixmap *pixmap = NULL;
530 pdf_obj *imobj = NULL;
531 pdf_obj *dp;
532 fz_buffer *buffer = NULL;
533 fz_compressed_buffer *cbuffer;
534 fz_pixmap *smask_pixmap = NULL;
535 fz_image *smask_image = NULL;
536 int i, n;
537
538 fz_var(pixmap);
539 fz_var(buffer);
540 fz_var(imobj);
541 fz_var(smask_pixmap);
542 fz_var(smask_image);
543
544 pdf_begin_operation(ctx, doc, "Add image");
545
546 fz_try(ctx)
547 {
548 /* If we can maintain compression, do so */
549 cbuffer = fz_compressed_image_buffer(ctx, image);
550
551 imobj = pdf_add_new_dict(ctx, doc, 3);
552
553 dp = pdf_dict_put_dict(ctx, imobj, PDF_NAME(DecodeParms), 3);
554 pdf_dict_put(ctx, imobj, PDF_NAME(Type), PDF_NAME(XObject));
555 pdf_dict_put(ctx, imobj, PDF_NAME(Subtype), PDF_NAME(Image));
556
557 if (cbuffer)
558 {
559 fz_compression_params *cp = &cbuffer->params;
560 switch (cp->type)
561 {
562 default:
563 goto unknown_compression;
564 case FZ_IMAGE_RAW:
565 break;
566 case FZ_IMAGE_JPEG:
567 pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(DCTDecode));
568 if (cp->u.jpeg.color_transform >= 0)
569 pdf_dict_put_int(ctx, dp, PDF_NAME(ColorTransform), cp->u.jpeg.color_transform);
570 if (cp->u.jpeg.invert_cmyk && image->n == 4)
571 {
572 pdf_obj *arr;
573 arr = pdf_dict_put_array(ctx, imobj, PDF_NAME(Decode), 8);
574 pdf_array_push_int(ctx, arr, 1);
575 pdf_array_push_int(ctx, arr, 0);
576 pdf_array_push_int(ctx, arr, 1);
577 pdf_array_push_int(ctx, arr, 0);
578 pdf_array_push_int(ctx, arr, 1);
579 pdf_array_push_int(ctx, arr, 0);
580 pdf_array_push_int(ctx, arr, 1);
581 pdf_array_push_int(ctx, arr, 0);
582 }
583 break;
584 case FZ_IMAGE_JPX:
585 if (cp->u.jpx.smask_in_data)
586 pdf_dict_put_int(ctx, dp, PDF_NAME(SMaskInData), cp->u.jpx.smask_in_data);
587 pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(JPXDecode));
588 break;
589 case FZ_IMAGE_JBIG2:
590 if (cp->u.jbig2.embedded && cp->u.jbig2.globals)
591 {
592 pdf_obj *globals_ref = pdf_add_new_dict(ctx, doc, 1);
593 pdf_dict_put_drop(ctx, dp, PDF_NAME(JBIG2Globals), globals_ref);
594 pdf_update_stream(ctx, doc, globals_ref, fz_jbig2_globals_data(ctx, cp->u.jbig2.globals), 0);
595 }
596 else
597 {
598 buffer = pdf_jbig2_stream_from_file(ctx, cbuffer->buffer,
599 cp->u.jbig2.globals,
600 1);
601 if (!buffer)
602 goto unknown_compression;
603 }
604 pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(JBIG2Decode));
605 break;
606 case FZ_IMAGE_FAX:
607 if (cp->u.fax.columns)
608 pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.fax.columns);
609 if (cp->u.fax.rows)
610 pdf_dict_put_int(ctx, dp, PDF_NAME(Rows), cp->u.fax.rows);
611 if (cp->u.fax.k)
612 pdf_dict_put_int(ctx, dp, PDF_NAME(K), cp->u.fax.k);
613 if (cp->u.fax.end_of_line)
614 pdf_dict_put_bool(ctx, dp, PDF_NAME(EndOfLine), cp->u.fax.end_of_line);
615 if (cp->u.fax.encoded_byte_align)
616 pdf_dict_put_bool(ctx, dp, PDF_NAME(EncodedByteAlign), cp->u.fax.encoded_byte_align);
617 if (cp->u.fax.end_of_block)
618 pdf_dict_put_bool(ctx, dp, PDF_NAME(EndOfBlock), cp->u.fax.end_of_block);
619 if (cp->u.fax.black_is_1)
620 pdf_dict_put_bool(ctx, dp, PDF_NAME(BlackIs1), cp->u.fax.black_is_1);
621 if (cp->u.fax.damaged_rows_before_error)
622 pdf_dict_put_int(ctx, dp, PDF_NAME(DamagedRowsBeforeError), cp->u.fax.damaged_rows_before_error);
623 pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(CCITTFaxDecode));
624 break;
625 case FZ_IMAGE_FLATE:
626 if (cp->u.flate.columns)
627 pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.flate.columns);
628 if (cp->u.flate.colors)
629 pdf_dict_put_int(ctx, dp, PDF_NAME(Colors), cp->u.flate.colors);
630 if (cp->u.flate.predictor)
631 pdf_dict_put_int(ctx, dp, PDF_NAME(Predictor), cp->u.flate.predictor);
632 if (cp->u.flate.bpc)
633 pdf_dict_put_int(ctx, dp, PDF_NAME(BitsPerComponent), cp->u.flate.bpc);
634 pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(FlateDecode));
635 break;
636 case FZ_IMAGE_BROTLI:
637 if (cp->u.brotli.columns)
638 pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.brotli.columns);
639 if (cp->u.brotli.colors)
640 pdf_dict_put_int(ctx, dp, PDF_NAME(Colors), cp->u.brotli.colors);
641 if (cp->u.brotli.predictor)
642 pdf_dict_put_int(ctx, dp, PDF_NAME(Predictor), cp->u.brotli.predictor);
643 if (cp->u.brotli.bpc)
644 pdf_dict_put_int(ctx, dp, PDF_NAME(BitsPerComponent), cp->u.brotli.bpc);
645 pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(BrotliDecode));
646 break;
647 case FZ_IMAGE_LZW:
648 if (cp->u.lzw.columns)
649 pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.lzw.columns);
650 if (cp->u.lzw.colors)
651 pdf_dict_put_int(ctx, dp, PDF_NAME(Colors), cp->u.lzw.colors);
652 if (cp->u.lzw.predictor)
653 pdf_dict_put_int(ctx, dp, PDF_NAME(Predictor), cp->u.lzw.predictor);
654 if (cp->u.lzw.early_change)
655 pdf_dict_put_int(ctx, dp, PDF_NAME(EarlyChange), cp->u.lzw.early_change);
656 if (cp->u.lzw.bpc)
657 pdf_dict_put_int(ctx, dp, PDF_NAME(BitsPerComponent), cp->u.lzw.bpc);
658 pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(LZWDecode));
659 break;
660 case FZ_IMAGE_RLD:
661 pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(RunLengthDecode));
662 break;
663 }
664
665 if (!pdf_dict_len(ctx, dp))
666 pdf_dict_del(ctx, imobj, PDF_NAME(DecodeParms));
667
668 pdf_dict_put_int(ctx, imobj, PDF_NAME(BitsPerComponent), image->bpc);
669 pdf_dict_put_int(ctx, imobj, PDF_NAME(Width), image->w);
670 pdf_dict_put_int(ctx, imobj, PDF_NAME(Height), image->h);
671
672 if (!buffer)
673 buffer = fz_keep_buffer(ctx, cbuffer->buffer);
674
675 if (image->use_decode)
676 {
677 pdf_obj *ary = pdf_dict_put_array(ctx, imobj, PDF_NAME(Decode), image->n * 2);
678 for (i = 0; i < image->n * 2; ++i)
679 pdf_array_push_real(ctx, ary, image->decode[i]);
680 }
681 }
682 else
683 {
684 unknown_compression:
685
686 pixmap = fz_get_pixmap_from_image(ctx, image, NULL, NULL, NULL, NULL);
687 n = pixmap->n - pixmap->alpha - pixmap->s; /* number of colorants */
688 if (n == 0)
689 n = 1; /* treat pixmaps with only alpha or spots as grayscale */
690
691 pdf_dict_put_int(ctx, imobj, PDF_NAME(Width), pixmap->w);
692 pdf_dict_put_int(ctx, imobj, PDF_NAME(Height), pixmap->h);
693
694 if (fz_is_pixmap_monochrome(ctx, pixmap))
695 {
696 int stride = (image->w + 7) / 8;
697 int h = pixmap->h;
698 int w = pixmap->w;
699 unsigned char *s = pixmap->samples;
700 unsigned char *d = fz_calloc(ctx, h, stride);
701 buffer = fz_new_buffer_from_data(ctx, d, (size_t)h * stride);
702
703 pdf_dict_put_int(ctx, imobj, PDF_NAME(BitsPerComponent), 1);
704
705 while (h--)
706 {
707 int x;
708 for (x = 0; x < w; ++x)
709 if (s[x] > 0)
710 d[x>>3] |= 1 << (7 - (x & 7));
711 s += pixmap->stride;
712 d += stride;
713 }
714 }
715 else
716 {
717 size_t size = (size_t)pixmap->w * n;
718 int h = pixmap->h;
719 unsigned char *s = pixmap->samples;
720 unsigned char *d = Memento_label(fz_malloc(ctx, size * h), "pdf_image_samples");
721 buffer = fz_new_buffer_from_data(ctx, d, size * h);
722
723 pdf_dict_put_int(ctx, imobj, PDF_NAME(BitsPerComponent), 8);
724
725 if (n == pixmap->n)
726 {
727 /* If we use all channels, we can copy the data as is. */
728 while (h--)
729 {
730 memcpy(d, s, size);
731 d += size;
732 s += pixmap->stride;
733 }
734 }
735 else
736 {
737 size_t line_skip;
738 int skip;
739
740 /* Need to extract the alpha into a SMask and remove spot planes. */
741 /* TODO: convert spots to colors. */
742
743 if (pixmap->alpha && !image->mask)
744 {
745 smask_pixmap = fz_new_pixmap_from_alpha_channel(ctx, pixmap);
746 smask_image = fz_new_image_from_pixmap(ctx, smask_pixmap, NULL);
747 pdf_dict_put_drop(ctx, imobj, PDF_NAME(SMask), pdf_add_image(ctx, doc, smask_image));
748 fz_drop_image(ctx, smask_image);
749 smask_image = NULL;
750 fz_drop_pixmap(ctx, smask_pixmap);
751 smask_pixmap = NULL;
752 }
753
754 line_skip = pixmap->stride - pixmap->w * (size_t)pixmap->n;
755 skip = pixmap->n - n;
756 if (pixmap->alpha)
757 {
758 int n1 = pixmap->n-1;
759 while (h--)
760 {
761 int w = pixmap->w;
762 while (w--)
763 {
764 int a = s[n1];
765 int inva = a ? 255 * 256 / a : 0;
766 int k;
767 for (k = 0; k < n; k++)
768 *d++ = (*s++ * inva) >> 8;
769 s += skip;
770 }
771 s += line_skip;
772 }
773 }
774 else
775 {
776 while (h--)
777 {
778 int w = pixmap->w;
779 while (w--)
780 {
781 int k;
782 for (k = 0; k < n; ++k)
783 *d++ = *s++;
784 s += skip;
785 }
786 s += line_skip;
787 }
788 }
789 }
790 }
791 }
792
793 if (image->imagemask)
794 {
795 pdf_dict_put_bool(ctx, imobj, PDF_NAME(ImageMask), 1);
796 }
797 else
798 {
799 fz_colorspace *cs = pixmap ? pixmap->colorspace : image->colorspace;
800 pdf_dict_put_drop(ctx, imobj, PDF_NAME(ColorSpace), pdf_add_colorspace(ctx, doc, cs));
801 }
802
803 if (image->mask)
804 {
805 if (image->mask->imagemask)
806 pdf_dict_put_drop(ctx, imobj, PDF_NAME(Mask), pdf_add_image(ctx, doc, image->mask));
807 else
808 pdf_dict_put_drop(ctx, imobj, PDF_NAME(SMask), pdf_add_image(ctx, doc, image->mask));
809 }
810
811 pdf_update_stream(ctx, doc, imobj, buffer, 1);
812 pdf_end_operation(ctx, doc);
813 }
814 fz_always(ctx)
815 {
816 fz_drop_image(ctx, smask_image);
817 fz_drop_pixmap(ctx, smask_pixmap);
818 fz_drop_pixmap(ctx, pixmap);
819 fz_drop_buffer(ctx, buffer);
820 }
821 fz_catch(ctx)
822 {
823 pdf_drop_obj(ctx, imobj);
824 pdf_abandon_operation(ctx, doc);
825 fz_rethrow(ctx);
826 }
827 return imobj;
828 }