/
SignAllPagesExample.swift
153 lines (131 loc) · 7.03 KB
/
SignAllPagesExample.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//
// Copyright © 2021-2024 PSPDFKit GmbH. All rights reserved.
//
// The PSPDFKit Sample applications are licensed with a modified BSD license.
// Please see License for details. This notice may not be removed from this file.
//
import PSPDFKit
import PSPDFKitUI
class SignAllPagesExample: Example {
var status: StatusHUDItem?
override init() {
super.init()
title = "Sign All Pages"
contentDescription = "Will add a signature to all pages of a document, optionally flattened."
category = .annotations
priority = 200
}
override func invoke(with delegate: ExampleRunnerDelegate?) -> UIViewController? {
guard let baseViewController = delegate?.currentViewController else {
return nil
}
// Ask for the annotation username, if needed.
if !UsernameHelper.isDefaultAnnotationUserNameSet {
// We don't use the static helper here because we do not yet have a PDFViewController at this point.
let helper = UsernameHelper()
helper.ask(forDefaultAnnotationUsername: baseViewController, suggestedName: nil) { _ in
self.showSignatureUI(on: baseViewController)
}
} else {
showSignatureUI(on: baseViewController)
}
return nil
}
func showSignatureUI(on baseViewController: UIViewController) {
// Show the signature controller
let signatureController = SignatureCreationViewController()
signatureController.delegate = self
baseViewController.present(signatureController, animated: true)
}
}
extension SignAllPagesExample: SignatureCreationViewControllerDelegate {
func signatureCreationViewControllerDidFinish(_ signatureController: SignatureCreationViewController) {
guard let navigationController = signatureController.presentingViewController as? UINavigationController else {
return
}
// Create the document.
let document = AssetLoader.writableDocument(for: .annualReport, overrideIfExists: true)
// We want to add the signature at the bottom of the page.
for pageIndex in 0..<document.pageCount {
// Check if we have already signed and ignore if so.
let alreadySigned = document.annotationsForPage(at: pageIndex, type: [.ink, .stamp]).contains { annotation in
if let ink = annotation as? InkAnnotation {
return ink.isSignature
} else if let stamp = annotation as? StampAnnotation {
return stamp.isSignature
} else {
return false
}
}
// Not yet signed -> create new annotation.
if !alreadySigned {
self.addAnnotation(from: signatureController, onDocument: document, pageIndex: pageIndex)
}
}
// The signature creation view needs to be at the correct size when extracting the
// signature annotations, so don’t dismiss it until after creating the annotations.
signatureController.dismiss(animated: true) {
// Now we could flatten the PDF so that the signature is "burned in".
let flattenAlert = UIAlertController(title: "Flatten Annotations", message: "Flattening will merge the annotations with the page content", preferredStyle: .alert)
flattenAlert.addAction(UIAlertAction(title: "Flatten", style: .destructive, handler: { _ in
let tempURL = FileHelper.temporaryPDFFileURL(prefix: "flattened_signature")
self.status = StatusHUDItem.progress(withText: localizedString("Preparing") + "…")
self.status?.push(animated: true, on: navigationController.view.window)
// Flatten in the background so progress can be shown.
DispatchQueue.global(qos: .default).async {
let configuration = Processor.Configuration(document: document)!
configuration.modifyAnnotations(ofTypes: .all, change: .flatten)
let processor = Processor(configuration: configuration, securityOptions: nil)
processor.delegate = self
try? processor.write(toFileURL: tempURL)
DispatchQueue.main.async {
self.status?.pop(animated: true)
self.status = nil
let flattenedDocument = Document(url: tempURL)
let pdfController = PDFViewController(document: flattenedDocument)
navigationController.pushViewController(pdfController, animated: true)
}
}
}))
flattenAlert.addAction(UIAlertAction(title: "Allow Editing", style: .default, handler: { _ in
let pdfController = PDFViewController(document: document)
navigationController.pushViewController(pdfController, animated: true)
}))
navigationController.present(flattenAlert, animated: true)
}
}
func signatureCreationViewControllerDidCancel(_ signatureController: SignatureCreationViewController) {
signatureController.dismiss(animated: true)
}
func addAnnotation(from signatureController: SignatureCreationViewController, onDocument document: Document, pageIndex: PageIndex) {
guard let pageInfo = document.pageInfoForPage(at: pageIndex),
let annotation = signatureController.signatureAnnotation(forPageWith: pageInfo.size) else {
return
}
let margin: CGFloat = 10.0
let maxSize = CGSize(width: 150.0, height: 75.0)
// Calculate the size, aspect ratio correct.
let annotationSize = annotation.boundingBox.size
let scale: CGFloat = {
let xScale = maxSize.width / annotationSize.width
let yScale = maxSize.height / annotationSize.height
let minScale = min(xScale, yScale)
return minScale > 1.0 ? 1.0 : minScale
}()
let scaledAnnotationSize = CGSize(width: round(annotationSize.width * scale), height: round(annotationSize.height * scale))
// Create the annotation.
// Add annotation to bottom right adding additional padding to avoid signature overlapping
// the page number in the PDF. (PDF zero is bottom left)
let pageLabelPadding: CGFloat = 40
annotation.boundingBox = CGRect(x: pageInfo.size.width - scaledAnnotationSize.width - margin, y: margin + pageLabelPadding, width: scaledAnnotationSize.width, height: scaledAnnotationSize.height)
annotation.contents = "Signed on \(DateFormatter.localizedString(from: Date(), dateStyle: .medium, timeStyle: .medium)) by test user."
annotation.pageIndex = pageIndex
// Add annotation.
document.add(annotations: [annotation])
}
}
extension SignAllPagesExample: ProcessorDelegate {
func processor(_ processor: Processor, didProcessPage currentPage: UInt, totalPages: UInt) {
status?.progress = CGFloat(currentPage + 1) / CGFloat(totalPages)
}
}