RCTCPDFPageUtil.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. //
  2. // RCTCPDFPageUtil.swift
  3. // react-native-compdfkit-pdf
  4. //
  5. // Copyright © 2014-2025 PDF Technologies, Inc. All Rights Reserved.
  6. //
  7. // THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
  8. // AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
  9. // UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
  10. // This notice may not be removed from this file.
  11. //
  12. import UIKit
  13. import ComPDFKit
  14. class RCTCPDFPageUtil: NSObject {
  15. private var page: CPDFPage?
  16. public var pageIndex: Int = 0
  17. init(page: CPDFPage? = nil) {
  18. self.page = page
  19. }
  20. //MARK: - Public Methods
  21. func getAnnotations() -> [Dictionary<String, Any>] {
  22. var annotaionDicts:[Dictionary<String, Any>] = []
  23. let annoations = page?.annotations ?? []
  24. for annoation in annoations {
  25. var annotaionDict: [String : Any] = [:]
  26. let type: String = annoation.type
  27. if annoation.type == "Widget" {
  28. continue
  29. }
  30. switch type {
  31. case "Highlight", "Squiggly", "Underline", "Strikeout":
  32. if let markupAnnotation = annoation as? CPDFMarkupAnnotation {
  33. let lowertype = lowercaseFirstLetter(of: type)
  34. let memory = getMemoryAddress(markupAnnotation)
  35. annotaionDict["uuid"] = memory
  36. annotaionDict["type"] = lowertype
  37. annotaionDict["title"] = markupAnnotation.userName()
  38. annotaionDict["page"] = pageIndex
  39. annotaionDict["content"] = markupAnnotation.contents
  40. }
  41. case "Circle":
  42. if let circleAnnotation = annoation as? CPDFCircleAnnotation {
  43. let lowertype = lowercaseFirstLetter(of: type)
  44. let memory = getMemoryAddress(circleAnnotation)
  45. annotaionDict["uuid"] = memory
  46. annotaionDict["type"] = lowertype
  47. annotaionDict["title"] = circleAnnotation.userName()
  48. annotaionDict["page"] = pageIndex
  49. annotaionDict["content"] = circleAnnotation.contents
  50. }
  51. case "Square":
  52. if let squareAnnotation = annoation as? CPDFSquareAnnotation {
  53. let lowertype = lowercaseFirstLetter(of: type)
  54. let memory = getMemoryAddress(squareAnnotation)
  55. annotaionDict["uuid"] = memory
  56. annotaionDict["type"] = lowertype
  57. annotaionDict["title"] = squareAnnotation.userName()
  58. annotaionDict["page"] = pageIndex
  59. annotaionDict["content"] = squareAnnotation.contents
  60. }
  61. case "Line", "Arrow":
  62. if let lineAnnotation = annoation as? CPDFLineAnnotation {
  63. let lowertype = lowercaseFirstLetter(of: type)
  64. let memory = getMemoryAddress(lineAnnotation)
  65. annotaionDict["uuid"] = memory
  66. annotaionDict["type"] = lowertype
  67. annotaionDict["title"] = lineAnnotation.userName()
  68. annotaionDict["page"] = pageIndex
  69. annotaionDict["content"] = lineAnnotation.contents
  70. }
  71. case "Freehand":
  72. if let inkAnnotation = annoation as? CPDFInkAnnotation {
  73. let memory = getMemoryAddress(inkAnnotation)
  74. annotaionDict["uuid"] = memory
  75. annotaionDict["type"] = "ink"
  76. annotaionDict["title"] = inkAnnotation.userName()
  77. annotaionDict["page"] = pageIndex
  78. annotaionDict["content"] = inkAnnotation.contents
  79. }
  80. case "Note":
  81. if let noteAnnotation = annoation as? CPDFTextAnnotation {
  82. let lowertype = lowercaseFirstLetter(of: type)
  83. let memory = getMemoryAddress(noteAnnotation)
  84. annotaionDict["uuid"] = memory
  85. annotaionDict["type"] = lowertype
  86. annotaionDict["title"] = noteAnnotation.userName()
  87. annotaionDict["page"] = pageIndex
  88. annotaionDict["content"] = noteAnnotation.contents
  89. }
  90. case "FreeText":
  91. if let freeTextAnnotation = annoation as? CPDFFreeTextAnnotation {
  92. let memory = getMemoryAddress(freeTextAnnotation)
  93. annotaionDict["uuid"] = memory
  94. annotaionDict["type"] = "freetext"
  95. annotaionDict["title"] = freeTextAnnotation.userName()
  96. annotaionDict["page"] = pageIndex
  97. annotaionDict["content"] = freeTextAnnotation.contents
  98. }
  99. case "Stamp", "Image":
  100. if let stampAnnotation = annoation as? CPDFStampAnnotation {
  101. let lowertype = lowercaseFirstLetter(of: type)
  102. let memory = getMemoryAddress(stampAnnotation)
  103. annotaionDict["uuid"] = memory
  104. annotaionDict["type"] = lowertype
  105. if type == "Image" {
  106. annotaionDict["type"] = "pictures"
  107. }
  108. annotaionDict["title"] = stampAnnotation.userName()
  109. annotaionDict["page"] = pageIndex
  110. annotaionDict["content"] = stampAnnotation.contents
  111. }
  112. case "Link":
  113. if let linkAnnotation = annoation as? CPDFLinkAnnotation {
  114. let lowertype = lowercaseFirstLetter(of: type)
  115. let memory = getMemoryAddress(linkAnnotation)
  116. annotaionDict["uuid"] = memory
  117. annotaionDict["type"] = lowertype
  118. annotaionDict["title"] = linkAnnotation.userName()
  119. annotaionDict["page"] = pageIndex
  120. annotaionDict["content"] = linkAnnotation.contents
  121. }
  122. case "Media":
  123. if let mediaAnnotation = annoation as? CPDFSoundAnnotation {
  124. let memory = getMemoryAddress(mediaAnnotation)
  125. annotaionDict["uuid"] = memory
  126. annotaionDict["type"] = "sound"
  127. annotaionDict["title"] = mediaAnnotation.userName()
  128. annotaionDict["page"] = pageIndex
  129. annotaionDict["content"] = mediaAnnotation.contents
  130. }
  131. case "":
  132. if let signatureAnnotation = annoation as? CPDFSignatureAnnotation {
  133. let memory = getMemoryAddress(signatureAnnotation)
  134. annotaionDict["uuid"] = memory
  135. annotaionDict["type"] = "signature"
  136. annotaionDict["title"] = signatureAnnotation.userName()
  137. annotaionDict["page"] = pageIndex
  138. annotaionDict["content"] = signatureAnnotation.contents
  139. }
  140. default:
  141. print("Unhandled type: \(type)")
  142. }
  143. if annotaionDict["type"] != nil {
  144. annotaionDicts.append(annotaionDict)
  145. }
  146. }
  147. return annotaionDicts
  148. }
  149. func getForms() -> [Dictionary<String, Any>] {
  150. var formDicts:[Dictionary<String, Any>] = []
  151. let forms = page?.annotations ?? []
  152. for form in forms {
  153. var formDict: [String : Any] = [:]
  154. let type: String = form.type
  155. if form.type == "Widget" {
  156. if let widgetAnnotation = form as? CPDFWidgetAnnotation {
  157. let widgetType: String = widgetAnnotation.widgetType
  158. switch widgetType {
  159. case "CheckBox", "RadioButton", "PushButton":
  160. if let buttonWidget = form as? CPDFButtonWidgetAnnotation {
  161. let lowertype = lowercaseFirstLetter(of: widgetType)
  162. let memory = getMemoryAddress(buttonWidget)
  163. formDict["uuid"] = memory
  164. formDict["type"] = lowertype
  165. formDict["title"] = buttonWidget.fieldName()
  166. formDict["page"] = pageIndex
  167. if widgetType != "PushButton" {
  168. let isOn = buttonWidget.state()
  169. if (isOn != 0) {
  170. formDict["isChecked"] = true
  171. } else {
  172. formDict["isChecked"] = false
  173. }
  174. }
  175. }
  176. case "TextField":
  177. if let textFieldWidget = form as? CPDFTextWidgetAnnotation {
  178. let lowertype = lowercaseFirstLetter(of: widgetType)
  179. let memory = getMemoryAddress(textFieldWidget)
  180. formDict["uuid"] = memory
  181. formDict["type"] = lowertype
  182. formDict["title"] = textFieldWidget.fieldName()
  183. formDict["page"] = pageIndex
  184. formDict["text"] = textFieldWidget.stringValue
  185. }
  186. case "ListBox", "ComboBox":
  187. if let choiceWidget = form as? CPDFChoiceWidgetAnnotation {
  188. let lowertype = lowercaseFirstLetter(of: widgetType)
  189. let memory = getMemoryAddress(choiceWidget)
  190. formDict["uuid"] = memory
  191. formDict["type"] = lowertype
  192. formDict["title"] = choiceWidget.fieldName()
  193. formDict["page"] = pageIndex
  194. }
  195. case "SignatureFields":
  196. if let signatureWidget = form as? CPDFSignatureWidgetAnnotation {
  197. let memory = getMemoryAddress(signatureWidget)
  198. formDict["uuid"] = memory
  199. formDict["type"] = "signaturesFields"
  200. formDict["title"] = signatureWidget.fieldName()
  201. formDict["page"] = pageIndex
  202. }
  203. default:
  204. print("Unhandled type: \(type)")
  205. }
  206. formDicts.append(formDict)
  207. }
  208. }
  209. }
  210. return formDicts
  211. }
  212. func setWidgetIsChecked(uuid: String, isChecked: Bool) {
  213. if let widget = self.getForm(formUUID: uuid) {
  214. if let buttonWidget = widget as? CPDFButtonWidgetAnnotation {
  215. buttonWidget.setState(isChecked ? 1 : 0)
  216. }
  217. }
  218. }
  219. func setTextWidgetText(uuid: String, text: String) {
  220. if let widget = self.getForm(formUUID: uuid) {
  221. if let textFieldWidget = widget as? CPDFTextWidgetAnnotation {
  222. textFieldWidget.stringValue = text
  223. }
  224. }
  225. }
  226. func addWidgetImageSignature(uuid: String, imagePath: URL, completionHandler: @escaping (Bool) -> Void) {
  227. if let widget = self.getForm(formUUID: uuid) {
  228. if let signatureWidget = widget as? CPDFSignatureWidgetAnnotation {
  229. let image = UIImage(contentsOfFile: imagePath.path)
  230. signatureWidget.sign(with: image)
  231. completionHandler(true)
  232. }
  233. } else if let annotation = self.getAnnotation(formUUID: uuid) {
  234. if let signatureAnnotation = annotation as? CPDFSignatureAnnotation {
  235. let image = UIImage(contentsOfFile: imagePath.path)
  236. signatureAnnotation.setImage(image)
  237. completionHandler(true)
  238. }
  239. } else {
  240. completionHandler(false)
  241. }
  242. }
  243. func updateAp(uuid: String) {
  244. if let widget = self.getForm(formUUID: uuid) {
  245. widget.updateAppearanceStream()
  246. } else if let annotation = self.getAnnotation(formUUID: uuid) {
  247. annotation.updateAppearanceStream()
  248. }
  249. }
  250. //MARK: - Private Methods
  251. func getAnnotation(formUUID uuid: String) -> CPDFAnnotation? {
  252. let annoations = page?.annotations ?? []
  253. for annoation in annoations {
  254. let type: String = annoation.type
  255. if annoation.type == "Widget" {
  256. continue
  257. }
  258. let _uuid = getMemoryAddress(annoation)
  259. if _uuid == uuid {
  260. return annoation
  261. }
  262. }
  263. return nil
  264. }
  265. func getForm(formUUID uuid: String) -> CPDFWidgetAnnotation? {
  266. let annoations = page?.annotations ?? []
  267. for annoation in annoations {
  268. let type: String = annoation.type
  269. if annoation.type == "Widget" {
  270. if let widgetAnnotation = annoation as? CPDFWidgetAnnotation {
  271. let _uuid = getMemoryAddress(annoation)
  272. if _uuid == uuid {
  273. return widgetAnnotation
  274. }
  275. }
  276. }
  277. }
  278. return nil
  279. }
  280. func lowercaseFirstLetter(of string: String) -> String {
  281. guard !string.isEmpty else { return string }
  282. let lowercaseString = string.prefix(1).lowercased() + string.dropFirst()
  283. return lowercaseString
  284. }
  285. func getMemoryAddress<T: AnyObject>(_ object: T) -> String {
  286. let pointer = Unmanaged.passUnretained(object).toOpaque()
  287. return String(describing: pointer)
  288. }
  289. }