CPDFDocumentPlugin.swift 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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. //TODO: 修改这个打开文件方法, 根据打开文档的结果返回对应值, 要是没有对应的错误就不管
  67. // result("success")
  68. // 打开成功:"success"
  69. // 打开失败,文档存在密码 : "errorPassword"
  70. // 错误文件 : "errorFile"
  71. // 错误页面 : "errorPage"
  72. // 错误的格式 : "errorFormat"
  73. // 未知 : "unknown"
  74. // 错误安全性 : "errorSecurity"
  75. // 未验证许可证 : "notVerifyLicense"
  76. // 无读取权限 : "noReadPermission"
  77. self.document = CPDFDocument(url: URL(fileURLWithPath: path))
  78. if(self.document?.isLocked == true){
  79. let success = self.document?.unlock(withPassword: password as? String ?? "")
  80. if(success == true){
  81. result("success")
  82. }else {
  83. result("errorPassword")
  84. }
  85. }
  86. self.pdfViewController?.pdfListView?.document = self.document
  87. self.pdfViewController?.pdfListView?.setNeedsDisplay()
  88. result(true)
  89. case CPDFConstants.getFileName:
  90. if(self.document == nil){
  91. print("self.document is nil")
  92. result("is nil")
  93. return
  94. }
  95. let fileName = self.document?.documentURL.lastPathComponent
  96. result(fileName)
  97. case CPDFConstants.isEncrypted:
  98. let isEncrypted = self.document?.isEncrypted ?? false
  99. result(isEncrypted)
  100. case CPDFConstants.isImageDoc:
  101. let isImageDoc = self.document?.isImageDocument() ?? false
  102. result(isImageDoc)
  103. case CPDFConstants.getPermissions:
  104. let permissions = self.document?.permissionsStatus ?? .none
  105. switch permissions {
  106. case .none:
  107. result(0)
  108. case .user:
  109. result(1)
  110. case .owner:
  111. result(2)
  112. default:
  113. result(0)
  114. }
  115. case CPDFConstants.checkOwnerUnlocked:
  116. let owner = self.document?.isCheckOwnerUnlocked() ?? false
  117. result(owner)
  118. case CPDFConstants.checkOwnerPassword:
  119. let info = call.arguments as? [String: Any]
  120. let password = info?["password"] as? String ?? ""
  121. let isOwnerPassword = self.document?.checkOwnerPassword(password) ?? false
  122. result(isOwnerPassword)
  123. case CPDFConstants.hasChange:
  124. let isModified = self.document?.isModified() ?? false
  125. result(isModified)
  126. case CPDFConstants.importAnnotations:
  127. let importPath = call.arguments as? String ?? ""
  128. let success = self.document?.importAnnotation(fromXFDFPath: importPath) ?? false
  129. if success {
  130. self.pdfViewController?.pdfListView?.setNeedsDisplayForVisiblePages()
  131. }
  132. result(success)
  133. case CPDFConstants.exportAnnotations:
  134. let fileNameWithExtension = self.document?.documentURL.lastPathComponent ?? ""
  135. let fileName = (fileNameWithExtension as NSString).deletingPathExtension
  136. let documentFolder = NSHomeDirectory().appending("/Documents/\(fileName)_xfdf.xfdf")
  137. let succes = self.document?.exportAnnotation(toXFDFPath: documentFolder) ?? false
  138. if succes {
  139. result(documentFolder)
  140. } else {
  141. result("")
  142. }
  143. case CPDFConstants.removeAllAnnotations:
  144. let pageCount = self.document?.pageCount ?? 0
  145. for i in 0..<pageCount {
  146. let page = self.document?.page(at: i)
  147. page?.removeAllAnnotations()
  148. }
  149. self.pdfViewController?.pdfListView?.setNeedsDisplayForVisiblePages()
  150. self.pdfViewController?.pdfListView?.updateActiveAnnotations([])
  151. result(true)
  152. case CPDFConstants.getPageCount:
  153. let count = self.document?.pageCount ?? 1
  154. result(count)
  155. case CPDFConstants.saveAs:
  156. let info = call.arguments as? [String: Any]
  157. let savePath = self.getValue(from: info, key: "save_path", defaultValue: "") ?? ""
  158. let removeSecurity = self.getValue(from: info, key: "remove_security", defaultValue: false)
  159. let fontSubSet = self.getValue(from: info, key: "font_sub_set", defaultValue: true)
  160. var success = false
  161. if removeSecurity {
  162. success = self.document?.writeDecrypt(to: URL(fileURLWithPath: savePath), isSaveFontSubset: fontSubSet) ?? false
  163. } else {
  164. success = self.document?.write(to: URL(fileURLWithPath: savePath), isSaveFontSubset: fontSubSet) ?? false
  165. }
  166. result(success)
  167. case CPDFConstants.print:
  168. self.pdfViewController?.enterPrintState()
  169. case CPDFConstants.removePassword:
  170. let url = self.document?.documentURL
  171. let success = self.document?.writeDecrypt(to: url, isSaveFontSubset: true) ?? false
  172. result(success)
  173. case CPDFConstants.setPassword:
  174. let info = call.arguments as? [String: Any]
  175. let userPassword : String = self.getValue(from: info, key: "user_password", defaultValue: "")
  176. let ownerPassword : String = self.getValue(from: info, key: "owner_password", defaultValue: "")
  177. let allowsPrinting : Bool = self.getValue(from: info, key: "allows_printing", defaultValue: true)
  178. let allowsCopying : Bool = self.getValue(from: info, key: "allows_copying", defaultValue: true)
  179. let encryptAlgo : String = self.getValue(from: info, key: "encrypt_algo", defaultValue: "rc4")
  180. var level: Int = 0
  181. // Encryption mode, the type passed in is:rc4, aes128, aes256, noEncryptAlgo
  182. switch encryptAlgo {
  183. case "rc4":
  184. level = 0
  185. case "aes128":
  186. level = 1
  187. case "aes256":
  188. level = 2
  189. case "noEncryptAlgo":
  190. level = 3
  191. default:
  192. level = 3
  193. }
  194. var options:[CPDFDocumentWriteOption: Any] = [:]
  195. options[CPDFDocumentWriteOption.userPasswordOption] = userPassword
  196. options[CPDFDocumentWriteOption.ownerPasswordOption] = ownerPassword
  197. options[CPDFDocumentWriteOption.allowsPrintingOption] = allowsPrinting
  198. options[CPDFDocumentWriteOption.allowsCopyingOption] = allowsCopying
  199. options[CPDFDocumentWriteOption.encryptionLevelOption] = NSNumber(value: level)
  200. let url = self.document?.documentURL
  201. let success = self.document?.write(to: url, withOptions: options, isSaveFontSubset: true)
  202. result(success)
  203. case CPDFConstants.getEncryptAlgorithm:
  204. let level: CPDFDocumentEncryptionLevel = self.document?.encryptionLevel ?? .noEncryptAlgo
  205. switch level {
  206. case .RC4:
  207. result("rc4")
  208. case .AES128:
  209. result("aes128")
  210. case .AES256:
  211. result("aes256")
  212. case .noEncryptAlgo:
  213. result("noEncryptAlgo")
  214. @unknown default:
  215. result("noEncryptAlgo")
  216. }
  217. case CPDFConstants.createWatermark:
  218. self.createWatermark(call: call, result: result)
  219. case CPDFConstants.removeAllWatermark:
  220. let watrmarks = self.document?.watermarks() ?? []
  221. for watermark in watrmarks {
  222. self.document?.removeWatermark(watermark)
  223. }
  224. let url = self.document?.documentURL
  225. self.document?.write(to: url, isSaveFontSubset: true)
  226. self.pdfViewController?.pdfListView?.layoutDocumentView()
  227. default:
  228. result(FlutterMethodNotImplemented)
  229. }
  230. });
  231. }
  232. private func createWatermark(call: FlutterMethodCall, result: FlutterResult) {
  233. let info = call.arguments as? [String: Any]
  234. // text, image
  235. let type : String = self.getValue(from: info, key: "type", defaultValue: "")
  236. // "0,1,2,3,4"
  237. let pages : String = self.getValue(from: info, key: "pages", defaultValue: "")
  238. let textContent : String = self.getValue(from: info, key: "text_content", defaultValue: "")
  239. let imagePath : String = self.getValue(from: info, key: "image_path", defaultValue: "")
  240. let textColor : String = self.getValue(from: info, key: "text_color", defaultValue: "#000000")
  241. let fontSize : Int = self.getValue(from: info, key: "font_size", defaultValue: 24)
  242. let scale : Double = self.getValue(from: info, key: "scale", defaultValue: 1.0)
  243. let rotation : Double = self.getValue(from: info, key: "rotation", defaultValue: 45)
  244. let opacity : Double = self.getValue(from: info, key: "opacity", defaultValue: 1.0)
  245. // top, center, bottom
  246. let verticalAlignment : String = self.getValue(from: info, key: "vertical_alignment", defaultValue: "center")
  247. // left, center, right
  248. let horizontalAlignment : String = self.getValue(from: info, key: "horizontal_alignment", defaultValue: "center")
  249. let verticalOffset : Double = self.getValue(from: info, key: "vertical_offset", defaultValue: 0)
  250. let horizontalOffset : Double = self.getValue(from: info, key: "horizontal_offset", defaultValue: 0)
  251. let isFront : Bool = self.getValue(from: info, key: "is_front", defaultValue: true)
  252. let isTilePage : Bool = self.getValue(from: info, key: "is_tile_page", defaultValue: false)
  253. let horizontalSpacing : Double = self.getValue(from: info, key: "horizontal_spacing", defaultValue: 0)
  254. let verticalSpacing : Double = self.getValue(from: info, key: "vertical_spacing", defaultValue: 0)
  255. var vertical:CPDFWatermarkVerticalPosition = .center
  256. var horizontal:CPDFWatermarkHorizontalPosition = .center
  257. switch verticalAlignment {
  258. case "top":
  259. vertical = .top
  260. case "center":
  261. vertical = .center
  262. case "bottom":
  263. vertical = .bottom
  264. default:
  265. vertical = .center
  266. }
  267. switch horizontalAlignment {
  268. case "left":
  269. horizontal = .left
  270. case "center":
  271. horizontal = .center
  272. case "right":
  273. horizontal = .right
  274. default:
  275. horizontal = .center
  276. }
  277. if(pages.isEmpty){
  278. 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))
  279. return
  280. }
  281. if("text" == type){
  282. if(textContent.isEmpty){
  283. result(FlutterError(code: "WATERMARK_FAIL", message: "Add text watermark, the text cannot be empty", details: nil))
  284. return
  285. }
  286. } else{
  287. if(imagePath.isEmpty){
  288. result(FlutterError(code: "WATERMARK_FAIL", message: "image path is empty", details: nil))
  289. return
  290. }
  291. }
  292. if type == "text" {
  293. let textWatermark = CPDFWatermark(document: self.document, type: .text)
  294. textWatermark?.text = textContent
  295. print("textColor:\(textColor)")
  296. let font = CPDFFont(familyName: "Helvetica", fontStyle: "")
  297. textWatermark?.cFont = font
  298. textWatermark?.opacity = opacity
  299. textWatermark?.fontSize = CGFloat(fontSize)
  300. textWatermark?.textColor = ColorHelper.colorWithHexString(hex: textColor)
  301. textWatermark?.scale = scale
  302. textWatermark?.isTilePage = isTilePage
  303. textWatermark?.isFront = isFront
  304. textWatermark?.tx = horizontalOffset
  305. textWatermark?.ty = verticalOffset
  306. textWatermark?.rotation = rotation
  307. textWatermark?.pageString = pages
  308. textWatermark?.horizontalPosition = horizontal
  309. textWatermark?.verticalPosition = vertical
  310. if textWatermark?.isTilePage == true {
  311. textWatermark?.verticalSpacing = verticalSpacing
  312. textWatermark?.horizontalSpacing = horizontalSpacing
  313. }
  314. self.document?.addWatermark(textWatermark)
  315. self.document?.updateWatermark(textWatermark)
  316. } else if type == "image" {
  317. let imageWatermark = CPDFWatermark(document: self.document, type: .image)
  318. imageWatermark?.image = UIImage.init(contentsOfFile: imagePath)
  319. imageWatermark?.opacity = opacity
  320. imageWatermark?.scale = scale
  321. imageWatermark?.isTilePage = isTilePage
  322. imageWatermark?.isFront = isFront
  323. imageWatermark?.tx = horizontalOffset
  324. imageWatermark?.ty = verticalOffset
  325. imageWatermark?.rotation = rotation
  326. imageWatermark?.pageString = pages
  327. imageWatermark?.horizontalPosition = horizontal
  328. imageWatermark?.verticalPosition = vertical
  329. if imageWatermark?.isTilePage == true {
  330. imageWatermark?.verticalSpacing = verticalSpacing
  331. imageWatermark?.horizontalSpacing = horizontalSpacing
  332. }
  333. self.document?.addWatermark(imageWatermark)
  334. self.document?.updateWatermark(imageWatermark)
  335. }
  336. self.pdfViewController?.pdfListView?.layoutDocumentView()
  337. }
  338. func getValue<T>(from info: [String: Any]?, key: String, defaultValue: T) -> T {
  339. guard let value = info?[key] as? T else {
  340. return defaultValue
  341. }
  342. return value
  343. }
  344. }