| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- // Copyright (C) 2004-2025 Artifex Software, Inc.
- //
- // This file is part of MuPDF.
- //
- // MuPDF is free software: you can redistribute it and/or modify it under the
- // terms of the GNU Affero General Public License as published by the Free
- // Software Foundation, either version 3 of the License, or (at your option)
- // any later version.
- //
- // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
- // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
- // details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
- //
- // Alternative licensing terms are available from the licensor.
- // For commercial licensing, see <https://www.artifex.com/> or contact
- // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
- // CA 94129, USA, for further information.
- #include "mupdf/fitz.h"
- #include "mupdf/pdf.h"
- #include <string.h>
- static fz_image *pdf_load_jpx(fz_context *ctx, pdf_document *doc, pdf_obj *dict, int forcemask);
- static fz_image *
- pdf_load_jpx_imp(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask)
- {
- fz_image *image = pdf_load_jpx(ctx, doc, dict, forcemask);
- if (forcemask)
- {
- fz_pixmap_image *cimg = (fz_pixmap_image *)image;
- fz_pixmap *mask_pixmap;
- fz_pixmap *tile = fz_pixmap_image_tile(ctx, cimg);
- if (tile->n != 1)
- {
- fz_pixmap *gray = fz_convert_pixmap(ctx, tile, fz_device_gray(ctx), NULL, NULL, fz_default_color_params, 0);
- fz_drop_pixmap(ctx, tile);
- tile = gray;
- }
- mask_pixmap = fz_alpha_from_gray(ctx, tile);
- fz_drop_pixmap(ctx, tile);
- fz_set_pixmap_image_tile(ctx, cimg, mask_pixmap);
- }
- return image;
- }
- static fz_image *
- pdf_load_image_imp(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *cstm, int forcemask)
- {
- fz_image *image = NULL;
- pdf_obj *obj, *res;
- int w, h, bpc, n;
- int imagemask;
- int interpolate;
- int indexed;
- fz_image *mask = NULL; /* explicit mask/soft mask image */
- int use_colorkey = 0;
- fz_colorspace *colorspace = NULL;
- float decode[FZ_MAX_COLORS * 2];
- int colorkey[FZ_MAX_COLORS * 2];
- int stride;
- pdf_obj *intent;
- int i;
- fz_compressed_buffer *buffer;
- /* special case for JPEG2000 images */
- if (pdf_is_jpx_image(ctx, dict))
- return pdf_load_jpx_imp(ctx, doc, rdb, dict, cstm, forcemask);
- w = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Width), PDF_NAME(W)));
- h = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Height), PDF_NAME(H)));
- bpc = pdf_to_int(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(BitsPerComponent), PDF_NAME(BPC)));
- if (bpc == 0)
- bpc = 8;
- imagemask = pdf_to_bool(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(ImageMask), PDF_NAME(IM)));
- interpolate = pdf_to_bool(ctx, pdf_dict_geta(ctx, dict, PDF_NAME(Interpolate), PDF_NAME(I)));
- intent = pdf_dict_get(ctx, dict, PDF_NAME(Intent));
- indexed = 0;
- use_colorkey = 0;
- if (imagemask)
- bpc = 1;
- if (w <= 0)
- fz_throw(ctx, FZ_ERROR_SYNTAX, "image width is zero (or less)");
- if (h <= 0)
- fz_throw(ctx, FZ_ERROR_SYNTAX, "image height is zero (or less)");
- if (bpc <= 0)
- fz_throw(ctx, FZ_ERROR_SYNTAX, "image depth is zero (or less)");
- if (bpc > 16)
- fz_throw(ctx, FZ_ERROR_SYNTAX, "image depth is too large: %d", bpc);
- if (SIZE_MAX / w < (size_t)(bpc+7)/8)
- fz_throw(ctx, FZ_ERROR_SYNTAX, "image is too large");
- if (SIZE_MAX / h < w * (size_t)((bpc+7)/8))
- fz_throw(ctx, FZ_ERROR_SYNTAX, "image is too large");
- fz_var(mask);
- fz_var(image);
- fz_var(colorspace);
- fz_try(ctx)
- {
- obj = pdf_dict_geta(ctx, dict, PDF_NAME(ColorSpace), PDF_NAME(CS));
- if (obj && !imagemask && !forcemask)
- {
- /* colorspace resource lookup is only done for inline images */
- if (pdf_is_name(ctx, obj))
- {
- res = pdf_dict_get(ctx, pdf_dict_get(ctx, rdb, PDF_NAME(ColorSpace)), obj);
- if (res)
- obj = res;
- }
- colorspace = pdf_load_colorspace(ctx, obj);
- indexed = fz_colorspace_is_indexed(ctx, colorspace);
- n = fz_colorspace_n(ctx, colorspace);
- }
- else
- {
- n = 1;
- }
- if (SIZE_MAX / n < h * ((size_t)w) * ((bpc+7)/8))
- fz_throw(ctx, FZ_ERROR_SYNTAX, "image is too large");
- obj = pdf_dict_geta(ctx, dict, PDF_NAME(Decode), PDF_NAME(D));
- if (obj)
- {
- for (i = 0; i < n * 2; i++)
- decode[i] = pdf_array_get_real(ctx, obj, i);
- }
- else if (fz_colorspace_is_lab(ctx, colorspace))
- {
- decode[0] = 0;
- decode[1] = 100;
- decode[2] = -128;
- decode[3] = 127;
- decode[4] = -128;
- decode[5] = 127;
- }
- else
- {
- float maxval = indexed ? (1 << bpc) - 1 : 1;
- for (i = 0; i < n * 2; i++)
- decode[i] = i & 1 ? maxval : 0;
- }
- obj = pdf_dict_get(ctx, dict, PDF_NAME(SMask));
- if (!pdf_is_dict(ctx, obj))
- obj = pdf_dict_get(ctx, dict, PDF_NAME(Mask));
- if (pdf_is_dict(ctx, obj))
- {
- /* Not allowed for inline images or soft masks */
- if (cstm)
- fz_warn(ctx, "Ignoring invalid inline image soft mask");
- else if (forcemask)
- fz_warn(ctx, "Ignoring recursive image soft mask");
- else
- {
- mask = pdf_load_image_imp(ctx, doc, rdb, obj, NULL, 1);
- obj = pdf_dict_get(ctx, obj, PDF_NAME(Matte));
- if (pdf_is_array(ctx, obj))
- {
- use_colorkey = 1;
- for (i = 0; i < n; i++)
- colorkey[i] = fz_clamp(pdf_array_get_real(ctx, obj, i), 0, 1) * 255;
- }
- }
- }
- else if (pdf_is_array(ctx, obj))
- {
- use_colorkey = 1;
- for (i = 0; i < n * 2; i++)
- {
- if (!pdf_is_int(ctx, pdf_array_get(ctx, obj, i)))
- {
- fz_warn(ctx, "invalid value in color key mask");
- use_colorkey = 0;
- }
- colorkey[i] = pdf_array_get_int(ctx, obj, i);
- }
- }
- /* Do we load from a ref, or do we load an inline stream? */
- if (cstm == NULL)
- {
- /* Just load the compressed image data now and we can decode it on demand. */
- size_t worst_case = w * (size_t)h;
- worst_case = (worst_case * bpc + 7) >> 3;
- if (colorspace)
- worst_case *= colorspace->n;
- buffer = pdf_load_compressed_stream(ctx, doc, pdf_to_num(ctx, dict), worst_case);
- image = fz_new_image_from_compressed_buffer(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, use_colorkey ? colorkey : NULL, buffer, mask);
- }
- else
- {
- /* Inline stream */
- stride = (w * n * bpc + 7) / 8;
- image = fz_new_image_from_compressed_buffer(ctx, w, h, bpc, colorspace, 96, 96, interpolate, imagemask, decode, use_colorkey ? colorkey : NULL, NULL, mask);
- pdf_load_compressed_inline_image(ctx, doc, dict, stride * h, cstm, indexed, (fz_compressed_image *)image);
- }
- if (pdf_name_eq(ctx, intent, PDF_NAME(Perceptual)))
- image->has_intent = 1, image->intent = FZ_RI_PERCEPTUAL;
- else if (pdf_name_eq(ctx, intent, PDF_NAME(AbsoluteColorimetric)))
- image->has_intent = 1, image->intent = FZ_RI_ABSOLUTE_COLORIMETRIC;
- else if (pdf_name_eq(ctx, intent, PDF_NAME(RelativeColorimetric)))
- image->has_intent = 1, image->intent = FZ_RI_RELATIVE_COLORIMETRIC;
- else if (pdf_name_eq(ctx, intent, PDF_NAME(Saturation)))
- image->has_intent = 1, image->intent = FZ_RI_SATURATION;
- }
- fz_always(ctx)
- {
- fz_drop_colorspace(ctx, colorspace);
- fz_drop_image(ctx, mask);
- }
- fz_catch(ctx)
- {
- fz_drop_image(ctx, image);
- fz_rethrow(ctx);
- }
- return image;
- }
- fz_image *
- pdf_load_inline_image(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict, fz_stream *file)
- {
- return pdf_load_image_imp(ctx, doc, rdb, dict, file, 0);
- }
- int
- pdf_is_jpx_image(fz_context *ctx, pdf_obj *dict)
- {
- pdf_obj *filter;
- int i, n;
- filter = pdf_dict_get(ctx, dict, PDF_NAME(Filter));
- if (pdf_name_eq(ctx, filter, PDF_NAME(JPXDecode)))
- return 1;
- n = pdf_array_len(ctx, filter);
- for (i = 0; i < n; i++)
- if (pdf_name_eq(ctx, pdf_array_get(ctx, filter, i), PDF_NAME(JPXDecode)))
- return 1;
- return 0;
- }
- static fz_image *
- pdf_load_jpx(fz_context *ctx, pdf_document *doc, pdf_obj *dict, int forcemask)
- {
- fz_buffer *buf = NULL;
- fz_colorspace *colorspace = NULL;
- fz_pixmap *pix = NULL;
- pdf_obj *obj;
- fz_image *mask = NULL;
- fz_image *img = NULL;
- fz_var(pix);
- fz_var(buf);
- fz_var(colorspace);
- fz_var(mask);
- buf = pdf_load_stream(ctx, dict);
- /* FIXME: We can't handle decode arrays for indexed images currently */
- fz_try(ctx)
- {
- unsigned char *data;
- size_t len;
- obj = pdf_dict_get(ctx, dict, PDF_NAME(ColorSpace));
- if (obj)
- colorspace = pdf_load_colorspace(ctx, obj);
- len = fz_buffer_storage(ctx, buf, &data);
- pix = fz_load_jpx(ctx, data, len, colorspace);
- obj = pdf_dict_geta(ctx, dict, PDF_NAME(SMask), PDF_NAME(Mask));
- if (pdf_is_dict(ctx, obj))
- {
- if (forcemask)
- fz_warn(ctx, "Ignoring recursive JPX soft mask");
- else
- mask = pdf_load_image_imp(ctx, doc, NULL, obj, NULL, 1);
- }
- obj = pdf_dict_geta(ctx, dict, PDF_NAME(Decode), PDF_NAME(D));
- if (obj && !fz_colorspace_is_indexed(ctx, colorspace))
- {
- float decode[FZ_MAX_COLORS * 2];
- int i;
- for (i = 0; i < pix->n * 2; i++)
- decode[i] = pdf_array_get_real(ctx, obj, i);
- fz_decode_tile(ctx, pix, decode);
- }
- img = fz_new_image_from_pixmap(ctx, pix, mask);
- }
- fz_always(ctx)
- {
- fz_drop_image(ctx, mask);
- fz_drop_pixmap(ctx, pix);
- fz_drop_colorspace(ctx, colorspace);
- fz_drop_buffer(ctx, buf);
- }
- fz_catch(ctx)
- {
- fz_morph_error(ctx, FZ_ERROR_FORMAT, FZ_ERROR_SYNTAX);
- fz_morph_error(ctx, FZ_ERROR_LIBRARY, FZ_ERROR_SYNTAX);
- fz_rethrow(ctx);
- }
- return img;
- }
- fz_image *
- pdf_load_image(fz_context *ctx, pdf_document *doc, pdf_obj *dict)
- {
- fz_image *image;
- if ((image = pdf_find_item(ctx, fz_drop_image_imp, dict)) != NULL)
- return image;
- image = pdf_load_image_imp(ctx, doc, NULL, dict, NULL, 0);
- pdf_store_item(ctx, dict, image, fz_image_size(ctx, image));
- return image;
- }
- struct jbig2_segment_header {
- int number;
- int flags;
- /* referred-to-segment numbers */
- int page;
- uint32_t length;
- };
- /* coverity[-tainted_data_return] */
- static uint32_t getu32(const unsigned char *data)
- {
- return ((uint32_t)data[0]<<24) | ((uint32_t)data[1]<<16) | ((uint32_t)data[2]<<8) | (uint32_t)data[3];
- }
- static size_t
- pdf_parse_jbig2_segment_header(fz_context *ctx,
- const unsigned char *data, const unsigned char *end,
- struct jbig2_segment_header *info)
- {
- uint32_t rts;
- size_t n = 5;
- if (data + 11 > end) return 0;
- info->number = getu32(data);
- info->flags = data[4];
- rts = (data[5] >> 5) & 0x7;
- if (rts == 7)
- {
- rts = getu32(data+5) & 0x1FFFFFFF;
- n += 4 + (rts + 1) / 8;
- }
- else
- {
- n += 1;
- }
- if (info->number <= 256)
- n += rts;
- else if (info->number <= 65536)
- n += rts * 2;
- else
- n += rts * 4;
- if (info->flags & 0x40)
- {
- if (data + n + 4 > end) return 0;
- info->page = getu32(data+n);
- n += 4;
- }
- else
- {
- if (data + n + 1 > end) return 0;
- info->page = data[n];
- n += 1;
- }
- if (data + n + 4 > end) return 0;
- info->length = getu32(data+n);
- return n + 4;
- }
- static void
- pdf_copy_jbig2_segments(fz_context *ctx, fz_buffer *output, const unsigned char *data, size_t size, int page)
- {
- struct jbig2_segment_header info;
- const unsigned char *end = data + size;
- size_t n;
- int type;
- while (data < end)
- {
- n = pdf_parse_jbig2_segment_header(ctx, data, end, &info);
- if (n == 0)
- fz_throw(ctx, FZ_ERROR_FORMAT, "truncated jbig2 segment header");
- /* omit end of page, end of file, and segments for other pages */
- type = (info.flags & 63);
- if (type == 49 || type == 51 || (info.page > 0 && info.page != page))
- {
- data += n;
- data += info.length;
- }
- else
- {
- fz_append_data(ctx, output, data, n);
- data += n;
- if (data + info.length > end)
- fz_throw(ctx, FZ_ERROR_FORMAT, "truncated jbig2 segment data");
- fz_append_data(ctx, output, data, info.length);
- data += info.length;
- }
- }
- }
- static void
- pdf_copy_jbig2_random_segments(fz_context *ctx, fz_buffer *output, const unsigned char *data, size_t size, int page)
- {
- struct jbig2_segment_header info;
- const unsigned char *header = data;
- const unsigned char *header_end;
- const unsigned char *end = data + size;
- size_t n;
- int type;
- /* Skip headers until end-of-file segment is found. */
- while (data < end)
- {
- n = pdf_parse_jbig2_segment_header(ctx, data, end, &info);
- if (n == 0)
- fz_throw(ctx, FZ_ERROR_FORMAT, "truncated jbig2 segment header");
- data += n;
- if ((info.flags & 63) == 51)
- break;
- }
- if (data >= end)
- fz_throw(ctx, FZ_ERROR_FORMAT, "truncated jbig2 segment header");
- /* Copy segment headers and segment data */
- header_end = data;
- while (data < end && header < header_end)
- {
- n = pdf_parse_jbig2_segment_header(ctx, header, header_end, &info);
- if (n == 0)
- fz_throw(ctx, FZ_ERROR_FORMAT, "truncated jbig2 segment header");
- /* omit end of page, end of file, and segments for other pages */
- type = (info.flags & 63);
- if (type == 49 || type == 51 || (info.page > 0 && info.page != page))
- {
- header += n;
- data += info.length;
- }
- else
- {
- fz_append_data(ctx, output, header, n);
- header += n;
- if (data + info.length > end)
- fz_throw(ctx, FZ_ERROR_FORMAT, "truncated jbig2 segment data");
- fz_append_data(ctx, output, data, info.length);
- data += info.length;
- }
- }
- }
- static fz_buffer *
- pdf_jbig2_stream_from_file(fz_context *ctx, fz_buffer *input, fz_jbig2_globals *globals_, int page)
- {
- fz_buffer *globals = fz_jbig2_globals_data(ctx, globals_);
- size_t globals_size = globals ? globals->len : 0;
- fz_buffer *output;
- int flags;
- size_t header = 9;
- if (input->len < 9)
- return NULL; /* not enough data! */
- flags = input->data[8];
- if ((flags & 2) == 0)
- {
- if (input->len < 13)
- return NULL; /* not enough data! */
- header = 13;
- }
- output = fz_new_buffer(ctx, input->len + globals_size);
- fz_try(ctx)
- {
- if (globals_size > 0)
- fz_append_buffer(ctx, output, globals);
- if ((flags & 1) == 0)
- pdf_copy_jbig2_random_segments(ctx, output, input->data + header, input->len - header, page);
- else
- pdf_copy_jbig2_segments(ctx, output, input->data + header, input->len - header, page);
- }
- fz_catch(ctx)
- {
- fz_drop_buffer(ctx, output);
- fz_rethrow(ctx);
- }
- return output;
- }
- pdf_obj *
- pdf_add_image(fz_context *ctx, pdf_document *doc, fz_image *image)
- {
- fz_pixmap *pixmap = NULL;
- pdf_obj *imobj = NULL;
- pdf_obj *dp;
- fz_buffer *buffer = NULL;
- fz_compressed_buffer *cbuffer;
- fz_pixmap *smask_pixmap = NULL;
- fz_image *smask_image = NULL;
- int i, n;
- fz_var(pixmap);
- fz_var(buffer);
- fz_var(imobj);
- fz_var(smask_pixmap);
- fz_var(smask_image);
- pdf_begin_operation(ctx, doc, "Add image");
- fz_try(ctx)
- {
- /* If we can maintain compression, do so */
- cbuffer = fz_compressed_image_buffer(ctx, image);
- imobj = pdf_add_new_dict(ctx, doc, 3);
- dp = pdf_dict_put_dict(ctx, imobj, PDF_NAME(DecodeParms), 3);
- pdf_dict_put(ctx, imobj, PDF_NAME(Type), PDF_NAME(XObject));
- pdf_dict_put(ctx, imobj, PDF_NAME(Subtype), PDF_NAME(Image));
- if (cbuffer)
- {
- fz_compression_params *cp = &cbuffer->params;
- switch (cp->type)
- {
- default:
- goto unknown_compression;
- case FZ_IMAGE_RAW:
- break;
- case FZ_IMAGE_JPEG:
- pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(DCTDecode));
- if (cp->u.jpeg.color_transform >= 0)
- pdf_dict_put_int(ctx, dp, PDF_NAME(ColorTransform), cp->u.jpeg.color_transform);
- if (cp->u.jpeg.invert_cmyk && image->n == 4)
- {
- pdf_obj *arr;
- arr = pdf_dict_put_array(ctx, imobj, PDF_NAME(Decode), 8);
- pdf_array_push_int(ctx, arr, 1);
- pdf_array_push_int(ctx, arr, 0);
- pdf_array_push_int(ctx, arr, 1);
- pdf_array_push_int(ctx, arr, 0);
- pdf_array_push_int(ctx, arr, 1);
- pdf_array_push_int(ctx, arr, 0);
- pdf_array_push_int(ctx, arr, 1);
- pdf_array_push_int(ctx, arr, 0);
- }
- break;
- case FZ_IMAGE_JPX:
- if (cp->u.jpx.smask_in_data)
- pdf_dict_put_int(ctx, dp, PDF_NAME(SMaskInData), cp->u.jpx.smask_in_data);
- pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(JPXDecode));
- break;
- case FZ_IMAGE_JBIG2:
- if (cp->u.jbig2.embedded && cp->u.jbig2.globals)
- {
- pdf_obj *globals_ref = pdf_add_new_dict(ctx, doc, 1);
- pdf_dict_put_drop(ctx, dp, PDF_NAME(JBIG2Globals), globals_ref);
- pdf_update_stream(ctx, doc, globals_ref, fz_jbig2_globals_data(ctx, cp->u.jbig2.globals), 0);
- }
- else
- {
- buffer = pdf_jbig2_stream_from_file(ctx, cbuffer->buffer,
- cp->u.jbig2.globals,
- 1);
- if (!buffer)
- goto unknown_compression;
- }
- pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(JBIG2Decode));
- break;
- case FZ_IMAGE_FAX:
- if (cp->u.fax.columns)
- pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.fax.columns);
- if (cp->u.fax.rows)
- pdf_dict_put_int(ctx, dp, PDF_NAME(Rows), cp->u.fax.rows);
- if (cp->u.fax.k)
- pdf_dict_put_int(ctx, dp, PDF_NAME(K), cp->u.fax.k);
- if (cp->u.fax.end_of_line)
- pdf_dict_put_bool(ctx, dp, PDF_NAME(EndOfLine), cp->u.fax.end_of_line);
- if (cp->u.fax.encoded_byte_align)
- pdf_dict_put_bool(ctx, dp, PDF_NAME(EncodedByteAlign), cp->u.fax.encoded_byte_align);
- if (cp->u.fax.end_of_block)
- pdf_dict_put_bool(ctx, dp, PDF_NAME(EndOfBlock), cp->u.fax.end_of_block);
- if (cp->u.fax.black_is_1)
- pdf_dict_put_bool(ctx, dp, PDF_NAME(BlackIs1), cp->u.fax.black_is_1);
- if (cp->u.fax.damaged_rows_before_error)
- pdf_dict_put_int(ctx, dp, PDF_NAME(DamagedRowsBeforeError), cp->u.fax.damaged_rows_before_error);
- pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(CCITTFaxDecode));
- break;
- case FZ_IMAGE_FLATE:
- if (cp->u.flate.columns)
- pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.flate.columns);
- if (cp->u.flate.colors)
- pdf_dict_put_int(ctx, dp, PDF_NAME(Colors), cp->u.flate.colors);
- if (cp->u.flate.predictor)
- pdf_dict_put_int(ctx, dp, PDF_NAME(Predictor), cp->u.flate.predictor);
- if (cp->u.flate.bpc)
- pdf_dict_put_int(ctx, dp, PDF_NAME(BitsPerComponent), cp->u.flate.bpc);
- pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(FlateDecode));
- break;
- case FZ_IMAGE_BROTLI:
- if (cp->u.brotli.columns)
- pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.brotli.columns);
- if (cp->u.brotli.colors)
- pdf_dict_put_int(ctx, dp, PDF_NAME(Colors), cp->u.brotli.colors);
- if (cp->u.brotli.predictor)
- pdf_dict_put_int(ctx, dp, PDF_NAME(Predictor), cp->u.brotli.predictor);
- if (cp->u.brotli.bpc)
- pdf_dict_put_int(ctx, dp, PDF_NAME(BitsPerComponent), cp->u.brotli.bpc);
- pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(BrotliDecode));
- break;
- case FZ_IMAGE_LZW:
- if (cp->u.lzw.columns)
- pdf_dict_put_int(ctx, dp, PDF_NAME(Columns), cp->u.lzw.columns);
- if (cp->u.lzw.colors)
- pdf_dict_put_int(ctx, dp, PDF_NAME(Colors), cp->u.lzw.colors);
- if (cp->u.lzw.predictor)
- pdf_dict_put_int(ctx, dp, PDF_NAME(Predictor), cp->u.lzw.predictor);
- if (cp->u.lzw.early_change)
- pdf_dict_put_int(ctx, dp, PDF_NAME(EarlyChange), cp->u.lzw.early_change);
- if (cp->u.lzw.bpc)
- pdf_dict_put_int(ctx, dp, PDF_NAME(BitsPerComponent), cp->u.lzw.bpc);
- pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(LZWDecode));
- break;
- case FZ_IMAGE_RLD:
- pdf_dict_put(ctx, imobj, PDF_NAME(Filter), PDF_NAME(RunLengthDecode));
- break;
- }
- if (!pdf_dict_len(ctx, dp))
- pdf_dict_del(ctx, imobj, PDF_NAME(DecodeParms));
- pdf_dict_put_int(ctx, imobj, PDF_NAME(BitsPerComponent), image->bpc);
- pdf_dict_put_int(ctx, imobj, PDF_NAME(Width), image->w);
- pdf_dict_put_int(ctx, imobj, PDF_NAME(Height), image->h);
- if (!buffer)
- buffer = fz_keep_buffer(ctx, cbuffer->buffer);
- if (image->use_decode)
- {
- pdf_obj *ary = pdf_dict_put_array(ctx, imobj, PDF_NAME(Decode), image->n * 2);
- for (i = 0; i < image->n * 2; ++i)
- pdf_array_push_real(ctx, ary, image->decode[i]);
- }
- }
- else
- {
- unknown_compression:
- pixmap = fz_get_pixmap_from_image(ctx, image, NULL, NULL, NULL, NULL);
- n = pixmap->n - pixmap->alpha - pixmap->s; /* number of colorants */
- if (n == 0)
- n = 1; /* treat pixmaps with only alpha or spots as grayscale */
- pdf_dict_put_int(ctx, imobj, PDF_NAME(Width), pixmap->w);
- pdf_dict_put_int(ctx, imobj, PDF_NAME(Height), pixmap->h);
- if (fz_is_pixmap_monochrome(ctx, pixmap))
- {
- int stride = (image->w + 7) / 8;
- int h = pixmap->h;
- int w = pixmap->w;
- unsigned char *s = pixmap->samples;
- unsigned char *d = fz_calloc(ctx, h, stride);
- buffer = fz_new_buffer_from_data(ctx, d, (size_t)h * stride);
- pdf_dict_put_int(ctx, imobj, PDF_NAME(BitsPerComponent), 1);
- while (h--)
- {
- int x;
- for (x = 0; x < w; ++x)
- if (s[x] > 0)
- d[x>>3] |= 1 << (7 - (x & 7));
- s += pixmap->stride;
- d += stride;
- }
- }
- else
- {
- size_t size = (size_t)pixmap->w * n;
- int h = pixmap->h;
- unsigned char *s = pixmap->samples;
- unsigned char *d = Memento_label(fz_malloc(ctx, size * h), "pdf_image_samples");
- buffer = fz_new_buffer_from_data(ctx, d, size * h);
- pdf_dict_put_int(ctx, imobj, PDF_NAME(BitsPerComponent), 8);
- if (n == pixmap->n)
- {
- /* If we use all channels, we can copy the data as is. */
- while (h--)
- {
- memcpy(d, s, size);
- d += size;
- s += pixmap->stride;
- }
- }
- else
- {
- size_t line_skip;
- int skip;
- /* Need to extract the alpha into a SMask and remove spot planes. */
- /* TODO: convert spots to colors. */
- if (pixmap->alpha && !image->mask)
- {
- smask_pixmap = fz_new_pixmap_from_alpha_channel(ctx, pixmap);
- smask_image = fz_new_image_from_pixmap(ctx, smask_pixmap, NULL);
- pdf_dict_put_drop(ctx, imobj, PDF_NAME(SMask), pdf_add_image(ctx, doc, smask_image));
- fz_drop_image(ctx, smask_image);
- smask_image = NULL;
- fz_drop_pixmap(ctx, smask_pixmap);
- smask_pixmap = NULL;
- }
- line_skip = pixmap->stride - pixmap->w * (size_t)pixmap->n;
- skip = pixmap->n - n;
- if (pixmap->alpha)
- {
- int n1 = pixmap->n-1;
- while (h--)
- {
- int w = pixmap->w;
- while (w--)
- {
- int a = s[n1];
- int inva = a ? 255 * 256 / a : 0;
- int k;
- for (k = 0; k < n; k++)
- *d++ = (*s++ * inva) >> 8;
- s += skip;
- }
- s += line_skip;
- }
- }
- else
- {
- while (h--)
- {
- int w = pixmap->w;
- while (w--)
- {
- int k;
- for (k = 0; k < n; ++k)
- *d++ = *s++;
- s += skip;
- }
- s += line_skip;
- }
- }
- }
- }
- }
- if (image->imagemask)
- {
- pdf_dict_put_bool(ctx, imobj, PDF_NAME(ImageMask), 1);
- }
- else
- {
- fz_colorspace *cs = pixmap ? pixmap->colorspace : image->colorspace;
- pdf_dict_put_drop(ctx, imobj, PDF_NAME(ColorSpace), pdf_add_colorspace(ctx, doc, cs));
- }
- if (image->mask)
- {
- if (image->mask->imagemask)
- pdf_dict_put_drop(ctx, imobj, PDF_NAME(Mask), pdf_add_image(ctx, doc, image->mask));
- else
- pdf_dict_put_drop(ctx, imobj, PDF_NAME(SMask), pdf_add_image(ctx, doc, image->mask));
- }
- pdf_update_stream(ctx, doc, imobj, buffer, 1);
- pdf_end_operation(ctx, doc);
- }
- fz_always(ctx)
- {
- fz_drop_image(ctx, smask_image);
- fz_drop_pixmap(ctx, smask_pixmap);
- fz_drop_pixmap(ctx, pixmap);
- fz_drop_buffer(ctx, buffer);
- }
- fz_catch(ctx)
- {
- pdf_drop_obj(ctx, imobj);
- pdf_abandon_operation(ctx, doc);
- fz_rethrow(ctx);
- }
- return imobj;
- }
|