diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2018-07-04 12:14:21 +0200 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2018-07-05 15:32:35 +0200 |
commit | 3da3d103216bf8966236621389e75943fdf08d24 (patch) | |
tree | d7b92dfd1e7cc1907d8792f40f082a4b3376f990 | |
parent | 96cc776650a1845f4b3894c2311bee4d51d60f20 (diff) | |
download | mupdf-3da3d103216bf8966236621389e75943fdf08d24.tar.xz |
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.
-rw-r--r-- | include/mupdf/pdf/name-table.h | 2 | ||||
-rw-r--r-- | source/pdf/pdf-appearance.c | 86 |
2 files changed, 86 insertions, 2 deletions
diff --git a/include/mupdf/pdf/name-table.h b/include/mupdf/pdf/name-table.h index bff67b0d..385f7331 100644 --- a/include/mupdf/pdf/name-table.h +++ b/include/mupdf/pdf/name-table.h @@ -371,6 +371,7 @@ PDF_MAKE_NAME("SubFilter", SubFilter) PDF_MAKE_NAME("Subtype", Subtype) PDF_MAKE_NAME("Subtype2", Subtype2) PDF_MAKE_NAME("Supplement", Supplement) +PDF_MAKE_NAME("Symb", Symb) PDF_MAKE_NAME("T", T) PDF_MAKE_NAME("TR", TR) PDF_MAKE_NAME("TR2", TR2) @@ -430,6 +431,7 @@ PDF_MAKE_NAME("XRefStm", XRefStm) PDF_MAKE_NAME("XStep", XStep) PDF_MAKE_NAME("XYZ", XYZ) PDF_MAKE_NAME("YStep", YStep) +PDF_MAKE_NAME("ZaDb", ZaDb) PDF_MAKE_NAME("adbe.pkcs7.detached", adbe_pkcs7_detached) PDF_MAKE_NAME("ca", ca) PDF_MAKE_NAME("n0", n0) 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) |