/* * Construct a filter to decode a stream, constraining * to stream length and decrypting. */ static fz_stream * pdf_open_filter(fz_stream *chain, pdf_xref *xref, fz_obj *stmobj, int num, int gen) { fz_obj *filters; fz_obj *params; filters = fz_dict_getsa(stmobj, "Filter", "F"); params = fz_dict_getsa(stmobj, "DecodeParms", "DP"); chain = pdf_open_raw_filter(chain, xref, stmobj, num, gen); if (fz_is_name(filters)) return build_filter(chain, xref, filters, params, num, gen); if (fz_array_len(filters) > 0) return build_filter_chain(chain, xref, filters, params, num, gen); return chain; }
/* * Construct a filter to decode a stream, without * constraining to stream length, and without decryption. */ fz_stream * pdf_open_inline_stream(fz_stream *chain, pdf_xref *xref, fz_obj *stmobj, int length) { fz_obj *filters; fz_obj *params; filters = fz_dict_getsa(stmobj, "Filter", "F"); params = fz_dict_getsa(stmobj, "DecodeParms", "DP"); /* don't close chain when we close this filter */ fz_keep_stream(chain); if (fz_is_name(filters)) return build_filter(chain, xref, filters, params, 0, 0); if (fz_array_len(filters) > 0) return build_filter_chain(chain, xref, filters, params, 0, 0); return fz_open_null(chain, length); }
static fz_error pdf_load_jpx_image(fz_pixmap **imgp, pdf_xref *xref, fz_obj *dict) { fz_error error; fz_buffer *buf; fz_colorspace *colorspace; fz_pixmap *img; fz_obj *obj; colorspace = NULL; error = pdf_load_stream(&buf, xref, fz_to_num(dict), fz_to_gen(dict)); if (error) return fz_rethrow(error, "cannot load jpx image data"); obj = fz_dict_gets(dict, "ColorSpace"); if (obj) { error = pdf_load_colorspace(&colorspace, xref, obj); if (error) fz_catch(error, "cannot load image colorspace"); } error = fz_load_jpx_image(&img, buf->data, buf->len, colorspace); if (error) { if (colorspace) fz_drop_colorspace(colorspace); fz_drop_buffer(buf); return fz_rethrow(error, "cannot load jpx image"); } if (colorspace) fz_drop_colorspace(colorspace); fz_drop_buffer(buf); obj = fz_dict_getsa(dict, "SMask", "Mask"); if (fz_is_dict(obj)) { error = pdf_load_image_imp(&img->mask, xref, NULL, obj, NULL, 1); if (error) { fz_drop_pixmap(img); return fz_rethrow(error, "cannot load image mask/softmask"); } } *imgp = img; return fz_okay; }
/* * Scan stream dictionary for an explicit /Crypt filter */ static int pdf_stream_has_crypt(fz_obj *stm) { fz_obj *filters; fz_obj *obj; int i; filters = fz_dict_getsa(stm, "Filter", "F"); if (filters) { if (!strcmp(fz_to_name(filters), "Crypt")) return 1; if (fz_is_array(filters)) { for (i = 0; i < fz_array_len(filters); i++) { obj = fz_array_get(filters, i); if (!strcmp(fz_to_name(obj), "Crypt")) return 1; } } } return 0; }
static fz_error pdf_load_image_imp(fz_pixmap **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cstm, int forcemask) { fz_stream *stm; fz_pixmap *tile; fz_obj *obj, *res; fz_error error; int w, h, bpc, n; int imagemask; int interpolate; int indexed; fz_colorspace *colorspace; fz_pixmap *mask; /* explicit mask/softmask image */ int usecolorkey; int colorkey[FZ_MAX_COLORS * 2]; float decode[FZ_MAX_COLORS * 2]; int stride; unsigned char *samples; int i, len; /* special case for JPEG2000 images */ if (pdf_is_jpx_image(dict)) { tile = NULL; error = pdf_load_jpx_image(&tile, xref, dict); if (error) return fz_rethrow(error, "cannot load jpx image"); if (forcemask) { if (tile->n != 2) { fz_drop_pixmap(tile); return fz_throw("softmask must be grayscale"); } mask = fz_alpha_from_gray(tile, 1); fz_drop_pixmap(tile); *imgp = mask; return fz_okay; } *imgp = tile; return fz_okay; } w = fz_to_int(fz_dict_getsa(dict, "Width", "W")); h = fz_to_int(fz_dict_getsa(dict, "Height", "H")); bpc = fz_to_int(fz_dict_getsa(dict, "BitsPerComponent", "BPC")); imagemask = fz_to_bool(fz_dict_getsa(dict, "ImageMask", "IM")); interpolate = fz_to_bool(fz_dict_getsa(dict, "Interpolate", "I")); indexed = 0; usecolorkey = 0; colorspace = NULL; mask = NULL; if (imagemask) bpc = 1; if (w == 0) return fz_throw("image width is zero"); if (h == 0) return fz_throw("image height is zero"); if (bpc == 0) return fz_throw("image depth is zero"); if (w > (1 << 16)) return fz_throw("image is too wide"); if (h > (1 << 16)) return fz_throw("image is too high"); obj = fz_dict_getsa(dict, "ColorSpace", "CS"); if (obj && !imagemask && !forcemask) { /* colorspace resource lookup is only done for inline images */ if (fz_is_name(obj)) { res = fz_dict_get(fz_dict_gets(rdb, "ColorSpace"), obj); if (res) obj = res; } error = pdf_load_colorspace(&colorspace, xref, obj); if (error) return fz_rethrow(error, "cannot load image colorspace"); if (!strcmp(colorspace->name, "Indexed")) indexed = 1; n = colorspace->n; } else { n = 1; } obj = fz_dict_getsa(dict, "Decode", "D"); if (obj) { for (i = 0; i < n * 2; i++) decode[i] = fz_to_real(fz_array_get(obj, i)); } else { float maxval = indexed ? (1 << bpc) - 1 : 1; for (i = 0; i < n * 2; i++) decode[i] = i & 1 ? maxval : 0; } obj = fz_dict_getsa(dict, "SMask", "Mask"); if (fz_is_dict(obj)) { /* Not allowed for inline images */ if (!cstm) { error = pdf_load_image_imp(&mask, xref, rdb, obj, NULL, 1); if (error) { if (colorspace) fz_drop_colorspace(colorspace); return fz_rethrow(error, "cannot load image mask/softmask"); } } } else if (fz_is_array(obj)) { usecolorkey = 1; for (i = 0; i < n * 2; i++) colorkey[i] = fz_to_int(fz_array_get(obj, i)); } /* Allocate now, to fail early if we run out of memory */ tile = fz_new_pixmap_with_limit(colorspace, w, h); if (!tile) { if (colorspace) fz_drop_colorspace(colorspace); if (mask) fz_drop_pixmap(mask); return fz_throw("out of memory"); } if (colorspace) fz_drop_colorspace(colorspace); tile->mask = mask; tile->interpolate = interpolate; stride = (w * n * bpc + 7) / 8; if (cstm) { stm = pdf_open_inline_stream(cstm, xref, dict, stride * h); } else { error = pdf_open_stream(&stm, xref, fz_to_num(dict), fz_to_gen(dict)); if (error) { fz_drop_pixmap(tile); return fz_rethrow(error, "cannot open image data stream (%d 0 R)", fz_to_num(dict)); } } samples = fz_calloc(h, stride); len = fz_read(stm, samples, h * stride); if (len < 0) { fz_close(stm); fz_free(samples); fz_drop_pixmap(tile); return fz_rethrow(len, "cannot read image data"); } /* Make sure we read the EOF marker (for inline images only) */ if (cstm) { unsigned char tbuf[512]; int tlen = fz_read(stm, tbuf, sizeof tbuf); if (tlen < 0) fz_catch(tlen, "ignoring error at end of image"); if (tlen > 0) fz_warn("ignoring garbage at end of image"); } fz_close(stm); /* Pad truncated images */ if (len < stride * h) { fz_warn("padding truncated image (%d 0 R)", fz_to_num(dict)); memset(samples + len, 0, stride * h - len); } /* Invert 1-bit image masks */ if (imagemask) { /* 0=opaque and 1=transparent so we need to invert */ unsigned char *p = samples; len = h * stride; for (i = 0; i < len; i++) p[i] = ~p[i]; } fz_unpack_tile(tile, samples, n, bpc, stride, indexed); fz_free(samples); if (usecolorkey) pdf_mask_color_key(tile, n, colorkey); if (indexed) { fz_pixmap *conv; fz_decode_indexed_tile(tile, decode, (1 << bpc) - 1); conv = pdf_expand_indexed_pixmap(tile); fz_drop_pixmap(tile); tile = conv; } else { fz_decode_tile(tile, decode); } *imgp = tile; return fz_okay; }
pdf_link * pdf_load_link(pdf_xref *xref, fz_obj *dict) { fz_obj *dest; fz_obj *action; fz_obj *obj; fz_rect bbox; pdf_link_kind kind; fz_context *ctx = xref->ctx; dest = NULL; obj = fz_dict_gets(ctx, dict, "Rect"); if (obj) bbox = pdf_to_rect(ctx, obj); else bbox = fz_empty_rect; obj = fz_dict_gets(ctx, dict, "Dest"); if (obj) { kind = PDF_LINK_GOTO; dest = resolve_dest(xref, obj); } action = fz_dict_gets(ctx, dict, "A"); /* fall back to additional action button's down/up action */ if (!action) action = fz_dict_getsa(ctx, fz_dict_gets(ctx, dict, "AA"), "U", "D"); if (action) { obj = fz_dict_gets(ctx, action, "S"); if (fz_is_name(ctx, obj) && !strcmp(fz_to_name(ctx, obj), "GoTo")) { kind = PDF_LINK_GOTO; dest = resolve_dest(xref, fz_dict_gets(ctx, action, "D")); } else if (fz_is_name(ctx, obj) && !strcmp(fz_to_name(ctx, obj), "URI")) { kind = PDF_LINK_URI; dest = fz_dict_gets(ctx, action, "URI"); } else if (fz_is_name(ctx, obj) && !strcmp(fz_to_name(ctx, obj), "Launch")) { kind = PDF_LINK_LAUNCH; dest = fz_dict_gets(ctx, action, "F"); } else if (fz_is_name(ctx, obj) && !strcmp(fz_to_name(ctx, obj), "Named")) { kind = PDF_LINK_NAMED; dest = fz_dict_gets(ctx, action, "N"); } else if (fz_is_name(ctx, obj) && (!strcmp(fz_to_name(ctx, obj), "GoToR"))) { kind = PDF_LINK_ACTION; dest = action; } else { dest = NULL; } } if (dest) { pdf_link *link = fz_malloc(ctx, sizeof(pdf_link)); link->kind = kind; link->rect = bbox; link->dest = fz_keep_obj(dest); link->next = NULL; return link; } return NULL; }