< iOS samples

DigitalSignaturesTest - Swift

Demonstrates the basic usage of high-level digital signature API to digitally sign and/or certify PDF documents.

//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2017 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------------------------------------
// This sample demonstrates the basic usage of high-level digital signature API in PDFNet.
//
// The following steps are typically used to add a digital signature to a PDF:
//
//     1. Extend and implement a new SignatureHandler. The SignatureHandler will be used to add or validate/check a
//        digital signature.
//     2. Create an instance of the implemented SignatureHandler and register it with PDFDoc with
//        pdfdoc.AddSignatureHandler(). The method returns an ID that can be used later to associate a SignatureHandler
//        with a field.
//     3. Find the required 'e_ptsignature' field in the existing document or create a new field.
//     4. Call field.UseSignatureHandler() with the ID of your handler.
//     5. Call pdfdoc.Save()
//
// Additional processing can be done before document is signed. For example, UseSignatureHandler() returns an instance
// of SDF dictionary which represents the signature dictionary (or the /V entry of the form field). This can be used to
// add additional information to the signature dictionary (e.g. Name, Reason, Location, etc.).
//
// Although the steps above describes extending the SignatureHandler class, this sample demonstrates the use of
// StdSignatureHandler (a built-in SignatureHandler in PDFNet) to sign a PDF file.
//----------------------------------------------------------------------------------------------------------------------

import PDFNet
import Foundation

//
// This functions add an approval signature to the PDF document. The original PDF document contains a blank form field
// that is prepared for a user to sign. The following code demonstrate how to sign this document using PDFNet.
//
func SignPDF() -> Bool {
    var result = true
    let infile: String! = Bundle.main.path(forResource: "doc_to_sign", ofType: "pdf")
    let outfile: String = URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("signed_doc.pdf").path
    let certfile: String! = Bundle.main.path(forResource: "pdftron", ofType: "pfx")
    let imagefile: String! = Bundle.main.path(forResource: "signature", ofType: "jpg")
    
    do {
        try PTPDFNet.catchException {
            print("Signing PDF document: '\(infile!)'.")
            
            // Open an existing PDF
            let doc: PTPDFDoc = PTPDFDoc(filepath: infile)
            
            // Add an StdSignatureHandler instance to PDFDoc, making sure to keep track of it using the ID returned.
            let sigHandlerId: SignatureHandlerId = SignatureHandlerId(doc.addStdSignatureHandler(fromFile: certfile, pkcs12_keypass: "password"))
            
            // Obtain the signature form field from the PDFDoc via Annotation.
            let sigField: PTField = doc.getField("Signature1")
            let widgetAnnot: PTWidget = PTWidget(d: sigField.getSDFObj())
            
            // Tell PDFNetC to use the SignatureHandler created to sign the new signature form field.
            let sigDict: PTObj = sigField.useSignatureHandler(sigHandlerId)
            
            // Add more information to the signature dictionary.
            sigDict.putName("SubFilter", name: "adbe.pkcs7.detached")
            sigDict.put("Name", value: "PDFTron")
            sigDict.put("Location", value: "Vancouver, BC")
            sigDict.put("Reason", value: "Document verification.")
            
            // Add the signature appearance
            let apWriter: PTElementWriter = PTElementWriter()
            let apBuilder: PTElementBuilder = PTElementBuilder()
            apWriter.writerBegin(with: doc.getSDFDoc(), compress: true)
            let sigImg: PTImage = PTImage.create(withFile: doc.getSDFDoc(), filename: imagefile, encoder_hints: PTObj())
            let w: Double = Double(sigImg.getWidth())
            let h: Double = Double(sigImg.getHeight())
            
            var apElement: PTElement = apBuilder.createImage(withCornerAndScale: sigImg, x: 0, y: 0, hscale: w, vscale: h)
            apWriter.writePlacedElement(apElement)
            var apObj: PTObj = apWriter.end()
            apObj.putRect("BBox", x1: 0, y1: 0, x2: w, y2: h)
            apObj.putName("Subtype", name: "Form")
            apObj.putName("Type", name: "XObject")
            apWriter.writerBegin(with: doc.getSDFDoc(), compress: true)
            apElement = apBuilder.createForm(with: apObj)
            apWriter.writePlacedElement(apElement)
            apObj = apWriter.end()
            apObj.putRect("BBox", x1: 0, y1: 0, x2: w, y2: h)
            apObj.putName("Subtype", name: "Form")
            apObj.putName("Type", name: "XObject")
            widgetAnnot.setAppearance(apObj, annot_state: e_ptnormal, app_state: nil)
            widgetAnnot.refreshAppearance()
            
            let widgetObj: PTObj = widgetAnnot.getSDFObj()
            widgetObj.putNumber("F", value: 132)
            widgetObj.putName("Type", name: "Annot")
            
            // Save the PDFDoc. Once the method below is called, PDFNetC will also sign the document using the information
            // provided.
            doc.save(toFile: outfile, flags: 0)
            
            print("Finished signing PDF document.")
        }
    } catch let e as NSError {
        print("Exception: \(e)\n")
        result = false
    }
    return result
}

