CPDFDocumentPlugin.swift 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. //
  2. // CPDFDocumentPlugin.swift
  3. // compdfkit_flutter
  4. // Copyright © 2014-2023 PDF Technologies, Inc. All Rights Reserved.
  5. //
  6. // THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
  7. // AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
  8. // UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
  9. // This notice may not be removed from this file.
  10. import Foundation
  11. import ComPDFKit
  12. import Flutter
  13. import ComPDFKit_Tools
  14. public class CPDFDocumentPlugin {
  15. private var document : CPDFDocument?
  16. public var _methodChannel : FlutterMethodChannel
  17. private var pdfViewController : CPDFViewController?
  18. init(uid : String, binaryMessager : FlutterBinaryMessenger) {
  19. _methodChannel = FlutterMethodChannel(name: "com.compdfkit.flutter.document_\(uid)", binaryMessenger: binaryMessager)
  20. registeryMethodChannel()
  21. }
  22. init(pdfViewController : CPDFViewController, uid : String, binaryMessager : FlutterBinaryMessenger){
  23. self.pdfViewController = pdfViewController
  24. _methodChannel = FlutterMethodChannel(name: "com.compdfkit.flutter.document_\(uid)", binaryMessenger: binaryMessager)
  25. registeryMethodChannel()
  26. }
  27. private func registeryMethodChannel(){
  28. _methodChannel.setMethodCallHandler({
  29. (call: FlutterMethodCall, result: FlutterResult) -> Void in
  30. print("ComPDFKit-Flutter: iOS-MethodChannel: CPDFDocumentPlugin [method:\(call.method)]")
  31. if(self.document == nil && self.pdfViewController != nil){
  32. guard let pdfListView = self.pdfViewController?.pdfListView else {
  33. print("pdfViewController error")
  34. return
  35. }
  36. self.document = pdfListView.document
  37. }
  38. switch call.method {
  39. case CPDFConstants.save:
  40. // save pdf
  41. guard let pdfListView = self.pdfViewController!.pdfListView else {
  42. result(true)
  43. return
  44. }
  45. var isSuccess = false
  46. if (pdfListView.isEditing() == true && pdfListView.isEdited() == true) {
  47. pdfListView.commitEditing()
  48. if pdfListView.document.isModified() == true {
  49. isSuccess = pdfListView.document.write(to: pdfListView.document.documentURL)
  50. }
  51. } else {
  52. if(pdfListView.document != nil) {
  53. if pdfListView.document.isModified() == true {
  54. isSuccess = pdfListView.document.write(to: pdfListView.document.documentURL)
  55. }
  56. }
  57. }
  58. if isSuccess {
  59. self._methodChannel.invokeMethod("saveDocument", arguments: nil)
  60. }
  61. result(isSuccess) // or return false
  62. case CPDFConstants.openDocument:
  63. let initInfo = call.arguments as? [String: Any]
  64. let path = initInfo?["filePath"] as? String ?? ""
  65. let password = initInfo?["password"] ?? ""
  66. self.document = CPDFDocument(url: URL(fileURLWithPath: path))
  67. if(self.document?.isLocked == true){
  68. self.document?.unlock(withPassword: password as? String ?? "")
  69. }
  70. self.pdfViewController?.pdfListView?.document = self.document
  71. self.pdfViewController?.pdfListView?.setNeedsDisplay()
  72. result(true)
  73. case CPDFConstants.getFileName:
  74. if(self.document == nil){
  75. print("self.document is nil")
  76. result("is nil")
  77. return
  78. }
  79. let fileName = self.document?.documentURL.lastPathComponent
  80. result(fileName)
  81. case CPDFConstants.isEncrypted:
  82. let isEncrypted = self.document?.isEncrypted ?? false
  83. result(isEncrypted)
  84. case CPDFConstants.isImageDoc:
  85. let isImageDoc = self.document?.isImageDocument() ?? false
  86. result(isImageDoc)
  87. case CPDFConstants.getPermissions:
  88. let permissions = self.document?.permissionsStatus ?? .none
  89. switch permissions {
  90. case .none:
  91. result(0)
  92. case .user:
  93. result(1)
  94. case .owner:
  95. result(2)
  96. default:
  97. result(0)
  98. }
  99. case CPDFConstants.checkOwnerUnlocked:
  100. let owner = self.document?.isCheckOwnerUnlocked() ?? false
  101. result(owner)
  102. case CPDFConstants.checkOwnerPassword:
  103. let info = call.arguments as? [String: Any]
  104. let password = info?["password"] as? String ?? ""
  105. let isOwnerPassword = self.document?.checkOwnerPassword(password) ?? false
  106. result(isOwnerPassword)
  107. case CPDFConstants.hasChange:
  108. let isModified = self.document?.isModified() ?? false
  109. result(isModified)
  110. case CPDFConstants.importAnnotations:
  111. let importPath = call.arguments as? String ?? ""
  112. let success = self.document?.importAnnotation(fromXFDFPath: importPath) ?? false
  113. if success {
  114. self.pdfViewController?.pdfListView?.setNeedsDisplayForVisiblePages()
  115. }
  116. result(success)
  117. case CPDFConstants.exportAnnotations:
  118. let fileNameWithExtension = self.document?.documentURL.lastPathComponent ?? ""
  119. let fileName = (fileNameWithExtension as NSString).deletingPathExtension
  120. let documentFolder = NSHomeDirectory().appending("/Documents/\(fileName)_xfdf.xfdf")
  121. let succes = self.document?.exportAnnotation(toXFDFPath: documentFolder) ?? false
  122. if succes {
  123. result(documentFolder)
  124. } else {
  125. result("")
  126. }
  127. case CPDFConstants.removeAllAnnotations:
  128. let pageCount = self.document?.pageCount ?? 0
  129. for i in 0..<pageCount {
  130. let page = self.document?.page(at: i)
  131. page?.removeAllAnnotations()
  132. }
  133. self.pdfViewController?.pdfListView?.setNeedsDisplayForVisiblePages()
  134. self.pdfViewController?.pdfListView?.updateActiveAnnotations([])
  135. result(true)
  136. case CPDFConstants.getPageCount:
  137. let count = self.document?.pageCount ?? 1
  138. result(count)
  139. case CPDFConstants.saveAs:
  140. let info = call.arguments as? [String: Any]
  141. let savePath = self.getValue(from: info, key: "save_path", defaultValue: "") ?? ""
  142. let removeSecurity = self.getValue(from: info, key: "remove_security", defaultValue: false)
  143. let fontSubSet = self.getValue(from: info, key: "font_sub_set", defaultValue: true)
  144. var success = false
  145. if removeSecurity {
  146. success = self.document?.writeDecrypt(to: URL(fileURLWithPath: savePath), isSaveFontSubset: fontSubSet) ?? false
  147. } else {
  148. success = self.document?.write(to: URL(fileURLWithPath: savePath), isSaveFontSubset: fontSubSet) ?? false
  149. }
  150. result(success)
  151. case CPDFConstants.print:
  152. self.pdfViewController?.enterPrintState()
  153. case CPDFConstants.removePassword:
  154. let url = self.document?.documentURL
  155. let success = self.document?.writeDecrypt(to: url, isSaveFontSubset: true) ?? false
  156. result(success)
  157. case CPDFConstants.setPassword:
  158. let info = call.arguments as? [String: Any]
  159. let userPassword : String = self.getValue(from: info, key: "user_password", defaultValue: "")
  160. let ownerPassword : String = self.getValue(from: info, key: "owner_password", defaultValue: "")
  161. let allowsPrinting : Bool = self.getValue(from: info, key: "allows_printing", defaultValue: true)
  162. let allowsCopying : Bool = self.getValue(from: info, key: "allows_copying", defaultValue: true)
  163. let encryptAlgo : String = self.getValue(from: info, key: "encrypt_algo", defaultValue: "rc4")
  164. var level: Int = 0
  165. // Encryption mode, the type passed in is:rc4, aes128, aes256, noEncryptAlgo
  166. switch encryptAlgo {
  167. case "rc4":
  168. level = 0
  169. case "aes128":
  170. level = 1
  171. case "aes256":
  172. level = 2
  173. case "noEncryptAlgo":
  174. level = 3
  175. default:
  176. level = 3
  177. }
  178. var options:[CPDFDocumentWriteOption: Any] = [:]
  179. options[CPDFDocumentWriteOption.userPasswordOption] = userPassword
  180. options[CPDFDocumentWriteOption.ownerPasswordOption] = ownerPassword
  181. options[CPDFDocumentWriteOption.allowsPrintingOption] = allowsPrinting
  182. options[CPDFDocumentWriteOption.allowsCopyingOption] = allowsCopying
  183. options[CPDFDocumentWriteOption.encryptionLevelOption] = NSNumber(value: level)
  184. let url = self.document?.documentURL
  185. let success = self.document?.write(to: url, withOptions: options, isSaveFontSubset: true)
  186. result(success)
  187. case CPDFConstants.getEncryptAlgorithm:
  188. let level: CPDFDocumentEncryptionLevel = self.document?.encryptionLevel ?? .noEncryptAlgo
  189. switch level {
  190. case .RC4:
  191. result("rc4")
  192. case .AES128:
  193. result("aes128")
  194. case .AES256:
  195. result("aes256")
  196. case .noEncryptAlgo:
  197. result("noEncryptAlgo")
  198. @unknown default:
  199. result("noEncryptAlgo")
  200. }
  201. case CPDFConstants.createWatermark:
  202. self.createWatermark(call: call, result: result)
  203. case CPDFConstants.removeAllWatermark:
  204. let watrmarks = self.document?.watermarks() ?? []
  205. for watermark in watrmarks {
  206. self.document?.removeWatermark(watermark)
  207. }
  208. let url = self.document?.documentURL
  209. self.document?.write(to: url, isSaveFontSubset: true)
  210. self.pdfViewController?.pdfListView?.layoutDocumentView()
  211. default:
  212. result(FlutterMethodNotImplemented)
  213. }
  214. });
  215. }
  216. private func createWatermark(call: FlutterMethodCall, result: FlutterResult) {
  217. let info = call.arguments as? [String: Any]
  218. // text, image
  219. let type : String = self.getValue(from: info, key: "type", defaultValue: "")
  220. // "0,1,2,3,4"
  221. let pages : String = self.getValue(from: info, key: "pages", defaultValue: "")
  222. let textContent : String = self.getValue(from: info, key: "text_content", defaultValue: "")
  223. let imagePath : String = self.getValue(from: info, key: "image_path", defaultValue: "")
  224. let textColor : String = self.getValue(from: info, key: "text_color", defaultValue: "#000000")
  225. let fontSize : Int = self.getValue(from: info, key: "font_size", defaultValue: 24)
  226. let scale : Double = self.getValue(from: info, key: "scale", defaultValue: 1.0)
  227. let rotation : Double = self.getValue(from: info, key: "rotation", defaultValue: 45)
  228. let opacity : Double = self.getValue(from: info, key: "opacity", defaultValue: 1.0)
  229. // top, center, bottom
  230. let verticalAlignment : String = self.getValue(from: info, key: "vertical_alignment", defaultValue: "center")
  231. // left, center, right
  232. let horizontalAlignment : String = self.getValue(from: info, key: "horizontal_alignment", defaultValue: "center")
  233. let verticalOffset : Double = self.getValue(from: info, key: "vertical_offset", defaultValue: 0)
  234. let horizontalOffset : Double = self.getValue(from: info, key: "horizontal_offset", defaultValue: 0)
  235. let isFront : Bool = self.getValue(from: info, key: "is_front", defaultValue: true)
  236. let isTilePage : Bool = self.getValue(from: info, key: "is_tile_page", defaultValue: false)
  237. let horizontalSpacing : Double = self.getValue(from: info, key: "horizontal_spacing", defaultValue: 0)
  238. let verticalSpacing : Double = self.getValue(from: info, key: "vertical_spacing", defaultValue: 0)
  239. var vertical:CPDFWatermarkVerticalPosition = .center
  240. var horizontal:CPDFWatermarkHorizontalPosition = .center
  241. switch verticalAlignment {
  242. case "top":
  243. vertical = .top
  244. case "center":
  245. vertical = .center
  246. case "bottom":
  247. vertical = .bottom
  248. default:
  249. vertical = .center
  250. }
  251. switch horizontalAlignment {
  252. case "left":
  253. horizontal = .left
  254. case "center":
  255. horizontal = .center
  256. case "right":
  257. horizontal = .right
  258. default:
  259. horizontal = .center
  260. }
  261. if(pages.isEmpty){
  262. result(FlutterError(code: "WATERMARK_FAIL", message: "The page range cannot be empty, please set the page range, for example: pages: \"0,1,2,3\"", details: nil))
  263. return
  264. }
  265. if("text" == type){
  266. if(textContent.isEmpty){
  267. result(FlutterError(code: "WATERMARK_FAIL", message: "Add text watermark, the text cannot be empty", details: nil))
  268. return
  269. }
  270. } else{
  271. if(imagePath.isEmpty){
  272. result(FlutterError(code: "WATERMARK_FAIL", message: "image path is empty", details: nil))
  273. return
  274. }
  275. }
  276. if type == "text" {
  277. let textWatermark = CPDFWatermark(document: self.document, type: .text)
  278. textWatermark?.text = textContent
  279. print("textColor:\(textColor)")
  280. let font = CPDFFont(familyName: "Helvetica", fontStyle: "")
  281. textWatermark?.cFont = font
  282. textWatermark?.opacity = opacity
  283. textWatermark?.fontSize = CGFloat(fontSize)
  284. textWatermark?.textColor = ColorHelper.colorWithHexString(hex: textColor)
  285. textWatermark?.scale = scale
  286. textWatermark?.isTilePage = isTilePage
  287. textWatermark?.isFront = isFront
  288. textWatermark?.tx = horizontalOffset
  289. textWatermark?.ty = verticalOffset
  290. textWatermark?.rotation = rotation
  291. textWatermark?.pageString = pages
  292. textWatermark?.horizontalPosition = horizontal
  293. textWatermark?.verticalPosition = vertical
  294. if textWatermark?.isTilePage == true {
  295. textWatermark?.verticalSpacing = verticalSpacing
  296. textWatermark?.horizontalSpacing = horizontalSpacing
  297. }
  298. self.document?.addWatermark(textWatermark)
  299. self.document?.updateWatermark(textWatermark)
  300. } else if type == "image" {
  301. let imageWatermark = CPDFWatermark(document: self.document, type: .image)
  302. imageWatermark?.image = UIImage.init(contentsOfFile: imagePath)
  303. imageWatermark?.opacity = opacity
  304. imageWatermark?.scale = scale
  305. imageWatermark?.isTilePage = isTilePage
  306. imageWatermark?.isFront = isFront
  307. imageWatermark?.tx = horizontalOffset
  308. imageWatermark?.ty = verticalOffset
  309. imageWatermark?.rotation = rotation
  310. imageWatermark?.pageString = pages
  311. imageWatermark?.horizontalPosition = horizontal
  312. imageWatermark?.verticalPosition = vertical
  313. if imageWatermark?.isTilePage == true {
  314. imageWatermark?.verticalSpacing = verticalSpacing
  315. imageWatermark?.horizontalSpacing = horizontalSpacing
  316. }
  317. self.document?.addWatermark(imageWatermark)
  318. self.document?.updateWatermark(imageWatermark)
  319. }
  320. self.pdfViewController?.pdfListView?.layoutDocumentView()
  321. }
  322. func getValue<T>(from info: [String: Any]?, key: String, defaultValue: T) -> T {
  323. guard let value = info?[key] as? T else {
  324. return defaultValue
  325. }
  326. return value
  327. }
  328. }