/* 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); }
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 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); }
fz_rect pdf_to_rect(fz_obj *array) { fz_rect r; float a = fz_to_real(fz_array_get(array, 0)); float b = fz_to_real(fz_array_get(array, 1)); float c = fz_to_real(fz_array_get(array, 2)); float d = fz_to_real(fz_array_get(array, 3)); r.x0 = MIN(a, c); r.y0 = MIN(b, d); r.x1 = MAX(a, c); r.y1 = MAX(b, d); return r; }
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); }
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; }
/* * 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; }
static void pdf_get_annot_color(fz_context *ctx, fz_obj *obj, float rgb[3]) { int k; obj = fz_dict_gets(ctx, obj, "C"); for (k = 0; k < 3; k++) rgb[k] = fz_to_real(ctx, fz_array_get(ctx, obj, k)); }
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; }
/* a: top/left to bottom/right; b: bottom/left to top/right */ static void pdf_get_quadrilaterals(fz_context *ctx, fz_obj *quad_points, int i, fz_rect *a, fz_rect *b) { a->x0 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 0)); a->y0 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 1)); b->x1 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 2)); b->y1 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 3)); b->x0 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 4)); b->y0 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 5)); a->x1 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 6)); a->y1 = fz_to_real(ctx, fz_array_get(ctx, quad_points, i * 8 + 7)); }
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 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); }
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 mume_rect_t _pdf_doc_get_link_dest_rect( struct _pdf_doc *self, pdf_link *link) { mume_rect_t rect = mume_rect_empty; fz_obj *dest = link->dest; fz_obj *obj = fz_array_get(dest, 1); const char *type = fz_to_name(obj); if (strcmp(type, "XYZ") == 0) { /* NULL values for the coordinates mean: keep the * current position. */ if (!fz_is_null(fz_array_get(dest, 2))) rect.x = round(fz_to_real(fz_array_get(dest, 2))); if (!fz_is_null(fz_array_get(dest, 3))) rect.y = round(fz_to_real(fz_array_get(dest, 3))); } else if (strcmp(type, "FitR") == 0) { double x0, y0, x1, y1; x0 = fz_to_real(fz_array_get(dest, 2)); y0 = fz_to_real(fz_array_get(dest, 5)); x1 = fz_to_real(fz_array_get(dest, 4)); y1 = fz_to_real(fz_array_get(dest, 3)); rect.x = round(x0); rect.y = round(y0); rect.width = round(x1 - x0); rect.height = round(y1 - y0); } else if (strcmp(type, "FitH") == 0 || strcmp(type, "FitBH") == 0) { rect.y = round(fz_to_real(fz_array_get(dest, 2))); } return rect; }
fz_matrix pdf_to_matrix(fz_obj *array) { fz_matrix m; m.a = fz_to_real(fz_array_get(array, 0)); m.b = fz_to_real(fz_array_get(array, 1)); m.c = fz_to_real(fz_array_get(array, 2)); m.d = fz_to_real(fz_array_get(array, 3)); m.e = fz_to_real(fz_array_get(array, 4)); m.f = fz_to_real(fz_array_get(array, 5)); return m; }
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; }
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 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 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 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 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 load_indexed(fz_colorspace **csp, pdf_xref *xref, fz_obj *array) { fz_error error; fz_colorspace *cs; struct indexed *idx; fz_obj *baseobj = fz_array_get(array, 1); fz_obj *highobj = fz_array_get(array, 2); fz_obj *lookup = fz_array_get(array, 3); fz_colorspace *base; int i, n; 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)); idx = fz_malloc(sizeof(struct indexed)); idx->base = base; idx->high = fz_to_int(highobj); idx->high = CLAMP(idx->high, 0, 255); n = base->n * (idx->high + 1); idx->lookup = fz_malloc(n); memset(idx->lookup, 0, n); cs = fz_new_colorspace("Indexed", 1); cs->to_rgb = indexed_to_rgb; cs->free_data = free_indexed; cs->data = idx; if (fz_is_string(lookup) && fz_to_str_len(lookup) == n) { unsigned char *buf = (unsigned char *) fz_to_str_buf(lookup); for (i = 0; i < n; i++) idx->lookup[i] = buf[i]; } else if (fz_is_indirect(lookup)) { fz_stream *file; error = pdf_open_stream(&file, xref, fz_to_num(lookup), fz_to_gen(lookup)); if (error) { fz_drop_colorspace(cs); return fz_rethrow(error, "cannot open colorspace lookup table (%d 0 R)", fz_to_num(lookup)); } i = fz_read(file, idx->lookup, n); if (i < 0) { fz_drop_colorspace(cs); return fz_throw("cannot read colorspace lookup table (%d 0 R)", fz_to_num(lookup)); } fz_close(file); } else { fz_drop_colorspace(cs); return fz_throw("cannot parse colorspace lookup table"); } *csp = cs; return fz_okay; }
static fz_colorspace * load_indexed(pdf_document *xref, fz_obj *array) { struct indexed *idx = NULL; fz_context *ctx = xref->ctx; fz_obj *baseobj = fz_array_get(array, 1); fz_obj *highobj = fz_array_get(array, 2); fz_obj *lookup = fz_array_get(array, 3); fz_colorspace *base = NULL; fz_colorspace *cs = NULL; int i, n; fz_var(idx); fz_var(base); fz_var(cs); fz_try(ctx) { base = pdf_load_colorspace(xref, baseobj); /* "cannot load base colorspace (%d %d R)", fz_to_num(baseobj), fz_to_gen(baseobj) */ idx = fz_malloc_struct(ctx, struct indexed); idx->lookup = NULL; idx->base = base; idx->high = fz_to_int(highobj); idx->high = CLAMP(idx->high, 0, 255); n = base->n * (idx->high + 1); idx->lookup = fz_malloc_array(ctx, 1, n); cs = fz_new_colorspace(ctx, "Indexed", 1); cs->to_rgb = indexed_to_rgb; cs->free_data = free_indexed; cs->data = idx; cs->size += sizeof(*idx) + n + (base ? base->size : 0); if (fz_is_string(lookup) && fz_to_str_len(lookup) == n) { unsigned char *buf = (unsigned char *) fz_to_str_buf(lookup); for (i = 0; i < n; i++) idx->lookup[i] = buf[i]; } else if (fz_is_indirect(lookup)) { fz_stream *file = NULL; fz_try(ctx) { file = pdf_open_stream(xref, fz_to_num(lookup), fz_to_gen(lookup)); } fz_catch(ctx) { fz_throw(ctx, "cannot open colorspace lookup table (%d 0 R)", fz_to_num(lookup)); } i = fz_read(file, idx->lookup, n); if (i < 0) { fz_close(file); fz_throw(ctx, "cannot read colorspace lookup table (%d 0 R)", fz_to_num(lookup)); } fz_close(file); } else { fz_throw(ctx, "cannot parse colorspace lookup table"); } }
void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int modifiers, int state) { pdf_link *link; fz_matrix ctm; fz_point p; p.x = x - app->panx + app->image->x; p.y = y - app->pany + app->image->y; ctm = pdfapp_viewctm(app); ctm = fz_invert_matrix(ctm); p = fz_transform_point(ctm, p); for (link = app->page_links; link; link = link->next) { if (p.x >= link->rect.x0 && p.x <= link->rect.x1) if (p.y >= link->rect.y0 && p.y <= link->rect.y1) break; } if (link) { wincursor(app, HAND); if (btn == 1 && state == 1) { if (link->kind == PDF_LINK_URI) pdfapp_gotouri(app, link->dest); else if (link->kind == PDF_LINK_GOTO) pdfapp_gotopage(app, fz_array_get(link->dest, 0)); /* [ pageobj ... ] */ return; } } else { wincursor(app, ARROW); } if (state == 1) { if (btn == 1 && !app->iscopying) { app->ispanning = 1; app->selx = x; app->sely = y; app->beyondy = 0; } if (btn == 3 && !app->ispanning) { app->iscopying = 1; app->selx = x; app->sely = y; app->selr.x0 = x; app->selr.x1 = x; app->selr.y0 = y; app->selr.y1 = y; } if (btn == 4 || btn == 5) /* scroll wheel */ { int dir = btn == 4 ? 1 : -1; app->ispanning = app->iscopying = 0; if (modifiers & (1<<2)) { /* zoom in/out if ctrl is pressed */ if (dir > 0) app->resolution *= ZOOMSTEP; else app->resolution /= ZOOMSTEP; if (app->resolution > MAXRES) app->resolution = MAXRES; if (app->resolution < MINRES) app->resolution = MINRES; pdfapp_showpage(app, 0, 1, 1); } else { /* scroll up/down, or left/right if shift is pressed */ int isx = (modifiers & (1<<0)); int xstep = isx ? 20 * dir : 0; int ystep = !isx ? 20 * dir : 0; pdfapp_panview(app, app->panx + xstep, app->pany + ystep); } } } else if (state == -1) { if (app->iscopying) { app->iscopying = 0; app->selr.x0 = MIN(app->selx, x) - app->panx + app->image->x; app->selr.x1 = MAX(app->selx, x) - app->panx + app->image->x; app->selr.y0 = MIN(app->sely, y) - app->pany + app->image->y; app->selr.y1 = MAX(app->sely, y) - app->pany + app->image->y; winrepaint(app); if (app->selr.x0 < app->selr.x1 && app->selr.y0 < app->selr.y1) windocopy(app); } if (app->ispanning) app->ispanning = 0; } else if (app->ispanning) { int newx = app->panx + x - app->selx; int newy = app->pany + y - app->sely; /* Scrolling beyond limits implies flipping pages */ /* Are we requested to scroll beyond limits? */ if (newy + app->image->h < app->winh || newy > 0) { /* Yes. We can assume that deltay != 0 */ int deltay = y - app->sely; /* Check whether the panning has occured in the * direction that we are already crossing the * limit it. If not, we can conclude that we * have switched ends of the page and will thus * start over counting. */ if( app->beyondy == 0 || (app->beyondy ^ deltay) >= 0 ) { /* Updating how far we are beyond and * flipping pages if beyond threshhold */ app->beyondy += deltay; if (app->beyondy > BEYOND_THRESHHOLD) { if( app->pageno > 1 ) { app->pageno--; pdfapp_showpage(app, 1, 1, 1); newy = -app->image->h; } app->beyondy = 0; } else if (app->beyondy < -BEYOND_THRESHHOLD) { if( app->pageno < app->pagecount ) { app->pageno++; pdfapp_showpage(app, 1, 1, 1); newy = 0; } app->beyondy = 0; } } else app->beyondy = 0; } /* Although at this point we've already determined that * or that no scrolling will be performed in * y-direction, the x-direction has not yet been taken * care off. Therefore */ pdfapp_panview(app, newx, newy); app->selx = x; app->sely = y; } else if (app->iscopying) { app->selr.x0 = MIN(app->selx, x) - app->panx + app->image->x; app->selr.x1 = MAX(app->selx, x) - app->panx + app->image->x; app->selr.y0 = MIN(app->sely, y) - app->pany + app->image->y; app->selr.y1 = MAX(app->sely, y) - app->pany + app->image->y; winrepaint(app); } }
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 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_outline * pdf_load_outline_imp(pdf_xref *xref, fz_obj *dict) { pdf_link *link; fz_outline *node; fz_obj *obj; /* SumatraPDF: prevent potential stack overflow */ fz_outline *prev, *root = NULL; fz_obj *origDict = dict; fz_context *ctx = xref->ctx; if (fz_is_null(ctx, dict)) return NULL; /* SumatraPDF: prevent cyclic outlines */ do { if (fz_dict_gets(ctx, dict, ".seen")) break; obj = fz_new_null(ctx); fz_dict_puts(ctx, dict, ".seen", obj); fz_drop_obj(ctx, obj); node = fz_malloc(ctx, sizeof(fz_outline)); node->title = NULL; node->page = -1; node->down = NULL; node->next = NULL; obj = fz_dict_gets(ctx, dict, "Title"); if (obj) node->title = pdf_to_utf8(ctx, obj); /* SumatraPDF: support expansion states */ node->is_open = fz_to_int(ctx, fz_dict_gets(ctx, dict, "Count")) >= 0; /* SumatraPDF: extended outline actions */ node->data = node->free_data = NULL; if (fz_dict_gets(ctx, dict, "Dest") || fz_dict_gets(ctx, dict, "A")) { link = pdf_load_link(xref, dict); if (link) /* SumatraPDF: don't crash if it's no link after all */ { if (link->kind == PDF_LINK_GOTO) node->page = pdf_find_page_number(xref, fz_array_get(ctx, link->dest, 0)); /* SumatraPDF: extended outline actions */ node->data = link; node->free_data = pdf_free_link; } } obj = fz_dict_gets(ctx, dict, "First"); if (obj) node->down = pdf_load_outline_imp(xref, obj); /* SumatraPDF: prevent potential stack overflow */ if (!root) prev = root = node; else prev = prev->next = node; dict = fz_dict_gets(ctx, dict, "Next"); } while (dict && !fz_is_null(ctx, dict)); node = root; /* SumatraPDF: prevent cyclic outlines */ for (dict = origDict; dict && fz_dict_gets(ctx, dict, ".seen"); dict = fz_dict_gets(ctx, dict, "Next")) fz_dict_dels(ctx, dict, ".seen"); return node; }