diff --git a/npm/podofo.d.ts b/npm/podofo.d.ts index a658f5f..f92a5ac 100644 --- a/npm/podofo.d.ts +++ b/npm/podofo.d.ts @@ -22,6 +22,7 @@ declare module 'podofo.js' { export interface Page extends Canvas { getRect: () => Array; extractText: () => Array<{text: string}>; + sign: (image: Image, rect: Array, certificate: Uint8Array, privateKey: Uint8Array) => Uint8ClampedArray; } export interface PageCollection { diff --git a/src/bind.cpp b/src/bind.cpp index c81a8ac..24ce04e 100644 --- a/src/bind.cpp +++ b/src/bind.cpp @@ -256,6 +256,42 @@ em::val getPageSize(const PoDoFo::PdfPageSize& page_size, PoDoFo::PdfPage::CreateStandardPageSize(page_size, landscape)}; return rectToArray(size); } + +em::val sign(PoDoFo::PdfPage& page, const PoDoFo::PdfImage& image, em::val jrect, em::val certificate, em::val key) +{ + const auto& rect{vecFromJSArray(jrect)}; + + const auto certificate_buffer{vecFromJSArray(certificate)}; + const auto key_buffer{vecFromJSArray(key)}; + + auto& signature = page.CreateField("Signature", PoDoFo::Rect(rect[0], rect[1], rect[2], rect[3])); + signature.SetSignatureDate(PoDoFo::PdfDate::LocalNow()); + + auto form{page.GetDocument().CreateXObjectForm(PoDoFo::Rect(0, 0, image.GetWidth(), image.GetHeight()))}; + + PoDoFo::PdfPainter painter; + painter.SetCanvas(*form); + painter.DrawImage(image, 0, 0, 1, 1); + painter.FinishDrawing(); + + std::vector buffer; + PoDoFo::VectorStreamDevice output{buffer}; + + PoDoFo::PdfSignerCms signer( + {reinterpret_cast(certificate_buffer.data()), certificate_buffer.size()}, + {reinterpret_cast(key_buffer.data()), key_buffer.size()} + ); + + signature.SetAppearanceStream(*form); + + PoDoFo::SignDocument(static_cast(page.GetDocument()), output, signer, signature, PoDoFo::PdfSaveOptions::SaveOnSigning); + + const auto Uint8ClampedArray{em::val::global("Uint8ClampedArray")}; + + return Uint8ClampedArray.new_(em::typed_memory_view( + buffer.size(), reinterpret_cast(buffer.data()))); +} + } // namespace Page namespace Resources @@ -309,6 +345,7 @@ EMSCRIPTEN_BINDINGS(PODOFO) .function("getRect", &Page::getRect) .function("extractText", &Page::extractText) .function("getResources", &Page::getResources, em::allow_raw_pointers()) + .function("sign", &Page::sign) ; em::class_("Canvas") diff --git a/tests/test_data/certificate.der b/tests/test_data/certificate.der new file mode 100644 index 0000000..9ac1818 Binary files /dev/null and b/tests/test_data/certificate.der differ diff --git a/tests/test_data/private_key.der b/tests/test_data/private_key.der new file mode 100644 index 0000000..0575d51 Binary files /dev/null and b/tests/test_data/private_key.der differ diff --git a/tests/unit_tests/sign.test.js b/tests/unit_tests/sign.test.js new file mode 100644 index 0000000..6469e8f --- /dev/null +++ b/tests/unit_tests/sign.test.js @@ -0,0 +1,34 @@ +const { readFile, writeFile } = require("./utils"); + +describe('podofo.js', () => { + it('sign pdf document', async () => { + const Podofo = global.Podofo; + + const document = new Podofo.Document(); + const pages = document.getPages(); + + const size = Podofo.getPageSize(Podofo.PageSize.A4, false); + const page = pages.createPage(size); + + const fonts = document.getFonts(); + const font = fonts.getDefaultFont(); + + const painter = new Podofo.Painter(); + painter.setCanvas(page); + painter.setFont(font, 10); + + const text = 'Signed document'; + painter.drawText(text, 56.69, page.getRect()[3] - 56.69); + painter.finishDrawing(); + + const buffer = readFile('image.png'); + + const image = new Podofo.Image(document); + image.loadFromBuffer(buffer); + + const certificate = readFile('certificate.der'); + const key = readFile('private_key.der'); + + page.sign(image, [20, 20, 100, 100], certificate, key); + }); +});