summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2018-07-04 12:14:21 +0200
committerTor Andersson <tor.andersson@artifex.com>2018-07-05 15:32:35 +0200
commit3da3d103216bf8966236621389e75943fdf08d24 (patch)
treed7b92dfd1e7cc1907d8792f40f082a4b3376f990
parent96cc776650a1845f4b3894c2311bee4d51d60f20 (diff)
downloadmupdf-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.h2
-rw-r--r--source/pdf/pdf-appearance.c86
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)