KMBatchAddHeaderFooterOperation.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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. self.saveAsPDFToPath((self.operateFile?.currentOperateInfo?.fetchDestinationFilepath())!)
  58. }else {
  59. willChangeValue(forKey: "isFinished")
  60. willChangeValue(forKey: "isExecuting")
  61. hasExcuting = false
  62. hasFinished = true
  63. didChangeValue(forKey: "isExecuting")
  64. didChangeValue(forKey: "isFinished")
  65. }
  66. }
  67. override func cancel() {
  68. // super.cancel()
  69. if isExecuting {
  70. operateFile!.removeWatermarkInfo.status = .Waiting
  71. if FileManager.default.fileExists(atPath: self.currentParameter().outPutPath!) { try? FileManager.default.removeItem(atPath: self.currentParameter().outPutPath!)
  72. }
  73. self.delegate?.fileOperateCanceled?(self.operateFile!, info: self.currentParameter())
  74. willChangeValue(forKey: "isFinished")
  75. hasFinished = true
  76. didChangeValue(forKey: "isFinished")
  77. } else {
  78. willChangeValue(forKey: "isCancelled")
  79. hasCanceled = true
  80. didChangeValue(forKey: "isCancelled")
  81. }
  82. }
  83. func saveAsPDFToPath(_ path: String) {
  84. var filePath = self.pdfDocument?.documentURL?.path
  85. let password = self.password
  86. if filePath == nil {
  87. let str = String(format: "%@.pdf", KMLocalizedString("Untitled", nil))
  88. let writeSuccess = self.pdfDocument!.write(to: URL(fileURLWithPath: (kTempSavePath?.stringByAppendingPathComponent(str))!))
  89. if writeSuccess {
  90. let newDocument: CPDFDocument = CPDFDocument(url: URL(fileURLWithPath: (kTempSavePath?.stringByAppendingPathComponent(str))!))
  91. filePath = newDocument.documentURL?.path
  92. } else {
  93. NSSound.beep()
  94. return
  95. }
  96. }
  97. guard let document = CPDFDocument(url: URL(fileURLWithPath: filePath!)) else {
  98. return
  99. }
  100. if password?.count ?? 0 > 0 {
  101. document.unlock(withPassword: password)
  102. }
  103. let font = NSFont.boldSystemFont(ofSize: self.headerFooter?.getTextFontSize() ?? 16)
  104. let style = NSMutableParagraphStyle()
  105. style.alignment = .center
  106. style.lineBreakMode = .byCharWrapping
  107. var dictionary = [NSAttributedString.Key: Any]()
  108. dictionary[.paragraphStyle] = style
  109. dictionary[.font] = font
  110. let size = "text".boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: CGFloat(MAXFLOAT)), options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: dictionary).size
  111. if self.headerFooter!.isBates {
  112. var bates: CPDFHeaderFooter = document.bates()
  113. 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))
  114. var arr = [NSNumber]()
  115. for i in 0..<(self.operateFile?.addBatesInfo.pagesArray?.count ?? 0) {
  116. var tmp = self.operateFile?.addBatesInfo.pagesArray?[i].intValue
  117. tmp! -= 1
  118. let number = NSNumber(value: tmp ?? 0)
  119. arr.append(number)
  120. }
  121. if arr.count < 1 {
  122. 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)])
  123. self.delegate?.fileOperateFailed?(self.operateFile!, error: error, info: self.operateFile!.addBatesInfo)
  124. willChangeValue(forKey: "isFinished")
  125. self.hasFinished = true
  126. didChangeValue(forKey: "isFinished")
  127. return
  128. }
  129. let pagesString = arr.map{ "\($0)" }.joined(separator: ",")
  130. if pagesString.count > 0 {
  131. bates.pageString = pagesString
  132. } else {
  133. let pageString = String(format: "0-%ld", document.pageCount-1)
  134. bates.pageString = pageString
  135. }
  136. let topLeftString = self.headerFooter?.topLeftString
  137. let topCenterString = self.headerFooter?.topCenterString
  138. let topRightString = self.headerFooter?.topRightString
  139. let bottomLeftString = self.headerFooter?.bottomLeftString
  140. let bottomCenterString = self.headerFooter?.bottomCenterString
  141. let bottomRightString = self.headerFooter?.bottomRightString
  142. let items = [topLeftString, topCenterString, topRightString, bottomLeftString, bottomCenterString, bottomRightString]
  143. for i in 0..<items.count {
  144. let text = items[i]
  145. bates.setText(text, at: UInt(Int(i)))
  146. bates.setTextColor(self.headerFooter?.getTextColor(), at: UInt(Int(i)))
  147. bates.setFontSize(self.headerFooter?.getTextFontSize() ?? 16.0, at: UInt(Int(i)))
  148. }
  149. bates.update()
  150. } else {
  151. let headerFooterNew = document.headerFooter()
  152. 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))
  153. var arr = [NSNumber]()
  154. for i in 0..<(self.operateFile?.addHeaderFooterInfo.pagesArray?.count ?? 0) {
  155. var tmp = self.operateFile?.addHeaderFooterInfo.pagesArray?[i].intValue
  156. tmp! -= 1
  157. let number = NSNumber(value: tmp ?? 0)
  158. arr.append(number)
  159. }
  160. if arr.count < 1 {
  161. 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)])
  162. self.delegate?.fileOperateFailed?(self.operateFile!, error: error, info: self.operateFile!.addHeaderFooterInfo)
  163. willChangeValue(forKey: "isFinished")
  164. self.hasFinished = true
  165. didChangeValue(forKey: "isFinished")
  166. return
  167. }
  168. let pagesString = arr.map{ "\($0)" }.joined(separator: ",")
  169. if pagesString.count > 0 {
  170. headerFooterNew?.pageString = pagesString
  171. } else {
  172. let pageString = String(format: "0-%ld", document.pageCount-1)
  173. headerFooterNew?.pageString = pageString
  174. }
  175. let num: Int = Int(self.headerFooter?.startString ?? "0") ?? 0
  176. let pageCount = Int(document.pageCount) + num - 1
  177. let topLeftString = convertPageFormat(oldString: self.headerFooter!.topLeftString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
  178. let topCenterString = convertPageFormat(oldString: self.headerFooter!.topCenterString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
  179. let topRightString = convertPageFormat(oldString: self.headerFooter!.topRightString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
  180. let bottomLeftString = convertPageFormat(oldString: self.headerFooter!.bottomLeftString, startPage: self.headerFooter!.startString, pageCount: "\(pageCount)")
  181. let bottomCenterString = convertPageFormat(oldString: self.headerFooter!.bottomCenterString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
  182. let bottomRightString = convertPageFormat(oldString: self.headerFooter!.bottomRightString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
  183. let items = [topLeftString, topCenterString, topRightString, bottomLeftString, bottomCenterString, bottomRightString]
  184. for i in 0..<items.count {
  185. let text = items[i]
  186. headerFooterNew?.setText(text, at: UInt(i))
  187. headerFooterNew?.setTextColor(self.headerFooter!.getTextColor(), at: UInt(Int(i)))
  188. headerFooterNew?.setFontSize(self.headerFooter!.getTextFontSize(), at: UInt(Int(i)))
  189. }
  190. headerFooterNew?.update()
  191. }
  192. let documentPath = NSTemporaryDirectory()
  193. let tempPath = documentPath.appending(filePath!.lastPathComponent)
  194. if FileManager.default.fileExists(atPath: tempPath) {
  195. try? FileManager.default.removeItem(atPath: tempPath)
  196. }
  197. let result = document.write(to: URL(fileURLWithPath: tempPath))
  198. if result {
  199. if FileManager.default.fileExists(atPath: path) {
  200. try? FileManager.default.removeItem(atPath: path)
  201. }
  202. try? FileManager.default.moveItem(atPath: tempPath, toPath: path)
  203. } else {
  204. try? FileManager.default.removeItem(atPath: tempPath)
  205. }
  206. if result {
  207. self.delegate?.fileOperateSuccessed?(self.operateFile!, info: self.currentParameter())
  208. } else {
  209. self.delegate?.fileOperateFailed?(self.operateFile!, error: self.defaultError(), info: self.currentParameter())
  210. }
  211. willChangeValue(forKey: "isFinished")
  212. self.hasFinished = true
  213. didChangeValue(forKey: "isFinished")
  214. }
  215. func defaultError() -> NSError {
  216. return errorWithMsg(NSLocalizedString("Failed", comment: ""))
  217. }
  218. }
  219. func convertPageFormat(oldString: String, startPage: String, pageCount: String) -> String {
  220. let pageFormatArray = ["1", "1 of n", "1/n", "Page 1", "Page 1 of n"]
  221. var newString = oldString
  222. for pageFormat in pageFormatArray {
  223. let format = "<<(pageFormat)>>"
  224. if newString.contains(format) {
  225. var tString: String? = nil
  226. if pageFormat == "1" {
  227. tString = "<<\(startPage)>>"
  228. } else if pageFormat == "1 of n" {
  229. tString = "\(startPage) of \(pageCount)"
  230. } else if pageFormat == "1/n" {
  231. tString = "\(startPage)/\(pageCount)"
  232. } else if pageFormat == "Page 1" {
  233. tString = "Page <<\(startPage)>>"
  234. } else if pageFormat == "Page 1 of n" {
  235. tString = "Page <<\(startPage)>> of \(pageCount)"
  236. }
  237. newString = newString.replacingOccurrences(of: format, with: tString ?? "")
  238. }
  239. }
  240. newString = convertDateFormat(oldString: newString)
  241. return newString
  242. }
  243. func convertDateFormat(oldString: String) -> String {
  244. var newString = oldString
  245. for dateFormat in KMHeaderFooterManager.defaultManager.dateFormatArray {
  246. if newString.contains(dateFormat) {
  247. let formatString = dateFormat.replacingOccurrences(of: "m", with: "M")
  248. let replace = "<<\(dateFormat)>>"
  249. let date = Date()
  250. let dateFormatter = DateFormatter()
  251. dateFormatter.dateFormat = formatString
  252. let dateString = dateFormatter.string(from: date)
  253. newString = newString.replacingOccurrences(of: replace, with: dateString)
  254. }
  255. }
  256. return newString
  257. }