static fz_error pdf_read_ocg(pdf_xref *xref) { fz_obj *obj, *ocg; int len, i; pdf_ocg_descriptor *desc; obj = fz_dict_gets(fz_dict_gets(xref->trailer, "Root"), "OCProperties"); if (obj == NULL) return fz_okay; ocg = fz_dict_gets(obj, "OCGs"); if (ocg == NULL || !fz_is_array(ocg)) /* Not ever supposed to happen, but live with it. */ return fz_okay; len = fz_array_len(ocg); desc = fz_malloc(sizeof(*desc)); desc->len = len; desc->ocgs = fz_calloc(len, sizeof(*desc->ocgs)); desc->intent = NULL; for (i=0; i < len; i++) { fz_obj *o = fz_array_get(ocg, i); desc->ocgs[i].num = fz_to_num(o); desc->ocgs[i].gen = fz_to_gen(o); desc->ocgs[i].state = 0; } xref->ocg = desc; return pdf_ocg_set_config(xref, 0); }
static fz_obj * resolve_dest(pdf_xref *xref, fz_obj *dest) { if (fz_is_name(xref->ctx, dest) || fz_is_string(xref->ctx, dest)) { dest = pdf_lookup_dest(xref, dest); return resolve_dest(xref, dest); } else if (fz_is_array(xref->ctx, dest)) { return dest; } else if (fz_is_dict(xref->ctx, dest)) { dest = fz_dict_gets(xref->ctx, dest, "D"); return resolve_dest(xref, dest); } else if (fz_is_indirect(dest)) return dest; return NULL; }
static void addhexfilter(fz_obj *dict) { fz_obj *f, *dp, *newf, *newdp; fz_obj *ahx, *nullobj; ahx = fz_new_name(ctx, "ASCIIHexDecode"); nullobj = fz_new_null(ctx); newf = newdp = NULL; f = fz_dict_gets(dict, "Filter"); dp = fz_dict_gets(dict, "DecodeParms"); if (fz_is_name(f)) { newf = fz_new_array(ctx, 2); fz_array_push(newf, ahx); fz_array_push(newf, f); f = newf; if (fz_is_dict(dp)) { newdp = fz_new_array(ctx, 2); fz_array_push(newdp, nullobj); fz_array_push(newdp, dp); dp = newdp; } } else if (fz_is_array(f)) { fz_array_insert(f, ahx); if (fz_is_array(dp)) fz_array_insert(dp, nullobj); } else f = ahx; fz_dict_puts(dict, "Filter", f); if (dp) fz_dict_puts(dict, "DecodeParms", dp); fz_drop_obj(ahx); fz_drop_obj(nullobj); if (newf) fz_drop_obj(newf); if (newdp) fz_drop_obj(newdp); }
static int _pdf_doc_find_page_no( struct _pdf_doc *self, fz_obj *dest) { if (fz_is_dict(dest)) { /* The destination is linked from a Go-To action's D array. */ fz_obj * D = fz_dict_gets(dest, "D"); if (D && fz_is_array(D)) dest = D; } if (fz_is_array(dest)) dest = fz_array_get(dest, 0); if (fz_is_int(dest)) return fz_to_int(dest); return pdf_find_page_number(self->xref, dest); }
static fz_colorspace * load_separation(pdf_document *xref, fz_obj *array) { fz_colorspace *cs; struct separation *sep = NULL; fz_context *ctx = xref->ctx; fz_obj *nameobj = fz_array_get(array, 1); fz_obj *baseobj = fz_array_get(array, 2); fz_obj *tintobj = fz_array_get(array, 3); fz_colorspace *base; pdf_function *tint = NULL; int n; fz_var(tint); fz_var(sep); if (fz_is_array(nameobj)) n = fz_array_len(nameobj); else n = 1; if (n > FZ_MAX_COLORS) fz_throw(ctx, "too many components in colorspace"); base = pdf_load_colorspace(xref, baseobj); /* RJW: "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj) */ fz_try(ctx) { tint = pdf_load_function(xref, tintobj); /* RJW: fz_drop_colorspace(ctx, base); * "cannot load tint function (%d %d R)", fz_to_num(tintobj), fz_to_gen(tintobj) */ sep = fz_malloc_struct(ctx, struct separation); sep->base = base; sep->tint = tint; cs = fz_new_colorspace(ctx, n == 1 ? "Separation" : "DeviceN", n); cs->to_rgb = separation_to_rgb; cs->free_data = free_separation; cs->data = sep; cs->size += sizeof(struct separation) + (base ? base->size : 0) + pdf_function_size(tint); } fz_catch(ctx) { fz_drop_colorspace(ctx, base); pdf_drop_function(ctx, tint); fz_free(ctx, sep); fz_rethrow(ctx); } return cs; }
static void sweepobj(fz_obj *obj) { int i; if (fz_is_indirect(obj)) sweepref(obj); else if (fz_is_dict(ctx, obj)) for (i = 0; i < fz_dict_len(ctx, obj); i++) sweepobj(fz_dict_get_val(ctx, obj, i)); else if (fz_is_array(ctx, obj)) for (i = 0; i < fz_array_len(ctx, obj); i++) sweepobj(fz_array_get(ctx, obj, i)); }
static fz_error load_separation(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) { fz_error error; fz_colorspace *cs; struct separation *sep; fz_obj *nameobj = fz_array_get(array, 1); fz_obj *baseobj = fz_array_get(array, 2); fz_obj *tintobj = fz_array_get(array, 3); fz_colorspace *base; pdf_function *tint; int n; if (fz_is_array(nameobj)) n = fz_array_len(nameobj); else n = 1; if (n > FZ_MAX_COLORS) return fz_throw("too many components in colorspace"); error = pdf_load_colorspace(&base, xref, baseobj); if (error) return fz_rethrow(error, "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj)); error = pdf_load_function(&tint, xref, tintobj); if (error) { fz_drop_colorspace(base); return fz_rethrow(error, "cannot load tint function (%d %d R)", fz_to_num(tintobj), fz_to_gen(tintobj)); } sep = fz_malloc(sizeof(struct separation)); sep->base = base; sep->tint = tint; cs = fz_new_colorspace(n == 1 ? "Separation" : "DeviceN", n); cs->to_rgb = separation_to_rgb; cs->free_data = free_separation; cs->data = sep; *csp = cs; return fz_okay; }
static void renumberobj(fz_obj *obj) { int i; fz_context *ctx = xref->ctx; if (fz_is_dict(obj)) { int n = fz_dict_len(obj); for (i = 0; i < n; i++) { fz_obj *key = fz_dict_get_key(obj, i); fz_obj *val = fz_dict_get_val(obj, i); if (fz_is_indirect(val)) { val = fz_new_indirect(ctx, renumbermap[fz_to_num(val)], 0, xref); fz_dict_put(obj, key, val); fz_drop_obj(val); } else { renumberobj(val); } } } else if (fz_is_array(obj)) { int n = fz_array_len(obj); for (i = 0; i < n; i++) { fz_obj *val = fz_array_get(obj, i); if (fz_is_indirect(val)) { val = fz_new_indirect(ctx, renumbermap[fz_to_num(val)], 0, xref); fz_array_put(obj, i, val); fz_drop_obj(val); } else { renumberobj(val); } } } }
static void sweepobj(fz_obj *obj) { int i; if (fz_is_indirect(obj)) sweepref(obj); else if (fz_is_dict(obj)) { int n = fz_dict_len(obj); for (i = 0; i < n; i++) sweepobj(fz_dict_get_val(obj, i)); } else if (fz_is_array(obj)) { int n = fz_array_len(obj); for (i = 0; i < n; i++) sweepobj(fz_array_get(obj, i)); } }
/* * 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 int _pdf_doc_load(struct _pdf_doc *self, mume_stream_t *stm) { fz_error error; fz_stream *fzstm; fz_rect *mbox; fz_obj *page_obj, *box_obj; int i, c; _pdf_doc_clear(self); fzstm = fz_new_stream(stm, _pdf_stream_read, _pdf_stream_close); mume_stream_reference(stm); fzstm->seek = _pdf_stream_seek; error = pdf_open_xref_with_stream(&self->xref, fzstm, NULL); fz_close(fzstm); if (error) { mume_error(("Read xref failed\n", error)); return 0; } assert(!pdf_needs_password(self->xref)); /* Load meta information. */ error = pdf_load_page_tree(self->xref); if (error) { mume_error(("Cannot load page tree\n")); return 0; } c = pdf_count_pages(self->xref); self->glyph_cache = fz_new_glyph_cache(); self->pages = calloc_abort(c, sizeof(pdf_page*)); self->disps = calloc_abort(c, sizeof(fz_display_list*)); self->media_boxes = malloc_abort(c * sizeof(fz_rect)); self->page_rotates = malloc_abort(c * sizeof(int)); /* Extract each pages' media box and rotation. */ for (i = 0; i < c; ++i) { mbox = self->media_boxes + i; page_obj = self->xref->page_objs[i]; if (!page_obj) { *mbox = fz_empty_rect; continue; } box_obj = fz_dict_gets(page_obj, "MediaBox"); *mbox = pdf_to_rect(box_obj); if (fz_is_empty_rect(*mbox)) { fz_warn("Cannot find page bounds, guessing page bounds."); mbox->x1 = 612; mbox->y1 = 792; } box_obj = fz_dict_gets(page_obj, "CropBox"); if (fz_is_array(box_obj)) *mbox = fz_intersect_rect(*mbox, pdf_to_rect(box_obj)); self->page_rotates[i] = fz_to_int( fz_dict_gets(page_obj, "Rotate")); if (self->page_rotates[i] % 90) self->page_rotates[i] = 0; } return 1; }
static fz_error pdf_load_colorspace_imp(fz_colorspace **csp, pdf_xref *xref, fz_obj *obj) { if (fz_is_name(obj)) { if (!strcmp(fz_to_name(obj), "Pattern")) *csp = fz_device_gray; else if (!strcmp(fz_to_name(obj), "G")) *csp = fz_device_gray; else if (!strcmp(fz_to_name(obj), "RGB")) *csp = fz_device_rgb; else if (!strcmp(fz_to_name(obj), "CMYK")) *csp = fz_device_cmyk; else if (!strcmp(fz_to_name(obj), "DeviceGray")) *csp = fz_device_gray; else if (!strcmp(fz_to_name(obj), "DeviceRGB")) *csp = fz_device_rgb; else if (!strcmp(fz_to_name(obj), "DeviceCMYK")) *csp = fz_device_cmyk; else return fz_throw("unknown colorspace: %s", fz_to_name(obj)); return fz_okay; } else if (fz_is_array(obj)) { fz_obj *name = fz_array_get(obj, 0); if (fz_is_name(name)) { /* load base colorspace instead */ if (!strcmp(fz_to_name(name), "Pattern")) { fz_error error; obj = fz_array_get(obj, 1); if (!obj) { *csp = fz_device_gray; return fz_okay; } error = pdf_load_colorspace(csp, xref, obj); if (error) return fz_rethrow(error, "cannot load pattern (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); } else if (!strcmp(fz_to_name(name), "G")) *csp = fz_device_gray; else if (!strcmp(fz_to_name(name), "RGB")) *csp = fz_device_rgb; else if (!strcmp(fz_to_name(name), "CMYK")) *csp = fz_device_cmyk; else if (!strcmp(fz_to_name(name), "DeviceGray")) *csp = fz_device_gray; else if (!strcmp(fz_to_name(name), "DeviceRGB")) *csp = fz_device_rgb; else if (!strcmp(fz_to_name(name), "DeviceCMYK")) *csp = fz_device_cmyk; else if (!strcmp(fz_to_name(name), "CalGray")) *csp = fz_device_gray; else if (!strcmp(fz_to_name(name), "CalRGB")) *csp = fz_device_rgb; else if (!strcmp(fz_to_name(name), "CalCMYK")) *csp = fz_device_cmyk; else if (!strcmp(fz_to_name(name), "Lab")) *csp = fz_device_lab; else if (!strcmp(fz_to_name(name), "ICCBased")) return load_icc_based(csp, xref, fz_array_get(obj, 1)); else if (!strcmp(fz_to_name(name), "Indexed")) return load_indexed(csp, xref, obj); else if (!strcmp(fz_to_name(name), "I")) return load_indexed(csp, xref, obj); else if (!strcmp(fz_to_name(name), "Separation")) return load_separation(csp, xref, obj); else if (!strcmp(fz_to_name(name), "DeviceN")) return load_separation(csp, xref, obj); else return fz_throw("syntaxerror: unknown colorspace %s", fz_to_name(name)); return fz_okay; } } return fz_throw("syntaxerror: could not parse color space (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); }
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; }
static fz_error pdf_load_shading_dict(fz_shade **shadep, pdf_xref *xref, fz_obj *dict, fz_matrix transform) { fz_error error; fz_shade *shade; pdf_function *func[FZ_MAX_COLORS] = { NULL }; fz_stream *stream = NULL; fz_obj *obj; int funcs; int type; int i; shade = fz_malloc(sizeof(fz_shade)); shade->refs = 1; shade->type = FZ_MESH; shade->use_background = 0; shade->use_function = 0; shade->matrix = transform; shade->bbox = fz_infinite_rect; shade->extend[0] = 0; shade->extend[1] = 0; shade->mesh_len = 0; shade->mesh_cap = 0; shade->mesh = NULL; shade->colorspace = NULL; funcs = 0; obj = fz_dict_gets(dict, "ShadingType"); type = fz_to_int(obj); obj = fz_dict_gets(dict, "ColorSpace"); if (!obj) { fz_drop_shade(shade); return fz_throw("shading colorspace is missing"); } error = pdf_load_colorspace(&shade->colorspace, xref, obj); if (error) { fz_drop_shade(shade); return fz_rethrow(error, "cannot load colorspace (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); } obj = fz_dict_gets(dict, "Background"); if (obj) { shade->use_background = 1; for (i = 0; i < shade->colorspace->n; i++) shade->background[i] = fz_to_real(fz_array_get(obj, i)); } obj = fz_dict_gets(dict, "BBox"); if (fz_is_array(obj)) { shade->bbox = pdf_to_rect(obj); } obj = fz_dict_gets(dict, "Function"); if (fz_is_dict(obj)) { funcs = 1; error = pdf_load_function(&func[0], xref, obj); if (error) { error = fz_rethrow(error, "cannot load shading function (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); goto cleanup; } } else if (fz_is_array(obj)) { funcs = fz_array_len(obj); if (funcs != 1 && funcs != shade->colorspace->n) { error = fz_throw("incorrect number of shading functions"); goto cleanup; } for (i = 0; i < funcs; i++) { error = pdf_load_function(&func[i], xref, fz_array_get(obj, i)); if (error) { error = fz_rethrow(error, "cannot load shading function (%d %d R)", fz_to_num(obj), fz_to_gen(obj)); goto cleanup; } } } if (type >= 4 && type <= 7) { error = pdf_open_stream(&stream, xref, fz_to_num(dict), fz_to_gen(dict)); if (error) { error = fz_rethrow(error, "cannot open shading stream (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); goto cleanup; } } switch (type) { case 1: pdf_load_function_based_shading(shade, xref, dict, func[0]); break; case 2: pdf_load_axial_shading(shade, xref, dict, funcs, func); break; case 3: pdf_load_radial_shading(shade, xref, dict, funcs, func); break; case 4: pdf_load_type4_shade(shade, xref, dict, funcs, func, stream); break; case 5: pdf_load_type5_shade(shade, xref, dict, funcs, func, stream); break; case 6: pdf_load_type6_shade(shade, xref, dict, funcs, func, stream); break; case 7: pdf_load_type7_shade(shade, xref, dict, funcs, func, stream); break; default: error = fz_throw("unknown shading type: %d", type); goto cleanup; } if (stream) fz_close(stream); for (i = 0; i < funcs; i++) if (func[i]) pdf_drop_function(func[i]); *shadep = shade; return fz_okay; cleanup: if (stream) fz_close(stream); for (i = 0; i < funcs; i++) if (func[i]) pdf_drop_function(func[i]); fz_drop_shade(shade); return fz_rethrow(error, "cannot load shading type %d (%d %d R)", type, fz_to_num(dict), fz_to_gen(dict)); }