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); }
/* 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); }
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); }
/* 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 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 pdf_annot * pdf_update_tx_widget_annot(pdf_xref *xref, fz_obj *obj) { fz_obj *ap, *res, *value; fz_rect rect; fz_buffer *content, *base_ap; int flags, align, rotate, is_multiline; float font_size, x, y; char *font_name; unsigned short *ucs2, *rest; fz_context *ctx = xref->ctx; if (strcmp(fz_to_name(ctx, fz_dict_gets(ctx, obj, "Subtype")), "Widget") != 0) return NULL; if (!fz_to_bool(ctx, pdf_dict_get_inheritable(xref, NULL, "NeedAppearances")) && pdf_get_ap_stream(xref, obj)) return NULL; value = pdf_dict_get_inheritable(xref, obj, "FT"); if (strcmp(fz_to_name(ctx, value), "Tx") != 0) return NULL; ap = pdf_dict_get_inheritable(xref, obj, "DA"); value = pdf_dict_get_inheritable(xref, obj, "V"); if (!ap || !value) return NULL; res = pdf_dict_get_inheritable(xref, obj, "DR"); rect = pdf_to_rect(ctx, fz_dict_gets(ctx, obj, "Rect")); rotate = fz_to_int(ctx, fz_dict_gets(ctx, fz_dict_gets(ctx, obj, "MK"), "R")); rect = fz_transform_rect(fz_rotate(rotate), rect); flags = fz_to_int(ctx, fz_dict_gets(ctx, obj, "Ff")); is_multiline = (flags & (1 << 12)) != 0; if ((flags & (1 << 25) /* richtext */)) fz_warn(ctx, "missing support for richtext fields"); align = fz_to_int(ctx, fz_dict_gets(ctx, obj, "Q")); font_size = pdf_extract_font_size(xref, fz_to_str_buf(ctx, ap), &font_name); if (!font_size || !font_name) font_size = is_multiline ? 10 /* FIXME */ : floor(rect.y1 - rect.y0 - 2); content = fz_new_buffer(ctx, 256); base_ap = fz_new_buffer(ctx, 256); pdf_prepend_ap_background(content, xref, obj); fz_buffer_printf(ctx, content, "/Tx BMC 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, "/Tx BMC q BT %s ", fz_to_str_buf(ctx, ap)); if (font_name) { fz_buffer_printf(ctx, content, "/%s %.4f Tf ", font_name, font_size); fz_buffer_printf(ctx, base_ap, "/%s %.4f Tf ", font_name, font_size); fz_free(ctx, font_name); } y = 0.5f * (rect.y1 - rect.y0) + 0.6f * font_size; if (is_multiline) y = rect.y1 - rect.y0 - 2; fz_buffer_printf(ctx, content, "1 0 0 1 2 %.4f Tm ", y); ucs2 = pdf_to_ucs2(ctx, value); for (rest = ucs2; *rest; rest++) if (*rest > 0xFF) *rest = '?'; if ((flags & (1 << 13) /* password */)) for (rest = ucs2; *rest; rest++) *rest = '*'; x = 0; rest = ucs2; if ((flags & (1 << 24) /* comb */)) { pdf_append_combed_line(xref, res, content, base_ap, ucs2, font_size, rect.x1 - rect.x0, fz_to_int(ctx, pdf_dict_get_inheritable(xref, obj, "MaxLen"))); rest = L""; } while (*rest) rest = pdf_append_line(xref, res, content, base_ap, rest, font_size, align, rect.x1 - rect.x0 - 4.0f, is_multiline, &x); fz_free(ctx, ucs2); fz_buffer_printf(ctx, content, "ET Q EMC"); fz_drop_buffer(ctx, base_ap); rect = fz_transform_rect(fz_rotate(-rotate), rect); return pdf_create_annot(ctx, rect, fz_keep_obj(obj), content, res ? fz_keep_obj(res) : NULL, 0); }
fz_annot *fz_create_annot(fz_interactive *idoc, fz_page *page, fz_annot_type type) { return (fz_annot *)pdf_create_annot((pdf_document *)idoc, (pdf_page *)page, type); }