//
// Adds a certification signature to the PDF document. Certifying a document is like notarizing a document. Unlike
// approval signatures, there can be only one certification per PDF document. Only the first signature in the PDF
// document can be used as the certification signature. The process of certifying a document is almost exactly the same
// as adding approval signatures with the exception of certification signatures requires an entry in the "Perms"
// dictionary.
//
func CertifyPDF() -> Bool {
    var result = true
    let infile: String! = Bundle.main.path(forResource: "newsletter", ofType: "pdf")
    let outfile: String = URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("newsletter_certified.pdf").path
    let certfile: String! = Bundle.main.path(forResource: "pdftron", ofType: "pfx")
    
    do {
        try PTPDFNet.catchException {
            print("Certifying PDF document: '\(infile!)',")
            
            // Open an existing PDF
            let doc: PTPDFDoc = PTPDFDoc(filepath: infile)
            
            // Add an StdSignatureHandler instance to PDFDoc, making sure to keep track of it using the ID returned.
            let sigHandlerId: SignatureHandlerId = SignatureHandlerId(doc.addStdSignatureHandler(fromFile: certfile, pkcs12_keypass: "password"))
            
            // Create new signature form field in the PDFDoc.
            let sigField: PTField = doc.fieldCreate(with: "Signature1", type: e_ptsignature, field_value: "", def_field_value: "")
            
            // Assign the form field as an annotation widget to the PDFDoc so that a signature appearance can be added.
            let page1: PTPage = doc.getPage(1)
            let widgetAnnot: PTWidget = PTWidget.create(doc.getSDFDoc(), pos: PTPDFRect(x1: 20, y1: 600, x2: 220, y2: 640), field: sigField)
            page1.annotPushBack(widgetAnnot)
            widgetAnnot.setPage(page1)
            let widgetObj: PTObj = widgetAnnot.getSDFObj()
            widgetObj.putNumber("F", value: 132)
            widgetObj.putName("Type", name: "Annot")
            
            // Tell PDFNetC to use the SignatureHandler created to sign the new signature form field.
            let sigDict: PTObj = sigField.useSignatureHandler(sigHandlerId)
            
            // Add more information to the signature dictionary.
            sigDict.putName("SubFilter", name: "adbe.pkcs7.detached")
            sigDict.put("Name", value: "PDFTron")
            sigDict.put("Location", value: "Vancouver, BC")
            sigDict.put("Reason", value: "Document verification.")
            
            // Appearance can be added to the widget annotation. Please see the "SignPDF()" function for details.
            
            // Add this sigDict as DocMDP in Perms dictionary from root
            let root: PTObj = doc.getRoot()
            let perms: PTObj = root.putDict("Perms")
            // add the sigDict as DocMDP (indirect) in Perms
            perms.put("DocMDP", obj: sigDict)
            
            // add the additional DocMDP transform params
            let refObj: PTObj = sigDict.putArray("Reference")
            let transform: PTObj = refObj.pushBackDict()
            transform.putName("TransformMethod", name: "DocMDP")
            transform.putName("Type", name: "SigRef")
            let transformParams: PTObj = transform.putDict("TransformParams")
            transformParams.putNumber("P", value: 1)   // Set permissions as necessary.
            transformParams.putName("Type", name: "TransformParams")
            transformParams.putName("V", name: "1.2")
            
            // Save the PDFDoc. Once the method below is called, PDFNetC will also sign the document using the information
            // provided.
            doc.save(toFile: outfile, flags: 0)
            
            print("Finished certifying PDF document.")
        }
    } catch let e as NSError {
        print("Exception: \(e)")
        result = false
    }
    return result
}

func runDigitalSignaturesTest() -> Int {
    return autoreleasepool {
        // Initialize PDFNetC
        
        
        var result = true
        if !SignPDF() {
            result = false
        }
        if !CertifyPDF() {
            result = false
        }
        
        if !result {
            print("Tests failed.")
            return 1
        }
        
        print("All tests passed.")
        
        return 0
    }
}