KMBatchAddHeaderFooterOperation.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. //
  2. // KMBatchAddHeaderFooterOperation.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by liujiajie on 2023/11/7.
  6. //
  7. import Foundation
  8. let supportDirectory = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last
  9. let mainBundleIdentifier = Bundle.main.bundleIdentifier ?? ""
  10. let kTempSavePath = supportDirectory?.stringByAppendingPathComponent(mainBundleIdentifier)
  11. class KMBatchAddHeaderFooterOperation: KMBatchOperation{
  12. var headerFooter: KMHeaderFooterObject?
  13. var pdfDocument: CPDFDocument?
  14. var password: String?
  15. init(file: KMBatchOperateFile, headerFooter: KMHeaderFooterObject) {
  16. super.init(file: file)
  17. self.headerFooter = headerFooter
  18. }
  19. func currentParameter() -> KMBatchBaseParameter {
  20. if headerFooter!.isBates{
  21. return operateFile!.addBatesInfo
  22. }
  23. return operateFile!.addHeaderFooterInfo
  24. }
  25. override func start() {
  26. self.pdfDocument = CPDFDocument(url: URL(fileURLWithPath: self.operateFile?.filePath ?? ""))
  27. self.password = self.operateFile?.password
  28. if let data = self.pdfDocument?.isLocked, data {
  29. self.pdfDocument?.unlock(withPassword: self.operateFile?.password)
  30. }
  31. if !self.isCancelled {
  32. self.delegate?.fileBeginOperate?(self.operateFile!, info: self.currentParameter())
  33. willChangeValue(forKey: "isExecuting")
  34. self.hasExcuting = true
  35. didChangeValue(forKey: "isExecuting")
  36. if !FileManager.default.fileExists(atPath: self.operateFile!.filePath) {
  37. self.delegate?.fileOperateFailed?(self.operateFile!, error: self.errorWithMsg(KMLocalizedString("File Not Exist", nil)), info: self.operateFile!.removeBatesInfo)
  38. self.willChangeValue(forKey: "isFinished")
  39. self.hasFinished = true
  40. self.didChangeValue(forKey: "isFinished")
  41. return
  42. }
  43. if self.pdfDocument == nil {
  44. self.delegate?.fileOperateFailed?(self.operateFile!, error: self.errorWithMsg(KMLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", nil)), info: self.operateFile!.removeWatermarkInfo)
  45. self.willChangeValue(forKey: "isFinished")
  46. self.hasFinished = true
  47. self.didChangeValue(forKey: "isFinished")
  48. return
  49. }
  50. if !self.pdfDocument!.allowsPrinting || !self.pdfDocument!.allowsCopying {
  51. self.delegate?.fileOperateFailed?(self.operateFile!, error: self.errorWithMsg(KMLocalizedString("This is a secured document. Editing is not permitted.", nil)), info: self.operateFile!.removeWatermarkInfo)
  52. self.willChangeValue(forKey: "isFinished")
  53. self.hasFinished = true
  54. self.didChangeValue(forKey: "isFinished")
  55. return
  56. }
  57. if let filepath = self.operateFile?.currentOperateInfo?.fetchDestinationFilepath() {
  58. self.saveAsPDFToPath(filepath)
  59. }
  60. }else {
  61. willChangeValue(forKey: "isFinished")
  62. willChangeValue(forKey: "isExecuting")
  63. hasExcuting = false
  64. hasFinished = true
  65. didChangeValue(forKey: "isExecuting")
  66. didChangeValue(forKey: "isFinished")
  67. }
  68. }
  69. override func cancel() {
  70. // super.cancel()
  71. if isExecuting {
  72. operateFile!.removeWatermarkInfo.status = .Waiting
  73. if FileManager.default.fileExists(atPath: self.currentParameter().outPutPath!) { try? FileManager.default.removeItem(atPath: self.currentParameter().outPutPath!)
  74. }
  75. self.delegate?.fileOperateCanceled?(self.operateFile!, info: self.currentParameter())
  76. willChangeValue(forKey: "isFinished")
  77. hasFinished = true
  78. didChangeValue(forKey: "isFinished")
  79. } else {
  80. willChangeValue(forKey: "isCancelled")
  81. hasCanceled = true
  82. didChangeValue(forKey: "isCancelled")
  83. }
  84. }
  85. func saveAsPDFToPath(_ path: String) {
  86. var filePath = self.pdfDocument?.documentURL?.path
  87. let password = self.password
  88. if filePath == nil {
  89. let str = String(format: "%@.pdf", KMLocalizedString("Untitled", nil))
  90. let writeSuccess = self.pdfDocument!.write(to: URL(fileURLWithPath: (kTempSavePath?.stringByAppendingPathComponent(str))!))
  91. if writeSuccess {
  92. let newDocument: CPDFDocument = CPDFDocument(url: URL(fileURLWithPath: (kTempSavePath?.stringByAppendingPathComponent(str))!))
  93. filePath = newDocument.documentURL?.path
  94. } else {
  95. NSSound.beep()
  96. return
  97. }
  98. }
  99. guard let document = CPDFDocument(url: URL(fileURLWithPath: filePath!)) else {
  100. return
  101. }
  102. if password?.count ?? 0 > 0 {
  103. document.unlock(withPassword: password)
  104. }
  105. let font = NSFont.boldSystemFont(ofSize: self.headerFooter?.getTextFontSize() ?? 16)
  106. let style = NSMutableParagraphStyle()
  107. style.alignment = .center
  108. style.lineBreakMode = .byCharWrapping
  109. var dictionary = [NSAttributedString.Key: Any]()
  110. dictionary[.paragraphStyle] = style
  111. dictionary[.font] = font
  112. let size = "text".boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: CGFloat(MAXFLOAT)), options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: dictionary).size
  113. if self.headerFooter!.isBates {
  114. var bates: CPDFHeaderFooter = document.bates()
  115. bates.margin = NSEdgeInsets(top: max(CGFloat(self.headerFooter!.topMargin) - size.height, 0), left: CGFloat(self.headerFooter!.leftMargin), bottom: max(CGFloat(self.headerFooter!.bottomMargin) - size.height, 0), right: CGFloat(self.headerFooter!.rightMargin))
  116. var arr = [NSNumber]()
  117. for i in 0..<(self.operateFile?.addBatesInfo.pagesArray?.count ?? 0) {
  118. var tmp = self.operateFile?.addBatesInfo.pagesArray?[i].intValue
  119. tmp! -= 1
  120. let number = NSNumber(value: tmp ?? 0)
  121. arr.append(number)
  122. }
  123. if arr.count < 1 {
  124. let error = NSError(domain: "LocalError", code: 0, userInfo: [NSLocalizedDescriptionKey: KMLocalizedString("Invalid page range or the page number is out of range. Please try again.", nil)])
  125. self.delegate?.fileOperateFailed?(self.operateFile!, error: error, info: self.operateFile!.addBatesInfo)
  126. willChangeValue(forKey: "isFinished")
  127. self.hasFinished = true
  128. didChangeValue(forKey: "isFinished")
  129. return
  130. }
  131. let pagesString = arr.map{ "\($0)" }.joined(separator: ",")
  132. if pagesString.count > 0 {
  133. bates.pageString = pagesString
  134. } else {
  135. let pageString = String(format: "0-%ld", document.pageCount-1)
  136. bates.pageString = pageString
  137. }
  138. let topLeftString = self.headerFooter?.topLeftString
  139. let topCenterString = self.headerFooter?.topCenterString
  140. let topRightString = self.headerFooter?.topRightString
  141. let bottomLeftString = self.headerFooter?.bottomLeftString
  142. let bottomCenterString = self.headerFooter?.bottomCenterString
  143. let bottomRightString = self.headerFooter?.bottomRightString
  144. let items = [topLeftString, topCenterString, topRightString, bottomLeftString, bottomCenterString, bottomRightString]
  145. for i in 0..<items.count {
  146. let text = items[i]
  147. bates.setText(text, at: UInt(Int(i)))
  148. bates.setTextColor(self.headerFooter?.getTextColor(), at: UInt(Int(i)))
  149. bates.setFontSize(self.headerFooter?.getTextFontSize() ?? 16.0, at: UInt(Int(i)))
  150. }
  151. bates.update()
  152. } else {
  153. let headerFooterNew = document.headerFooter()
  154. headerFooterNew?.margin = NSEdgeInsets(top: max(CGFloat(self.headerFooter!.topMargin)-size.height, 0), left: CGFloat(self.headerFooter!.leftMargin), bottom: max(CGFloat(self.headerFooter!.bottomMargin)-size.height, 0), right: CGFloat(self.headerFooter!.rightMargin))
  155. var arr = [NSNumber]()
  156. for i in 0..<(self.operateFile?.addHeaderFooterInfo.pagesArray?.count ?? 0) {
  157. var tmp = self.operateFile?.addHeaderFooterInfo.pagesArray?[i].intValue
  158. tmp! -= 1
  159. let number = NSNumber(value: tmp ?? 0)
  160. arr.append(number)
  161. }
  162. if arr.count < 1 {
  163. let error = NSError(domain: "LocalError", code: 0, userInfo: [NSLocalizedDescriptionKey: KMLocalizedString("Invalid page range or the page number is out of range. Please try again.", nil)])
  164. self.delegate?.fileOperateFailed?(self.operateFile!, error: error, info: self.operateFile!.addHeaderFooterInfo)
  165. willChangeValue(forKey: "isFinished")
  166. self.hasFinished = true
  167. didChangeValue(forKey: "isFinished")
  168. return
  169. }
  170. let pagesString = arr.map{ "\($0)" }.joined(separator: ",")
  171. if pagesString.count > 0 {
  172. headerFooterNew?.pageString = pagesString
  173. } else {
  174. let pageString = String(format: "0-%ld", document.pageCount-1)
  175. headerFooterNew?.pageString = pageString
  176. }
  177. let num: Int = Int(self.headerFooter?.startString ?? "0") ?? 0
  178. let pageCount = Int(document.pageCount) + num - 1
  179. let topLeftString = convertPageFormat(oldString: self.headerFooter!.topLeftString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
  180. let topCenterString = convertPageFormat(oldString: self.headerFooter!.topCenterString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
  181. let topRightString = convertPageFormat(oldString: self.headerFooter!.topRightString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
  182. let bottomLeftString = convertPageFormat(oldString: self.headerFooter!.bottomLeftString, startPage: self.headerFooter!.startString, pageCount: "\(pageCount)")
  183. let bottomCenterString = convertPageFormat(oldString: self.headerFooter!.bottomCenterString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
  184. let bottomRightString = convertPageFormat(oldString: self.headerFooter!.bottomRightString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
  185. let items = [topLeftString, topCenterString, topRightString, bottomLeftString, bottomCenterString, bottomRightString]
  186. for i in 0..<items.count {
  187. let text = items[i]
  188. headerFooterNew?.setText(text, at: UInt(i))
  189. headerFooterNew?.setTextColor(self.headerFooter!.getTextColor(), at: UInt(Int(i)))
  190. headerFooterNew?.setFontSize(self.headerFooter!.getTextFontSize(), at: UInt(Int(i)))
  191. }
  192. headerFooterNew?.update()
  193. }
  194. let documentPath = NSTemporaryDirectory()
  195. let tempPath = documentPath.appending(filePath!.lastPathComponent)
  196. if FileManager.default.fileExists(atPath: tempPath) {
  197. try? FileManager.default.removeItem(atPath: tempPath)
  198. }
  199. let result = document.write(to: URL(fileURLWithPath: tempPath))
  200. if result {
  201. if FileManager.default.fileExists(atPath: path) {
  202. try? FileManager.default.removeItem(atPath: path)
  203. }
  204. try? FileManager.default.moveItem(atPath: tempPath, toPath: path)
  205. } else {
  206. try? FileManager.default.removeItem(atPath: tempPath)
  207. }
  208. if result {
  209. self.delegate?.fileOperateSuccessed?(self.operateFile!, info: self.currentParameter())
  210. } else {
  211. self.delegate?.fileOperateFailed?(self.operateFile!, error: self.defaultError(), info: self.currentParameter())
  212. }
  213. willChangeValue(forKey: "isFinished")
  214. self.hasFinished = true
  215. didChangeValue(forKey: "isFinished")
  216. }
  217. func defaultError() -> NSError {
  218. return errorWithMsg(NSLocalizedString("Failed", comment: ""))
  219. }
  220. }
  221. func convertPageFormat(oldString: String, startPage: String, pageCount: String) -> String {
  222. let pageFormatArray = ["1", "1 of n", "1/n", "Page 1", "Page 1 of n"]
  223. var newString = oldString
  224. for pageFormat in pageFormatArray {
  225. let format = "<<(pageFormat)>>"
  226. if newString.contains(format) {
  227. var tString: String? = nil
  228. if pageFormat == "1" {
  229. tString = "<<\(startPage)>>"
  230. } else if pageFormat == "1 of n" {
  231. tString = "\(startPage) of \(pageCount)"
  232. } else if pageFormat == "1/n" {
  233. tString = "\(startPage)/\(pageCount)"
  234. } else if pageFormat == "Page 1" {
  235. tString = "Page <<\(startPage)>>"
  236. } else if pageFormat == "Page 1 of n" {
  237. tString = "Page <<\(startPage)>> of \(pageCount)"
  238. }
  239. newString = newString.replacingOccurrences(of: format, with: tString ?? "")
  240. }
  241. }
  242. newString = convertDateFormat(oldString: newString)
  243. return newString
  244. }
  245. func convertDateFormat(oldString: String) -> String {
  246. var newString = oldString
  247. for dateFormat in KMHeaderFooterManager.defaultManager.dateFormatArray {
  248. if newString.contains(dateFormat) {
  249. let formatString = dateFormat.replacingOccurrences(of: "m", with: "M")
  250. let replace = "<<\(dateFormat)>>"
  251. let date = Date()
  252. let dateFormatter = DateFormatter()
  253. dateFormatter.dateFormat = formatString
  254. let dateString = dateFormatter.string(from: date)
  255. newString = newString.replacingOccurrences(of: replace, with: dateString)
  256. }
  257. }
  258. return newString
  259. }