/* SumatraPDF: partial support for file attachment icons */ static pdf_annot * pdf_create_file_annot(pdf_xref *xref, fz_obj *obj) { fz_buffer *content = fz_new_buffer(xref->ctx, 512); fz_rect rect = pdf_to_rect(xref->ctx, fz_dict_gets(xref->ctx, obj, "Rect")); char *icon_name = fz_to_name(xref->ctx, fz_dict_gets(xref->ctx, obj, "Name")); char *content_ap = ANNOT_FILE_ATTACHMENT_AP_PUSHPIN; float rgb[3]; pdf_get_annot_color(xref->ctx, obj, rgb); if (!strcmp(icon_name, "Graph")) content_ap = ANNOT_FILE_ATTACHMENT_AP_GRAPH; else if (!strcmp(icon_name, "Paperclip")) content_ap = ANNOT_FILE_ATTACHMENT_AP_PAPERCLIP; else if (!strcmp(icon_name, "Tag")) content_ap = ANNOT_FILE_ATTACHMENT_AP_TAG; fz_buffer_printf(xref->ctx, content, "q %.4f 0 0 %.4f 0 0 cm ", (rect.x1 - rect.x0) / 24, (rect.y1 - rect.y0) / 24); fz_buffer_printf(xref->ctx, content, content_ap, 0.5, 0.5, 0.5); fz_buffer_printf(xref->ctx, content, " 1 0 0 1 0 1 cm "); fz_buffer_printf(xref->ctx, content, content_ap, rgb[0], rgb[1], rgb[2]); fz_buffer_printf(xref->ctx, content, " Q", content_ap); obj = pdf_clone_for_view_only(xref, obj); return pdf_create_annot(xref->ctx, rect, obj, content, NULL, 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); }
/* SumatraPDF: synthesize appearance streams for a few more annotations */ static pdf_annot * pdf_create_annot(fz_context *ctx, fz_rect rect, fz_obj *base_obj, fz_buffer *content, fz_obj *resources, int transparency) { pdf_annot *annot; pdf_xobject *form; int rotate = fz_to_int(ctx, fz_dict_gets(ctx, fz_dict_gets(ctx, base_obj, "MK"), "R")); form = fz_malloc(ctx, sizeof(pdf_xobject)); memset(form, 0, sizeof(pdf_xobject)); form->refs = 1; form->matrix = fz_rotate(rotate); form->bbox.x1 = (rotate % 180 == 0) ? rect.x1 - rect.x0 : rect.y1 - rect.y0; form->bbox.y1 = (rotate % 180 == 0) ? rect.y1 - rect.y0 : rect.x1 - rect.x0; form->transparency = transparency; form->isolated = !transparency; form->contents = content; form->resources = resources; annot = fz_malloc(ctx, sizeof(pdf_annot)); annot->obj = base_obj; annot->rect = rect; annot->ap = form; annot->next = NULL; pdf_transform_annot(annot); return annot; }
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); }
/* * 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; }
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); }
/* cf. http://bugs.ghostscript.com/show_bug.cgi?id=692078 */ static fz_obj * pdf_dict_get_inheritable(pdf_xref *xref, fz_obj *obj, char *key) { fz_context *ctx = xref->ctx; while (obj) { fz_obj *val = fz_dict_gets(ctx, obj, key); if (val) return val; obj = fz_dict_gets(ctx, obj, "Parent"); } return fz_dict_gets(ctx, fz_dict_gets(ctx, fz_dict_gets(ctx, xref->trailer, "Root"), "AcroForm"), key); }
fz_outline * pdf_load_outline(pdf_document *xref) { fz_obj *root, *obj, *first; root = fz_dict_gets(xref->trailer, "Root"); obj = fz_dict_gets(root, "Outlines"); first = fz_dict_gets(obj, "First"); if (first) return pdf_load_outline_imp(xref, first); return NULL; }
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 const char* _pdf_doc_title(struct _pdf_doc *self) { if (self->xref) { fz_obj *info, *obj; info = fz_dict_gets(self->xref->trailer, "Info"); if (info) { obj = fz_dict_gets(info, "Title"); if (obj) return pdf_to_utf8(obj); } } return NULL; }
fz_outline * pdf_load_outline(pdf_xref *xref) { fz_obj *root, *obj, *first; fz_context *ctx = xref->ctx; root = fz_dict_gets(ctx, xref->trailer, "Root"); obj = fz_dict_gets(ctx, root, "Outlines"); first = fz_dict_gets(ctx, obj, "First"); if (first) return pdf_load_outline_imp(xref, first); return NULL; }
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_obj * pdf_get_ap_stream(pdf_xref *xref, fz_obj *obj) { fz_obj *ap = fz_dict_gets(xref->ctx, obj, "AP"); if (!fz_is_dict(xref->ctx, ap)) return NULL; ap = fz_dict_gets(xref->ctx, ap, "N"); if (!pdf_is_stream(xref, fz_to_num(ap), fz_to_gen(ap))) ap = fz_dict_get(xref->ctx, ap, fz_dict_gets(xref->ctx, obj, "AS")); if (!pdf_is_stream(xref, fz_to_num(ap), fz_to_gen(ap))) return NULL; return ap; }
/* * Load raw (compressed but decrypted) contents of a stream into buf. */ fz_error pdf_load_raw_stream(fz_buffer **bufp, pdf_xref *xref, int num, int gen) { fz_error error; fz_stream *stm; fz_obj *dict; int len; 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")); fz_drop_obj(dict); error = pdf_open_raw_stream(&stm, xref, num, gen); if (error) return fz_rethrow(error, "cannot open raw stream (%d %d R)", num, gen); 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; }
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 sweepref(fz_obj *obj) { int num = fz_to_num(obj); int gen = fz_to_gen(obj); if (num < 0 || num >= xref->len) return; if (uselist[num]) return; uselist[num] = 1; /* Bake in /Length in stream objects */ fz_try(ctx) { if (pdf_is_stream(xref, num, gen)) { fz_obj *len = fz_dict_gets(obj, "Length"); if (fz_is_indirect(len)) { uselist[fz_to_num(len)] = 0; len = fz_resolve_indirect(len); fz_dict_puts(obj, "Length", len); } } } fz_catch(ctx) { /* Leave broken */ } sweepobj(fz_resolve_indirect(obj)); }
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 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 void writexref(void) { fz_obj *trailer; fz_obj *obj; int startxref; int num; startxref = ftell(out); fprintf(out, "xref\n0 %d\n", xref->len); for (num = 0; num < xref->len; num++) { if (uselist[num]) fprintf(out, "%010d %05d n \n", ofslist[num], genlist[num]); else fprintf(out, "%010d %05d f \n", ofslist[num], genlist[num]); } fprintf(out, "\n"); trailer = fz_new_dict(ctx, 5); obj = fz_new_int(ctx, xref->len); fz_dict_puts(trailer, "Size", obj); fz_drop_obj(obj); obj = fz_dict_gets(xref->trailer, "Info"); if (obj) fz_dict_puts(trailer, "Info", obj); obj = fz_dict_gets(xref->trailer, "Root"); if (obj) fz_dict_puts(trailer, "Root", obj); obj = fz_dict_gets(xref->trailer, "ID"); if (obj) fz_dict_puts(trailer, "ID", obj); fprintf(out, "trailer\n"); fz_fprint_obj(out, trailer, doexpand == 0); fprintf(out, "\n"); fz_drop_obj(trailer); fprintf(out, "startxref\n%d\n%%%%EOF\n", startxref); }
/* SumatraPDF: partial support for text icons */ static pdf_annot * pdf_create_text_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")); char *icon_name = fz_to_name(ctx, fz_dict_gets(ctx, obj, "Name")); char *content_ap = ANNOT_TEXT_AP_NOTE; float rgb[3]; rect.x1 = rect.x0 + 24; rect.y0 = rect.y1 - 24; pdf_get_annot_color(ctx, obj, rgb); if (!strcmp(icon_name, "Comment")) content_ap = ANNOT_TEXT_AP_COMMENT; else if (!strcmp(icon_name, "Key")) content_ap = ANNOT_TEXT_AP_KEY; else if (!strcmp(icon_name, "Help")) content_ap = ANNOT_TEXT_AP_HELP; else if (!strcmp(icon_name, "Paragraph")) content_ap = ANNOT_TEXT_AP_PARAGRAPH; else if (!strcmp(icon_name, "NewParagraph")) content_ap = ANNOT_TEXT_AP_NEW_PARAGRAPH; else if (!strcmp(icon_name, "Insert")) content_ap = ANNOT_TEXT_AP_INSERT; else if (!strcmp(icon_name, "Cross")) content_ap = ANNOT_TEXT_AP_CROSS; else if (!strcmp(icon_name, "Circle")) content_ap = ANNOT_TEXT_AP_CIRCLE; // TODO: make icons semi-transparent (cf. pdf_create_highlight_annot)? fz_buffer_printf(ctx, content, "q "); fz_buffer_printf(ctx, content, content_ap, 0.5, 0.5, 0.5); fz_buffer_printf(ctx, content, " 1 0 0 1 0 1 cm "); fz_buffer_printf(ctx, content, content_ap, rgb[0], rgb[1], rgb[2]); fz_buffer_printf(ctx, content, " Q", content_ap); obj = pdf_clone_for_view_only(xref, obj); return pdf_create_annot(ctx, rect, obj, content, NULL, 0); }
static fz_outline * pdf_load_outline_imp(pdf_document *xref, fz_obj *dict) { fz_context *ctx = xref->ctx; fz_outline *node, **prev, *first; fz_obj *obj; fz_obj *odict = dict; fz_var(dict); fz_try(ctx) { first = NULL; prev = &first; while (dict && fz_is_dict(dict)) { if (fz_dict_mark(dict)) break; node = fz_malloc_struct(ctx, fz_outline); node->title = NULL; node->dest.kind = FZ_LINK_NONE; node->down = NULL; node->next = NULL; *prev = node; prev = &node->next; obj = fz_dict_gets(dict, "Title"); if (obj) node->title = pdf_to_utf8(ctx, obj); if ((obj = fz_dict_gets(dict, "Dest"))) node->dest = pdf_parse_link_dest(xref, obj); else if ((obj = fz_dict_gets(dict, "A"))) node->dest = pdf_parse_action(xref, obj); obj = fz_dict_gets(dict, "First"); if (obj) node->down = pdf_load_outline_imp(xref, obj); dict = fz_dict_gets(dict, "Next"); } } fz_catch(ctx) { for (dict = odict; dict && fz_dict_marked(dict); dict = fz_dict_gets(dict, "Next")) fz_dict_unmark(dict); fz_rethrow(ctx); } for (dict = odict; dict && fz_dict_marked(dict); dict = fz_dict_gets(dict, "Next")) fz_dict_unmark(dict); return first; }
static fz_error pdf_read_xref_sections(pdf_xref *xref, int ofs, char *buf, int cap) { fz_error error; fz_obj *trailer; fz_obj *prev; fz_obj *xrefstm; error = pdf_read_xref(&trailer, xref, ofs, buf, cap); if (error) return fz_rethrow(error, "cannot read xref section"); /* FIXME: do we overwrite free entries properly? */ xrefstm = fz_dict_gets(trailer, "XRefStm"); if (xrefstm) { error = pdf_read_xref_sections(xref, fz_to_int(xrefstm), buf, cap); if (error) { fz_drop_obj(trailer); return fz_rethrow(error, "cannot read /XRefStm xref section"); } } prev = fz_dict_gets(trailer, "Prev"); if (prev) { error = pdf_read_xref_sections(xref, fz_to_int(prev), buf, cap); if (error) { fz_drop_obj(trailer); return fz_rethrow(error, "cannot read /Prev xref section"); } } fz_drop_obj(trailer); return fz_okay; }
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 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; }
static pdf_annot * pdf_create_freetext_annot(pdf_xref *xref, fz_obj *obj) { fz_context *ctx = xref->ctx; fz_buffer *content = fz_new_buffer(ctx, 256); fz_buffer *base_ap = fz_new_buffer(ctx, 256); fz_obj *ap = fz_dict_gets(ctx, obj, "DA"); fz_obj *value = fz_dict_gets(ctx, obj, "Contents"); fz_rect rect = pdf_to_rect(ctx, fz_dict_gets(ctx, obj, "Rect")); int align = fz_to_int(ctx, fz_dict_gets(ctx, obj, "Q")); fz_obj *res = pdf_dict_from_string(xref, ANNOT_FREETEXT_AP_RESOURCES); unsigned short *ucs2, *rest; float x; char *font_name = NULL; float font_size = pdf_extract_font_size(xref, fz_to_str_buf(ctx, ap), &font_name); if (!font_size) font_size = 10; /* TODO: what resource dictionary does this font name refer to? */ if (font_name) { fz_obj *font = fz_dict_gets(ctx, res, "Font"); fz_dict_puts(ctx, font, font_name, fz_dict_gets(ctx, font, "Default")); fz_free(ctx, font_name); } fz_buffer_printf(ctx, content, "q 1 1 %.4f %.4f re W n BT %s ", rect.x1 - rect.x0 - 2.0f, rect.y1 - rect.y0 - 2.0f, fz_to_str_buf(ctx, ap)); fz_buffer_printf(ctx, base_ap, "q BT %s ", fz_to_str_buf(ctx, ap)); fz_buffer_printf(ctx, content, "/Default %.4f Tf ", font_size); fz_buffer_printf(ctx, base_ap, "/Default %.4f Tf ", font_size); fz_buffer_printf(ctx, content, "1 0 0 1 2 %.4f Tm ", rect.y1 - rect.y0 - 2); /* Adobe Reader seems to consider "[1 0 0] r" and "1 0 0 rg" to mean the same(?) */ if (strchr(base_ap->data, '[')) { float r, g, b; if (sscanf(strchr(base_ap->data, '['), "[%f %f %f] r", &r, &g, &b) == 3) fz_buffer_printf(ctx, content, "%.4f %.4f %.4f rg ", r, g, b); } ucs2 = pdf_to_ucs2(ctx, value); for (rest = ucs2; *rest; rest++) if (*rest > 0xFF) *rest = '?'; x = 0; rest = ucs2; while (*rest) rest = pdf_append_line(xref, res, content, base_ap, rest, font_size, align, rect.x1 - rect.x0 - 4.0f, 1, &x); fz_free(ctx, ucs2); fz_buffer_printf(ctx, content, "ET Q"); fz_drop_buffer(ctx, base_ap); return pdf_create_annot(ctx, rect, fz_keep_obj(obj), content, res, 0); }
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); }
static fz_error load_icc_based(fz_colorspace **csp, pdf_xref *xref, fz_obj *dict) { int n; n = fz_to_int(fz_dict_gets(dict, "N")); switch (n) { case 1: *csp = fz_device_gray; return fz_okay; case 3: *csp = fz_device_rgb; return fz_okay; case 4: *csp = fz_device_cmyk; return fz_okay; } return fz_throw("syntaxerror: ICCBased must have 1, 3 or 4 components"); }
static fz_colorspace * load_icc_based(pdf_document *xref, fz_obj *dict) { int n; n = fz_to_int(fz_dict_gets(dict, "N")); switch (n) { case 1: return fz_device_gray; case 3: return fz_device_rgb; case 4: return fz_device_cmyk; } fz_throw(xref->ctx, "syntaxerror: ICCBased must have 1, 3 or 4 components"); return NULL; /* Stupid MSVC */ }
static fz_error pdf_load_xref(pdf_xref *xref, char *buf, int bufsize) { fz_error error; fz_obj *size; int i; error = pdf_load_version(xref); if (error) return fz_rethrow(error, "cannot read version marker"); error = pdf_read_start_xref(xref); if (error) return fz_rethrow(error, "cannot read startxref"); error = pdf_read_trailer(xref, buf, bufsize); if (error) return fz_rethrow(error, "cannot read trailer"); size = fz_dict_gets(xref->trailer, "Size"); if (!size) return fz_throw("trailer missing Size entry"); pdf_resize_xref(xref, fz_to_int(size)); error = pdf_read_xref_sections(xref, xref->startxref, buf, bufsize); if (error) return fz_rethrow(error, "cannot read xref"); /* broken pdfs where first object is not free */ if (xref->table[0].type != 'f') return fz_throw("first object in xref is not free"); /* broken pdfs where object offsets are out of range */ for (i = 0; i < xref->len; i++) { if (xref->table[i].type == 'n') if (xref->table[i].ofs <= 0 || xref->table[i].ofs >= xref->file_size) return fz_throw("object offset out of range: %d (%d 0 R)", xref->table[i].ofs, i); if (xref->table[i].type == 'o') if (xref->table[i].ofs <= 0 || xref->table[i].ofs >= xref->len || xref->table[xref->table[i].ofs].type != 'n') return fz_throw("invalid reference to an objstm that does not exist: %d (%d 0 R)", xref->table[i].ofs, i); } return fz_okay; }