static pdf_annot * pdf_create_highlight_annot(pdf_xref *xref, fz_obj *obj) { fz_context *ctx = xref->ctx; fz_buffer *content = fz_new_buffer(ctx, 512); fz_rect rect = pdf_to_rect(ctx, fz_dict_gets(ctx, obj, "Rect")); fz_obj *quad_points = fz_dict_gets(ctx, obj, "QuadPoints"); fz_obj *resources = pdf_dict_from_string(xref, ANNOT_HIGHLIGHT_AP_RESOURCES); fz_rect a, b; float rgb[3]; float skew; int i; for (i = 0; i < fz_array_len(ctx, quad_points) / 8; i++) { pdf_get_quadrilaterals(ctx, quad_points, i, &a, &b); skew = 0.15 * fabs(a.y0 - b.y0); b.x0 -= skew; b.x1 += skew; rect = fz_union_rect(rect, fz_union_rect(a, b)); } pdf_get_annot_color(ctx, obj, rgb); fz_buffer_printf(ctx, content, "q /GS gs %.4f %.4f %.4f rg 1 0 0 1 -%.4f -%.4f cm ", rgb[0], rgb[1], rgb[2], rect.x0, rect.y0); for (i = 0; i < fz_array_len(ctx, quad_points) / 8; i++) { pdf_get_quadrilaterals(ctx, quad_points, i, &a, &b); skew = 0.15 * fabs(a.y0 - b.y0); fz_buffer_printf(ctx, content, "%.4f %.4f m %.4f %.4f l %.4f %.4f l %.4f %.4f l h ", a.x0, a.y0, b.x1 + skew, b.y1, a.x1, a.y1, b.x0 - skew, b.y0); } fz_buffer_printf(ctx, content, "f Q"); return pdf_create_annot(ctx, rect, fz_keep_obj(obj), content, resources, 1); }
static void pdf_load_radial_shading(fz_shade *shade, pdf_xref *xref, fz_obj *dict, int funcs, pdf_function **func) { fz_obj *obj; float d0, d1; int e0, e1; float x0, y0, r0, x1, y1, r1; struct vertex p1, p2; fz_context *ctx = xref->ctx; obj = fz_dict_gets(ctx, dict, "Coords"); x0 = fz_to_real(ctx, fz_array_get(ctx, obj, 0)); y0 = fz_to_real(ctx, fz_array_get(ctx, obj, 1)); r0 = fz_to_real(ctx, fz_array_get(ctx, obj, 2)); x1 = fz_to_real(ctx, fz_array_get(ctx, obj, 3)); y1 = fz_to_real(ctx, fz_array_get(ctx, obj, 4)); r1 = fz_to_real(ctx, fz_array_get(ctx, obj, 5)); d0 = 0; d1 = 1; obj = fz_dict_gets(ctx, dict, "Domain"); if (fz_array_len(ctx, obj) == 2) { d0 = fz_to_real(ctx, fz_array_get(ctx, obj, 0)); d1 = fz_to_real(ctx, fz_array_get(ctx, obj, 1)); } e0 = e1 = 0; obj = fz_dict_gets(ctx, dict, "Extend"); if (fz_array_len(ctx, obj) == 2) { e0 = fz_to_bool(ctx, fz_array_get(ctx, obj, 0)); e1 = fz_to_bool(ctx, fz_array_get(ctx, obj, 1)); } pdf_sample_shade_function(ctx, shade, funcs, func, d0, d1); shade->type = FZ_RADIAL; shade->extend[0] = e0; shade->extend[1] = e1; p1.x = x0; p1.y = y0; p1.c[0] = r0; pdf_add_vertex(ctx, shade, &p1); p2.x = x1; p2.y = y1; p2.c[0] = r1; pdf_add_vertex(ctx, shade, &p2); }
static void pdf_load_mesh_params(pdf_xref *xref, fz_obj *dict, struct mesh_params *p) { fz_obj *obj; int i, n; fz_context *ctx = xref->ctx; p->x0 = p->y0 = 0; p->x1 = p->y1 = 1; for (i = 0; i < FZ_MAX_COLORS; i++) { p->c0[i] = 0; p->c1[i] = 1; } p->vprow = fz_to_int(ctx, fz_dict_gets(ctx, dict, "VerticesPerRow")); p->bpflag = fz_to_int(ctx, fz_dict_gets(ctx, dict, "BitsPerFlag")); p->bpcoord = fz_to_int(ctx, fz_dict_gets(ctx, dict, "BitsPerCoordinate")); p->bpcomp = fz_to_int(ctx, fz_dict_gets(ctx, dict, "BitsPerComponent")); obj = fz_dict_gets(ctx, dict, "Decode"); if (fz_array_len(ctx, obj) >= 6) { n = (fz_array_len(ctx, obj) - 4) / 2; p->x0 = fz_to_real(ctx, fz_array_get(ctx, obj, 0)); p->x1 = fz_to_real(ctx, fz_array_get(ctx, obj, 1)); p->y0 = fz_to_real(ctx, fz_array_get(ctx, obj, 2)); p->y1 = fz_to_real(ctx, fz_array_get(ctx, obj, 3)); for (i = 0; i < n; i++) { p->c0[i] = fz_to_real(ctx, fz_array_get(ctx, obj, 4 + i * 2)); p->c1[i] = fz_to_real(ctx, fz_array_get(ctx, obj, 5 + i * 2)); } } if (p->vprow < 2) p->vprow = 2; if (p->bpflag != 2 && p->bpflag != 4 && p->bpflag != 8) p->bpflag = 8; if (p->bpcoord != 1 && p->bpcoord != 2 && p->bpcoord != 4 && p->bpcoord != 8 && p->bpcoord != 12 && p->bpcoord != 16 && p->bpcoord != 24 && p->bpcoord != 32) p->bpcoord = 8; if (p->bpcomp != 1 && p->bpcomp != 2 && p->bpcomp != 4 && p->bpcomp != 8 && p->bpcomp != 12 && p->bpcomp != 16) p->bpcomp = 8; }
static void pdf_load_axial_shading(fz_shade *shade, pdf_xref *xref, fz_obj *dict, int funcs, pdf_function **func) { fz_obj *obj; float d0, d1; int e0, e1; float x0, y0, x1, y1; struct vertex p1, p2; obj = fz_dict_gets(dict, "Coords"); x0 = fz_to_real(fz_array_get(obj, 0)); y0 = fz_to_real(fz_array_get(obj, 1)); x1 = fz_to_real(fz_array_get(obj, 2)); y1 = fz_to_real(fz_array_get(obj, 3)); d0 = 0; d1 = 1; obj = fz_dict_gets(dict, "Domain"); if (fz_array_len(obj) == 2) { d0 = fz_to_real(fz_array_get(obj, 0)); d1 = fz_to_real(fz_array_get(obj, 1)); } e0 = e1 = 0; obj = fz_dict_gets(dict, "Extend"); if (fz_array_len(obj) == 2) { e0 = fz_to_bool(fz_array_get(obj, 0)); e1 = fz_to_bool(fz_array_get(obj, 1)); } pdf_sample_shade_function(shade, funcs, func, d0, d1); shade->type = FZ_LINEAR; shade->extend[0] = e0; shade->extend[1] = e1; p1.x = x0; p1.y = y0; p1.c[0] = 0; pdf_add_vertex(shade, &p1); p2.x = x1; p2.y = y1; p2.c[0] = 0; pdf_add_vertex(shade, &p2); }
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); }
/* SumatraPDF: partial support for link borders */ static pdf_annot * pdf_create_link_annot(pdf_xref *xref, fz_obj *obj) { fz_obj *border, *dashes; fz_buffer *content; fz_rect rect; float rgb[3]; int i; border = fz_dict_gets(xref->ctx, obj, "Border"); if (fz_to_real(xref->ctx, fz_array_get(xref->ctx, border, 2)) <= 0) return NULL; pdf_get_annot_color(xref->ctx, obj, rgb); dashes = fz_array_get(xref->ctx, border, 3); rect = pdf_to_rect(xref->ctx, fz_dict_gets(xref->ctx, obj, "Rect")); obj = pdf_clone_for_view_only(xref, obj); // TODO: draw rounded rectangles if the first two /Border values are non-zero content = fz_new_buffer(xref->ctx, 128); fz_buffer_printf(xref->ctx, content, "q %.4f w [", fz_to_real(xref->ctx, fz_array_get(xref->ctx, border, 2))); for (i = 0; i < fz_array_len(xref->ctx, dashes); i++) fz_buffer_printf(xref->ctx, content, "%.4f ", fz_to_real(xref->ctx, fz_array_get(xref->ctx, dashes, i))); fz_buffer_printf(xref->ctx, content, "] 0 d %.4f %.4f %.4f RG 0 0 %.4f %.4f re S Q", rgb[0], rgb[1], rgb[2], rect.x1 - rect.x0, rect.y1 - rect.y0); return pdf_create_annot(xref->ctx, rect, obj, content, NULL, 0); }
void pdf_load_links(pdf_link **linkp, pdf_xref *xref, fz_obj *annots) { pdf_link *link, *head, *tail; fz_obj *obj; int i; fz_context *ctx = xref->ctx; head = tail = NULL; link = NULL; for (i = 0; i < fz_array_len(ctx, annots); i++) { obj = fz_array_get(ctx, annots, i); link = pdf_load_link(xref, obj); if (link) { if (!head) head = tail = link; else { tail->next = link; tail = link; } } } *linkp = head; }
/* * Load uncompressed contents of a stream into buf. */ fz_error pdf_load_stream(fz_buffer **bufp, pdf_xref *xref, int num, int gen) { fz_error error; fz_stream *stm; fz_obj *dict, *obj; int i, len; error = pdf_open_stream(&stm, xref, num, gen); if (error) return fz_rethrow(error, "cannot open stream (%d %d R)", num, gen); error = pdf_load_object(&dict, xref, num, gen); if (error) return fz_rethrow(error, "cannot load stream dictionary (%d %d R)", num, gen); len = fz_to_int(fz_dict_gets(dict, "Length")); obj = fz_dict_gets(dict, "Filter"); len = pdf_guess_filter_length(len, fz_to_name(obj)); for (i = 0; i < fz_array_len(obj); i++) len = pdf_guess_filter_length(len, fz_to_name(fz_array_get(obj, i))); fz_drop_obj(dict); error = fz_read_all(bufp, stm, len); if (error) { fz_close(stm); return fz_rethrow(error, "cannot read raw stream (%d %d R)", num, gen); } fz_close(stm); return fz_okay; }
fz_obj * fz_copy_array(fz_context *ctx, fz_obj *obj) { fz_obj *arr; int i; int n; RESOLVE(obj); if (!obj || obj->kind != FZ_ARRAY) fz_warn(ctx, "assert: not an array (%s)", fz_objkindstr(obj)); arr = fz_new_array(ctx, fz_array_len(obj)); n = fz_array_len(obj); for (i = 0; i < n; i++) fz_array_push(arr, fz_array_get(obj, i)); return arr; }
int fz_array_contains(fz_obj *arr, fz_obj *obj) { int i; for (i = 0; i < fz_array_len(arr); i++) if (!fz_objcmp(fz_array_get(arr, i), obj)) return 1; return 0; }
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; }
int pdf_is_jpx_image(fz_obj *dict) { fz_obj *filter; int i; filter = fz_dict_gets(dict, "Filter"); if (!strcmp(fz_to_name(filter), "JPXDecode")) return 1; for (i = 0; i < fz_array_len(filter); i++) if (!strcmp(fz_to_name(fz_array_get(filter, i)), "JPXDecode")) return 1; return 0; }
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 pdf_annot * pdf_create_markup_annot(pdf_xref *xref, fz_obj *obj, char *type) { fz_context *ctx = xref->ctx; fz_buffer *content = fz_new_buffer(ctx, 512); fz_rect rect = pdf_to_rect(ctx, fz_dict_gets(ctx, obj, "Rect")); fz_obj *quad_points = fz_dict_gets(ctx, obj, "QuadPoints"); fz_rect a, b; float rgb[3]; int i; for (i = 0; i < fz_array_len(ctx, quad_points) / 8; i++) { pdf_get_quadrilaterals(ctx, quad_points, i, &a, &b); b.y0 -= 0.25; a.y1 += 0.25; rect = fz_union_rect(rect, fz_union_rect(a, b)); } pdf_get_annot_color(ctx, obj, rgb); fz_buffer_printf(ctx, content, "q %.4f %.4f %.4f RG 1 0 0 1 -%.4f -%.4f cm 0.5 w ", rgb[0], rgb[1], rgb[2], rect.x0, rect.y0); if (!strcmp(type, "Squiggly")) fz_buffer_printf(ctx, content, "[1 1] d "); for (i = 0; i < fz_array_len(ctx, quad_points) / 8; i++) { pdf_get_quadrilaterals(ctx, quad_points, i, &a, &b); if (!strcmp(type, "StrikeOut")) fz_buffer_printf(ctx, content, "%.4f %.4f m %.4f %.4f l ", (a.x0 + b.x0) / 2, (a.y0 + b.y0) / 2, (a.x1 + b.x1) / 2, (a.y1 + b.y1) / 2); else fz_buffer_printf(ctx, content, "%.4f %.4f m %.4f %.4f l ", b.x0, b.y0, a.x1, a.y1); } fz_buffer_printf(ctx, content, "S Q"); return pdf_create_annot(ctx, rect, fz_keep_obj(obj), content, NULL, 0); }
/* * Build a chain of filters given filter names and param dicts. * If head is given, start filter chain with it. * Assume ownership of head. */ static fz_stream * build_filter_chain(fz_stream *chain, pdf_xref *xref, fz_obj *fs, fz_obj *ps, int num, int gen) { fz_obj *f; fz_obj *p; int i; for (i = 0; i < fz_array_len(fs); i++) { f = fz_array_get(fs, i); p = fz_array_get(ps, i); chain = build_filter(chain, xref, f, p, num, gen); } return chain; }
/* * 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; }
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); } } } }
/* * 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 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; }
fz_error pdf_ocg_set_config(pdf_xref *xref, int config) { int i, j, len, len2; pdf_ocg_descriptor *desc = xref->ocg; fz_obj *obj, *cobj; char *name; obj = fz_dict_gets(fz_dict_gets(xref->trailer, "Root"), "OCProperties"); if (obj == NULL) { if (config == 0) return fz_okay; else return fz_throw("Unknown OCG config (None known!)"); } if (config == 0) { cobj = fz_dict_gets(obj, "D"); if (cobj == NULL) return fz_throw("No default OCG config"); } else { cobj = fz_array_get(fz_dict_gets(obj, "Configs"), config); if (cobj == NULL) return fz_throw("Illegal OCG config"); } if (desc->intent != NULL) fz_drop_obj(desc->intent); desc->intent = fz_dict_gets(cobj, "Intent"); if (desc->intent != NULL) fz_keep_obj(desc->intent); len = desc->len; name = fz_to_name(fz_dict_gets(cobj, "BaseState")); if (strcmp(name, "Unchanged") == 0) { /* Do nothing */ } else if (strcmp(name, "OFF") == 0) { for (i = 0; i < len; i++) { desc->ocgs[i].state = 0; } } else /* Default to ON */ { for (i = 0; i < len; i++) { desc->ocgs[i].state = 1; } } obj = fz_dict_gets(cobj, "ON"); len2 = fz_array_len(obj); for (i = 0; i < len2; i++) { fz_obj *o = fz_array_get(obj, i); int n = fz_to_num(o); int g = fz_to_gen(o); for (j=0; j < len; j++) { if (desc->ocgs[j].num == n && desc->ocgs[j].gen == g) { desc->ocgs[j].state = 1; break; } } } obj = fz_dict_gets(cobj, "OFF"); len2 = fz_array_len(obj); for (i = 0; i < len2; i++) { fz_obj *o = fz_array_get(obj, i); int n = fz_to_num(o); int g = fz_to_gen(o); for (j=0; j < len; j++) { if (desc->ocgs[j].num == n && desc->ocgs[j].gen == g) { desc->ocgs[j].state = 0; break; } } } /* FIXME: Should make 'num configs' available in the descriptor. */ /* FIXME: Should copy out 'Intent' here into the descriptor, and remove * csi->intent in favour of that. */ /* FIXME: Should copy 'AS' into the descriptor, and visibility * decisions should respect it. */ /* FIXME: Make 'Order' available via the descriptor (when we have an * app that needs it) */ /* FIXME: Make 'ListMode' available via the descriptor (when we have * an app that needs it) */ /* FIXME: Make 'RBGroups' available via the descriptor (when we have * an app that needs it) */ /* FIXME: Make 'Locked' available via the descriptor (when we have * an app that needs it) */ return fz_okay; }
void pdf_load_annots(pdf_annot **annotp, pdf_xref *xref, fz_obj *annots) { pdf_annot *annot, *head, *tail; fz_obj *obj, *ap, *as, *n, *rect; pdf_xobject *form; fz_error error; int i; fz_context *ctx = xref->ctx; head = tail = NULL; annot = NULL; for (i = 0; i < fz_array_len(ctx, annots); i++) { obj = fz_array_get(ctx, annots, i); /* cf. http://bugs.ghostscript.com/show_bug.cgi?id=692078 */ if ((annot = pdf_update_tx_widget_annot(xref, obj))) { if (!head) head = tail = annot; else { tail->next = annot; tail = annot; } continue; } rect = fz_dict_gets(ctx, obj, "Rect"); ap = fz_dict_gets(ctx, obj, "AP"); as = fz_dict_gets(ctx, obj, "AS"); if (fz_is_dict(ctx, ap)) { n = fz_dict_gets(ctx, ap, "N"); /* normal state */ /* lookup current state in sub-dictionary */ if (!pdf_is_stream(xref, fz_to_num(n), fz_to_gen(n))) n = fz_dict_get(ctx, n, as); if (pdf_is_stream(xref, fz_to_num(n), fz_to_gen(n))) { error = pdf_load_xobject(&form, xref, n); if (error) { fz_error_handle(ctx, error, "ignoring broken annotation"); continue; } annot = fz_malloc(ctx, sizeof(pdf_annot)); annot->obj = fz_keep_obj(obj); annot->rect = pdf_to_rect(ctx, rect); annot->ap = form; annot->next = NULL; pdf_transform_annot(annot); if (annot) { if (!head) head = tail = annot; else { tail->next = annot; tail = annot; } } } } /* SumatraPDF: synthesize appearance streams for a few more annotations */ else if ((annot = pdf_create_annot_with_appearance(xref, obj))) { if (!head) head = tail = annot; else { tail->next = annot; tail = annot; } } } *annotp = head; }
static void retainpages(int argc, char **argv) { fz_obj *oldroot, *root, *pages, *kids, *countobj, *parent, *olddests; /* Keep only pages/type and (reduced) dest entries to avoid * references to unretained pages */ oldroot = fz_dict_gets(xref->trailer, "Root"); pages = fz_dict_gets(oldroot, "Pages"); olddests = pdf_load_name_tree(xref, "Dests"); root = fz_new_dict(ctx, 2); fz_dict_puts(root, "Type", fz_dict_gets(oldroot, "Type")); fz_dict_puts(root, "Pages", fz_dict_gets(oldroot, "Pages")); pdf_update_object(xref, fz_to_num(oldroot), fz_to_gen(oldroot), root); fz_drop_obj(root); /* Create a new kids array with only the pages we want to keep */ parent = fz_new_indirect(ctx, fz_to_num(pages), fz_to_gen(pages), xref); kids = fz_new_array(ctx, 1); /* Retain pages specified */ while (argc - fz_optind) { int page, spage, epage; char *spec, *dash; char *pagelist = argv[fz_optind]; spec = fz_strsep(&pagelist, ","); while (spec) { dash = strchr(spec, '-'); if (dash == spec) spage = epage = pdf_count_pages(xref); else spage = epage = atoi(spec); if (dash) { if (strlen(dash) > 1) epage = atoi(dash + 1); else epage = pdf_count_pages(xref); } if (spage > epage) page = spage, spage = epage, epage = page; if (spage < 1) spage = 1; if (epage > pdf_count_pages(xref)) epage = pdf_count_pages(xref); for (page = spage; page <= epage; page++) { fz_obj *pageobj = xref->page_objs[page-1]; fz_obj *pageref = xref->page_refs[page-1]; fz_dict_puts(pageobj, "Parent", parent); /* Store page object in new kids array */ fz_array_push(kids, pageref); } spec = fz_strsep(&pagelist, ","); } fz_optind++; } fz_drop_obj(parent); /* Update page count and kids array */ countobj = fz_new_int(ctx, fz_array_len(kids)); fz_dict_puts(pages, "Count", countobj); fz_drop_obj(countobj); fz_dict_puts(pages, "Kids", kids); fz_drop_obj(kids); /* Also preserve the (partial) Dests name tree */ if (olddests) { int i; fz_obj *names = fz_new_dict(ctx, 1); fz_obj *dests = fz_new_dict(ctx, 1); fz_obj *names_list = fz_new_array(ctx, 32); for (i = 0; i < fz_dict_len(olddests); i++) { fz_obj *key = fz_dict_get_key(olddests, i); fz_obj *val = fz_dict_get_val(olddests, i); fz_obj *key_str = fz_new_string(ctx, fz_to_name(key), strlen(fz_to_name(key))); fz_obj *dest = fz_dict_gets(val, "D"); dest = fz_array_get(dest ? dest : val, 0); if (fz_array_contains(fz_dict_gets(pages, "Kids"), dest)) { fz_array_push(names_list, key_str); fz_array_push(names_list, val); } fz_drop_obj(key_str); } root = fz_dict_gets(xref->trailer, "Root"); fz_dict_puts(dests, "Names", names_list); fz_dict_puts(names, "Dests", dests); fz_dict_puts(root, "Names", names); fz_drop_obj(names); fz_drop_obj(dests); fz_drop_obj(names_list); fz_drop_obj(olddests); } }
static fz_error pdf_read_new_xref(fz_obj **trailerp, pdf_xref *xref, char *buf, int cap) { fz_error error; fz_stream *stm; fz_obj *trailer; fz_obj *index; fz_obj *obj; int num, gen, stm_ofs; int size, w0, w1, w2; int t; error = pdf_parse_ind_obj(&trailer, xref, xref->file, buf, cap, &num, &gen, &stm_ofs); if (error) return fz_rethrow(error, "cannot parse compressed xref stream object"); obj = fz_dict_gets(trailer, "Size"); if (!obj) { fz_drop_obj(trailer); return fz_throw("xref stream missing Size entry (%d %d R)", num, gen); } size = fz_to_int(obj); if (size > xref->len) { pdf_resize_xref(xref, size); } if (num < 0 || num >= xref->len) { fz_drop_obj(trailer); return fz_throw("object id (%d %d R) out of range (0..%d)", num, gen, xref->len - 1); } obj = fz_dict_gets(trailer, "W"); if (!obj) { fz_drop_obj(trailer); return fz_throw("xref stream missing W entry (%d %d R)", num, gen); } w0 = fz_to_int(fz_array_get(obj, 0)); w1 = fz_to_int(fz_array_get(obj, 1)); w2 = fz_to_int(fz_array_get(obj, 2)); index = fz_dict_gets(trailer, "Index"); error = pdf_open_stream_at(&stm, xref, num, gen, trailer, stm_ofs); if (error) { fz_drop_obj(trailer); return fz_rethrow(error, "cannot open compressed xref stream (%d %d R)", num, gen); } if (!index) { error = pdf_read_new_xref_section(xref, stm, 0, size, w0, w1, w2); if (error) { fz_close(stm); fz_drop_obj(trailer); return fz_rethrow(error, "cannot read xref stream (%d %d R)", num, gen); } } else { for (t = 0; t < fz_array_len(index); t += 2) { int i0 = fz_to_int(fz_array_get(index, t + 0)); int i1 = fz_to_int(fz_array_get(index, t + 1)); error = pdf_read_new_xref_section(xref, stm, i0, i1, w0, w1, w2); if (error) { fz_close(stm); fz_drop_obj(trailer); return fz_rethrow(error, "cannot read xref stream section (%d %d R)", num, gen); } } } fz_close(stm); *trailerp = trailer; return fz_okay; }
static void pdf_load_function_based_shading(fz_shade *shade, pdf_xref *xref, fz_obj *dict, pdf_function *func) { fz_obj *obj; float x0, y0, x1, y1; fz_matrix matrix; struct vertex v[4]; int xx, yy; float x, y; float xn, yn; int i; x0 = y0 = 0; x1 = y1 = 1; obj = fz_dict_gets(dict, "Domain"); if (fz_array_len(obj) == 4) { x0 = fz_to_real(fz_array_get(obj, 0)); x1 = fz_to_real(fz_array_get(obj, 1)); y0 = fz_to_real(fz_array_get(obj, 2)); y1 = fz_to_real(fz_array_get(obj, 3)); } matrix = fz_identity; obj = fz_dict_gets(dict, "Matrix"); if (fz_array_len(obj) == 6) matrix = pdf_to_matrix(obj); for (yy = 0; yy < FUNSEGS; yy++) { y = y0 + (y1 - y0) * yy / FUNSEGS; yn = y0 + (y1 - y0) * (yy + 1) / FUNSEGS; for (xx = 0; xx < FUNSEGS; xx++) { x = x0 + (x1 - x0) * xx / FUNSEGS; xn = x0 + (x1 - x0) * (xx + 1) / FUNSEGS; v[0].x = x; v[0].y = y; v[1].x = xn; v[1].y = y; v[2].x = xn; v[2].y = yn; v[3].x = x; v[3].y = yn; for (i = 0; i < 4; i++) { fz_point pt; float fv[2]; fv[0] = v[i].x; fv[1] = v[i].y; pdf_eval_function(func, fv, 2, v[i].c, shade->colorspace->n); pt.x = v[i].x; pt.y = v[i].y; pt = fz_transform_point(matrix, pt); v[i].x = pt.x; v[i].y = pt.y; } pdf_add_quad(shade, &v[0], &v[1], &v[2], &v[3]); } } }
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)); }