B4J Tutorial [BANano] How to sign PDF Documents?

Hi Fam

I wanted to sign PDF documents in my product. So.. I used the PDF-LIB for this.

1. I designed a screen to enter the signature and initials.

Wizard.jpeg


2. The canvas we use stores the entered signature and initials as DataURL and I save it in the database. In actual sense this is just a collection of images that we will store in the database.

3. We read the signature signed on the canvas as a DataURL and then pass it to the class below.

4. Download the signed document.

5. Below is an example of a signature made on an existing contract pdf document.

Signature.jpeg
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
This class uses pdf-lib to read the contents of the PDF and then inserts an image at XY with width and height.

B4X:
#IgnoreWarnings: 12
Sub Class_Globals
    Private mCallBack As Object
    Private mEvent As String
    Private mFileName As String
    Private pdfObj As BANanoObject
    Private arrayBuffer As Object
    Private BANAno As BANano
    Private PDFLib As BANanoObject
    Private pdfDoc As BANanoObject
    Private pages As List
End Sub

Public Sub Initialize(Module As Object, event As String, fileName As String)
    mCallBack = Module
    mEvent = event
    mFileName = fileName
    PDFLib.Initialize("PDFLib")
End Sub

Sub OpenTemplate(tmpFile As String)
    arrayBuffer = BANAno.Await(BANAno.GetFileAsArrayBuffer(tmpFile, Null))
    pdfDoc = BANAno.Await(PDFLib.GetField("PDFDocument").RunMethod("load", arrayBuffer))
    'const pdfDoc = await PDFLib.PDFDocument.load(arrayBuffer);
    pages = pdfDoc.RunMethod("getPages", Null)
End Sub

Sub AddSignaturePng(pageNumber As Int, signURL As String, x As Int, y As Int, width As Int, height As Int)
    Dim tPage As Int = BANAno.parseInt(pageNumber) - 1
    Dim sigBuffer As Object = BANAno.Await(BANAno.GetFileAsArrayBuffer(signURL, Null))
    Dim pngIMage As Object = BANAno.Await(pdfDoc.RunMethod("embedPng", sigBuffer))
    
    Dim opt As Map = CreateMap()
    opt.Put("x", x)
    opt.Put("y", y)
    opt.Put("width", width)
    opt.Put("height", height)
    '
    Dim page As BANanoObject = pages.Get(tPage)
    page.RunMethod("drawImage", Array(pngIMage, opt))
End Sub

Sub AddSignatureJpeg(pageNumber As Int, signURL As String, x As Int, y As Int, width As Int, height As Int)
    Dim tPage As Int = BANAno.parseInt(pageNumber) - 1
    Dim sigBuffer As Object = BANAno.Await(BANAno.GetFileAsArrayBuffer(signURL, Null))
    Dim pngIMage As Object = BANAno.Await(pdfDoc.RunMethod("embedJpg", sigBuffer))
    
    Dim opt As Map = CreateMap()
    opt.Put("x", x)
    opt.Put("y", y)
    opt.Put("width", width)
    opt.Put("height", height)
    '
    Dim page As BANanoObject = pages.Get(tPage)
    page.RunMethod("drawImage", Array(pngIMage, opt))
End Sub

Sub SaveToFileObject As BANanoObject
    Dim pdfBytes As Object = BANAno.Await(pdfDoc.RunMethod("save", Null))
    Dim fc As List
    fc.Initialize
    fc.Add(pdfBytes)
    Dim blob As BANanoObject
    blob.Initialize2("Blob",Array(fc, CreateMap("type": "application/pdf")))
    ' make a new File object
    Dim f As BANanoObject
    f.Initialize2("File",Array(Array(blob), mFileName, CreateMap("type": blob.getfield("type"))))
    Return f
End Sub

Sub Download
    Dim pdfBytes As Object = BANAno.Await(pdfDoc.RunMethod("save", Null))
    Dim fc As List
    fc.Initialize
    fc.Add(pdfBytes)
    Dim blob As BANanoObject
    blob.Initialize2("Blob",Array(fc, CreateMap("type": "application/pdf")))
    BANAno.RunJavascriptMethod("saveAs",Array(blob,mFileName))
End Sub
 

Mashiane

Expert
Licensed User
Longtime User
Usage - this is a proof of concept to read an existing "contract" from the assets folder and insert the signatures at

B4X:
Dim pdfWriter As SDUIPDFLib
    pdfWriter.Initialize(Me, "pdf", "73....pdf")
    BANano.Await(pdfWriter.OpenTemplate("./assets/contract.pdf"))
    '
    Dim signatureURL As String = $"data:image/jpeg;base64,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..."$
    '
    BANano.Await(pdfWriter.AddSignatureJpeg(1, signatureURL, 100, 100, 150, 150))
    BANano.Await(pdfWriter.AddSignatureJpeg(2, signatureURL, 100, 100, 150, 150))
    BANano.Await(pdfWriter.Download)
 
Top