static void pdf_write_ch_widget_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect, fz_rect *bbox, fz_matrix *matrix, pdf_obj **res) { int ff = pdf_field_flags(ctx, annot->obj); if (ff & PDF_CH_FIELD_IS_COMBO) { /* TODO: Pop-down arrow */ pdf_write_tx_widget_appearance(ctx, annot, buf, rect, bbox, matrix, res, pdf_field_value(ctx, annot->obj), 0); } else { fz_buffer *text = fz_new_buffer(ctx, 1024); fz_try(ctx) { pdf_obj *opt = pdf_dict_get(ctx, annot->obj, PDF_NAME(Opt)); int i = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(TI)); int n = pdf_array_len(ctx, opt); /* TODO: Scrollbar */ /* TODO: Highlight selected items */ if (i < 0) i = 0; for (; i < n; ++i) { pdf_obj *val = pdf_array_get(ctx, opt, i); if (pdf_is_array(ctx, val)) fz_append_string(ctx, text, pdf_array_get_text_string(ctx, val, 1)); else fz_append_string(ctx, text, pdf_to_text_string(ctx, val)); fz_append_byte(ctx, text, '\n'); } pdf_write_tx_widget_appearance(ctx, annot, buf, rect, bbox, matrix, res, fz_string_from_buffer(ctx, text), PDF_TX_FIELD_IS_MULTILINE); } fz_always(ctx) fz_drop_buffer(ctx, text); fz_catch(ctx) fz_rethrow(ctx); } }
void pdf_set_text_annot_position(fz_context *ctx, pdf_annot *annot, fz_point pt) { fz_matrix page_ctm, inv_page_ctm; fz_rect rect; int flags; pdf_page_transform(ctx, annot->page, NULL, &page_ctm); fz_invert_matrix(&inv_page_ctm, &page_ctm); rect.x0 = pt.x; rect.x1 = pt.x + TEXT_ANNOT_SIZE; rect.y0 = pt.y; rect.y1 = pt.y + TEXT_ANNOT_SIZE; fz_transform_rect(&rect, &inv_page_ctm); pdf_dict_put_rect(ctx, annot->obj, PDF_NAME(Rect), &rect); flags = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F)); flags |= (PDF_ANNOT_IS_NO_ZOOM|PDF_ANNOT_IS_NO_ROTATE); pdf_dict_put_int(ctx, annot->obj, PDF_NAME(F), flags); }
static void pdf_write_free_text_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect, fz_rect *bbox, fz_matrix *matrix, pdf_obj **res) { const char *font; float size, color[3]; const char *text; float w, h, t, b; int q, r; /* /Rotate is an undocumented annotation property supported by Adobe */ text = pdf_annot_contents(ctx, annot); r = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(Rotate)); q = pdf_annot_quadding(ctx, annot); pdf_annot_default_appearance(ctx, annot, &font, &size, color); w = rect->x1 - rect->x0; h = rect->y1 - rect->y0; if (r == 90 || r == 270) t = h, h = w, w = t; *matrix = fz_rotate(r); *bbox = fz_make_rect(0, 0, w, h); if (pdf_write_fill_color_appearance(ctx, annot, buf)) fz_append_printf(ctx, buf, "0 0 %g %g re\nf\n", w, h); b = pdf_write_border_appearance(ctx, annot, buf); if (b > 0) { fz_append_printf(ctx, buf, "%g %g %g RG\n", color[0], color[1], color[2]); fz_append_printf(ctx, buf, "%g %g %g %g re\nS\n", b/2, b/2, w-b, h-b); } fz_append_printf(ctx, buf, "%g %g %g %g re\nW\nn\n", b, b, w-b*2, h-b*2); write_variable_text(ctx, annot, buf, res, text, font, size, color, q, w, h, b*2, 0.8f, 1.2f, 1, 0, 0); }
/* Performs the same task as pdf_clean_page_contents, but with an optional text filter function. text_filter: Function to assess whether a given character should be kept (return 0) or removed (return 1). after_text: Function called after each text object is closed to allow other output to be sent. arg: Opaque value to be passed to callback functions. */ void pdf_filter_page_contents(fz_context *ctx, pdf_document *doc, pdf_page *page, fz_cookie *cookie, pdf_page_contents_process_fn *proc_fn, pdf_text_filter_fn *text_filter, pdf_after_text_object_fn *after_text, void *proc_arg, int sanitize, int ascii) { pdf_processor *proc_buffer = NULL; pdf_processor *proc_filter = NULL; pdf_obj *new_obj = NULL; pdf_obj *new_ref = NULL; pdf_obj *res = NULL; pdf_obj *obj; pdf_obj *contents; pdf_obj *resources; fz_buffer *buffer; fz_var(new_obj); fz_var(new_ref); fz_var(res); fz_var(proc_buffer); fz_var(proc_filter); buffer = fz_new_buffer(ctx, 1024); fz_try(ctx) { contents = pdf_page_contents(ctx, page); resources = pdf_page_resources(ctx, page); proc_buffer = pdf_new_buffer_processor(ctx, buffer, ascii); if (sanitize) { res = pdf_new_dict(ctx, doc, 1); proc_filter = pdf_new_filter_processor_with_text_filter(ctx, doc, proc_buffer, resources, res, text_filter, after_text, proc_arg); pdf_process_contents(ctx, proc_filter, doc, resources, contents, cookie); pdf_close_processor(ctx, proc_filter); } else { res = pdf_keep_obj(ctx, resources); pdf_process_contents(ctx, proc_buffer, doc, resources, contents, cookie); } pdf_close_processor(ctx, proc_buffer); /* Deal with page content stream. */ if (pdf_is_array(ctx, contents)) { /* create a new object to replace the array */ new_obj = pdf_new_dict(ctx, doc, 1); new_ref = pdf_add_object(ctx, doc, new_obj); contents = new_ref; pdf_dict_put(ctx, page->obj, PDF_NAME(Contents), contents); } else { pdf_dict_del(ctx, contents, PDF_NAME(Filter)); pdf_dict_del(ctx, contents, PDF_NAME(DecodeParms)); } pdf_update_stream(ctx, doc, contents, buffer, 0); /* Now deal with resources. The spec allows for Type3 fonts and form * XObjects to omit a resource dictionary and look in the parent. * Avoid that by flattening here as part of the cleaning. This could * conceivably cause changes in rendering, but we don't care. */ /* ExtGState */ obj = pdf_dict_get(ctx, res, PDF_NAME(ExtGState)); if (obj) { int i, l; l = pdf_dict_len(ctx, obj); for (i = 0; i < l; i++) { pdf_obj *o = pdf_dict_get(ctx, pdf_dict_get_val(ctx, obj, i), PDF_NAME(SMask)); if (!o) continue; o = pdf_dict_get(ctx, o, PDF_NAME(G)); if (!o) continue; /* Transparency group XObject */ pdf_clean_stream_object(ctx, doc, o, resources, cookie, 1, text_filter, after_text, proc_arg, sanitize, ascii); } } /* Pattern */ obj = pdf_dict_get(ctx, res, PDF_NAME(Pattern)); if (obj) { int i, l; l = pdf_dict_len(ctx, obj); for (i = 0; i < l; i++) { pdf_obj *pat_res; pdf_obj *pat = pdf_dict_get_val(ctx, obj, i); if (!pat) continue; pat_res = pdf_dict_get(ctx, pat, PDF_NAME(Resources)); if (pat_res == NULL) pat_res = resources; if (pdf_dict_get_int(ctx, pat, PDF_NAME(PatternType)) == 1) pdf_clean_stream_object(ctx, doc, pat, pat_res, cookie, 0, text_filter, after_text, proc_arg, sanitize, ascii); } } /* XObject */ obj = pdf_dict_get(ctx, res, PDF_NAME(XObject)); if (obj) { int i, l; l = pdf_dict_len(ctx, obj); for (i = 0; i < l; i++) { pdf_obj *xobj_res; pdf_obj *xobj = pdf_dict_get_val(ctx, obj, i); if (!xobj) continue; xobj_res = pdf_dict_get(ctx, xobj, PDF_NAME(Resources)); if (xobj_res == NULL) xobj_res = resources; if (pdf_name_eq(ctx, PDF_NAME(Form), pdf_dict_get(ctx, xobj, PDF_NAME(Subtype)))) pdf_clean_stream_object(ctx, doc, xobj, xobj_res, cookie, 1, text_filter, after_text, proc_arg, sanitize, ascii); } } /* Font */ obj = pdf_dict_get(ctx, res, PDF_NAME(Font)); if (obj) { int i, l; l = pdf_dict_len(ctx, obj); for (i = 0; i < l; i++) { pdf_obj *o = pdf_dict_get_val(ctx, obj, i); if (!o) continue; if (pdf_name_eq(ctx, PDF_NAME(Type3), pdf_dict_get(ctx, o, PDF_NAME(Subtype)))) pdf_clean_type3(ctx, doc, o, resources, cookie, sanitize, ascii); } } /* ProcSet - no cleaning possible. Inherit this from the old dict. */ obj = pdf_dict_get(ctx, resources, PDF_NAME(ProcSet)); if (obj) pdf_dict_put(ctx, res, PDF_NAME(ProcSet), obj); /* ColorSpace - no cleaning possible. */ /* Properties - no cleaning possible. */ if (proc_fn) (*proc_fn)(ctx, buffer, res, proc_arg); /* Update resource dictionary */ if (sanitize) { pdf_dict_put(ctx, page->obj, PDF_NAME(Resources), res); } } fz_always(ctx) { pdf_drop_processor(ctx, proc_filter); pdf_drop_processor(ctx, proc_buffer); fz_drop_buffer(ctx, buffer); pdf_drop_obj(ctx, new_obj); pdf_drop_obj(ctx, new_ref); pdf_drop_obj(ctx, res); } fz_catch(ctx) { fz_rethrow(ctx); } }
int pdf_annot_quadding(fz_context *ctx, pdf_annot *annot) { int q = pdf_dict_get_int(ctx, annot->obj, PDF_NAME(Q)); return (q < 0 || q > 2) ? 0 : q; }
int pdf_annot_flags(fz_context *ctx, pdf_annot *annot) { return pdf_dict_get_int(ctx, annot->obj, PDF_NAME(F)); }
static void pdf_update_button_appearance(fz_context *ctx, pdf_annot *annot) { int ff = pdf_field_flags(ctx, annot->obj); fz_rect rect = pdf_dict_get_rect(ctx, annot->obj, PDF_NAME(Rect)); fz_matrix matrix; fz_rect bbox; float w, h, t; int r; r = pdf_dict_get_int(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(R)); w = rect.x1 - rect.x0; h = rect.y1 - rect.y0; if (r == 90 || r == 270) t = h, h = w, w = t; matrix = fz_rotate(r); bbox = fz_make_rect(0, 0, w, h); if (ff & PDF_BTN_FIELD_IS_PUSHBUTTON) { pdf_obj *ap_n = NULL; pdf_obj *ap_d = NULL; fz_var(ap_n); fz_var(ap_d); fz_try(ctx) { pdf_obj *ap, *MK, *CA, *AC; const char *font; const char *label; float size, color[3]; pdf_annot_default_appearance(ctx, annot, &font, &size, color); MK = pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)); CA = pdf_dict_get(ctx, MK, PDF_NAME(CA)); AC = pdf_dict_get(ctx, MK, PDF_NAME(AC)); label = pdf_to_text_string(ctx, CA); ap_n = draw_push_button(ctx, annot, bbox, matrix, w, h, label, font, size, color, 0); label = pdf_to_text_string(ctx, AC ? AC : CA); ap_d = draw_push_button(ctx, annot, bbox, matrix, w, h, label, font, size, color, 1); ap = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(AP), 2); pdf_dict_put(ctx, ap, PDF_NAME(N), ap_n); pdf_dict_put(ctx, ap, PDF_NAME(D), ap_d); pdf_drop_obj(ctx, annot->ap); if (annot->is_hot && annot->is_active) annot->ap = pdf_keep_obj(ctx, ap_d); else annot->ap = pdf_keep_obj(ctx, ap_n); annot->has_new_ap = 1; } fz_always(ctx) { pdf_drop_obj(ctx, ap_n); pdf_drop_obj(ctx, ap_d); } fz_catch(ctx) fz_rethrow(ctx); }
static void pdf_write_tx_widget_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, fz_rect *rect, fz_rect *bbox, fz_matrix *matrix, pdf_obj **res, const char *text, int ff) { const char *font; float size, color[3]; float w, h, t, b; int has_bc = 0; int q, r; r = pdf_dict_get_int(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(MK)), PDF_NAME(R)); q = pdf_annot_quadding(ctx, annot); pdf_annot_default_appearance(ctx, annot, &font, &size, color); w = rect->x1 - rect->x0; h = rect->y1 - rect->y0; if (r == 90 || r == 270) t = h, h = w, w = t; *matrix = fz_rotate(r); *bbox = fz_make_rect(0, 0, w, h); fz_append_string(ctx, buf, "/Tx BMC\nq\n"); if (pdf_write_MK_BG_appearance(ctx, annot, buf)) fz_append_printf(ctx, buf, "0 0 %g %g re\nf\n", w, h); b = pdf_write_border_appearance(ctx, annot, buf); if (b > 0 && pdf_write_MK_BC_appearance(ctx, annot, buf)) { fz_append_printf(ctx, buf, "%g %g %g %g re\ns\n", b/2, b/2, w-b, h-b); has_bc = 1; } fz_append_printf(ctx, buf, "%g %g %g %g re\nW\nn\n", b, b, w-b*2, h-b*2); if (ff & PDF_TX_FIELD_IS_MULTILINE) { write_variable_text(ctx, annot, buf, res, text, font, size, color, q, w, h, b*2, 1.116f, 1.116f, 1, 0, 1); } else if (ff & PDF_TX_FIELD_IS_COMB) { int maxlen = pdf_to_int(ctx, pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(MaxLen))); if (has_bc && maxlen > 1) { float cell_w = (w - 2 * b) / maxlen; int i; for (i = 1; i < maxlen; ++i) { float x = b + cell_w * i; fz_append_printf(ctx, buf, "%g %g m %g %g l s\n", x, b, x, h-b); } } write_variable_text(ctx, annot, buf, res, text, font, size, color, q, w, h, 0, 0.8f, 1.2f, 0, maxlen, 0); } else { write_variable_text(ctx, annot, buf, res, text, font, size, color, q, w, h, b*2, 0.8f, 1.2f, 0, 0, 0); } fz_append_string(ctx, buf, "Q\nEMC\n"); }
static void pdf_load_mesh_params(fz_context *ctx, pdf_document *doc, fz_shade *shade, pdf_obj *dict) { pdf_obj *obj; int i, n; shade->u.m.x0 = shade->u.m.y0 = 0; shade->u.m.x1 = shade->u.m.y1 = 1; for (i = 0; i < FZ_MAX_COLORS; i++) { shade->u.m.c0[i] = 0; shade->u.m.c1[i] = 1; } shade->u.m.vprow = pdf_dict_get_int(ctx, dict, PDF_NAME(VerticesPerRow)); shade->u.m.bpflag = pdf_dict_get_int(ctx, dict, PDF_NAME(BitsPerFlag)); shade->u.m.bpcoord = pdf_dict_get_int(ctx, dict, PDF_NAME(BitsPerCoordinate)); shade->u.m.bpcomp = pdf_dict_get_int(ctx, dict, PDF_NAME(BitsPerComponent)); obj = pdf_dict_get(ctx, dict, PDF_NAME(Decode)); if (pdf_array_len(ctx, obj) >= 6) { n = fz_mini(FZ_MAX_COLORS, (pdf_array_len(ctx, obj) - 4) / 2); shade->u.m.x0 = pdf_array_get_real(ctx, obj, 0); shade->u.m.x1 = pdf_array_get_real(ctx, obj, 1); shade->u.m.y0 = pdf_array_get_real(ctx, obj, 2); shade->u.m.y1 = pdf_array_get_real(ctx, obj, 3); for (i = 0; i < n; i++) { shade->u.m.c0[i] = pdf_array_get_real(ctx, obj, 4 + i * 2); shade->u.m.c1[i] = pdf_array_get_real(ctx, obj, 5 + i * 2); } } if (shade->u.m.vprow < 2 && shade->type == 5) { fz_warn(ctx, "Too few vertices per row (%d)", shade->u.m.vprow); shade->u.m.vprow = 2; } if (shade->u.m.bpflag != 2 && shade->u.m.bpflag != 4 && shade->u.m.bpflag != 8 && shade->type != 5) { fz_warn(ctx, "Invalid number of bits per flag (%d)", shade->u.m.bpflag); shade->u.m.bpflag = 8; } if (shade->u.m.bpcoord != 1 && shade->u.m.bpcoord != 2 && shade->u.m.bpcoord != 4 && shade->u.m.bpcoord != 8 && shade->u.m.bpcoord != 12 && shade->u.m.bpcoord != 16 && shade->u.m.bpcoord != 24 && shade->u.m.bpcoord != 32) { fz_warn(ctx, "Invalid number of bits per coordinate (%d)", shade->u.m.bpcoord); shade->u.m.bpcoord = 8; } if (shade->u.m.bpcomp != 1 && shade->u.m.bpcomp != 2 && shade->u.m.bpcomp != 4 && shade->u.m.bpcomp != 8 && shade->u.m.bpcomp != 12 && shade->u.m.bpcomp != 16) { fz_warn(ctx, "Invalid number of bits per component (%d)", shade->u.m.bpcomp); shade->u.m.bpcomp = 8; } }