From 3da3d103216bf8966236621389e75943fdf08d24 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 4 Jul 2018 12:14:21 +0200 Subject: Add digital signature appearance synthesis. The pdf_update_signature_appearance function must be called directly by the signing code when it signs the document; as only the signing code has all the text that needs to be written into the appearance. --- source/pdf/pdf-appearance.c | 86 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 2 deletions(-) (limited to 'source/pdf') diff --git a/source/pdf/pdf-appearance.c b/source/pdf/pdf-appearance.c index 0e2e2847..1bf0fd33 100644 --- a/source/pdf/pdf-appearance.c +++ b/source/pdf/pdf-appearance.c @@ -1202,9 +1202,91 @@ pdf_write_appearance(fz_context *ctx, pdf_annot *annot, fz_buffer *buf, } } -void pdf_update_signature_appearance(fz_context *ctx, pdf_annot *annot, const char *name, const char *text, const char *date) +void pdf_update_signature_appearance(fz_context *ctx, pdf_annot *annot, const char *name, const char *dn, const char *date) { - fz_throw(ctx, FZ_ERROR_GENERIC, "writing digital signature appearance streams is not yet implemented"); + pdf_obj *ap, *new_ap_n, *res_font; + char tmp[500]; + fz_font *helv = NULL; + fz_font *zadb = NULL; + pdf_obj *res = NULL; + fz_buffer *buf; + fz_rect rect; + float w, h, size, name_w; + + rect = pdf_to_rect(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME(Rect))); + + fz_var(helv); + fz_var(zadb); + fz_var(res); + + buf = fz_new_buffer(ctx, 1024); + fz_try(ctx) + { + helv = fz_new_base14_font(ctx, "Helvetica"); + zadb = fz_new_base14_font(ctx, "ZapfDingbats"); + + res = pdf_new_dict(ctx, annot->page->doc, 1); + res_font = pdf_dict_put_dict(ctx, res, PDF_NAME(Font), 1); + pdf_dict_put_drop(ctx, res_font, PDF_NAME(Helv), pdf_add_simple_font(ctx, annot->page->doc, helv, 0)); + pdf_dict_put_drop(ctx, res_font, PDF_NAME(ZaDb), pdf_add_simple_font(ctx, annot->page->doc, zadb, 0)); + + w = (rect.x1 - rect.x0) / 2; + h = (rect.y1 - rect.y0); + + /* Use flower symbol from ZapfDingbats as sigil */ + fz_append_printf(ctx, buf, "q 1 0.8 0.8 rg BT /ZaDb %g Tf %g %g Td (`) Tj ET Q\n", + h*1.1f, + rect.x0 + w - (h*0.4f), + rect.y0 + h*0.1f); + + /* Name */ + name_w = measure_simple_string(ctx, helv, name); + size = fz_min(fz_min((w - 4) / name_w, h), 24); + fz_append_string(ctx, buf, "BT\n"); + fz_append_printf(ctx, buf, "/Helv %g Tf\n", size); + fz_append_printf(ctx, buf, "%g %g Td\n", rect.x0+2, rect.y1 - size*0.8f - (h-size)/2); + write_simple_string(ctx, buf, name, name + strlen(name)); + fz_append_string(ctx, buf, " Tj\n"); + fz_append_string(ctx, buf, "ET\n"); + + /* Information text */ + size = fz_min(fz_min((w / 12), h / 6), 16); + fz_append_string(ctx, buf, "BT\n"); + fz_append_printf(ctx, buf, "/Helv %g Tf\n", size); + fz_append_printf(ctx, buf, "%g TL\n", size); + fz_append_printf(ctx, buf, "%g %g Td\n", rect.x0+w+2, rect.y1); + fz_snprintf(tmp, sizeof tmp, "Digitally signed by %s", name); + write_simple_string_with_quadding(ctx, buf, helv, size, tmp, w-4, 0); + fz_snprintf(tmp, sizeof tmp, "DN: %s", dn); + write_simple_string_with_quadding(ctx, buf, helv, size, tmp, w-4, 0); + if (date) + { + fz_snprintf(tmp, sizeof tmp, "Date: %s", date); + write_simple_string_with_quadding(ctx, buf, helv, size, tmp, w-4, 0); + } + fz_append_string(ctx, buf, "ET\n"); + + /* Update the AP/N stream */ + ap = pdf_dict_get(ctx, annot->obj, PDF_NAME(AP)); + if (!ap) + ap = pdf_dict_put_dict(ctx, annot->obj, PDF_NAME(AP), 1); + new_ap_n = pdf_new_xobject(ctx, annot->page->doc, rect, fz_identity, res, buf); + pdf_dict_put(ctx, ap, PDF_NAME(N), new_ap_n); + + pdf_drop_obj(ctx, annot->ap); + annot->ap = new_ap_n; + annot->has_new_ap = 1; + } + fz_always(ctx) + { + fz_drop_font(ctx, helv); + fz_drop_font(ctx, zadb); + pdf_drop_obj(ctx, res); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } } void pdf_update_appearance(fz_context *ctx, pdf_annot *annot) -- cgit v1.2.3