Mercurial > hgrepos > Python2 > PyMuPDF
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 } |
