123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- //
- // KMBatchAddHeaderFooterOperation.swift
- // PDF Reader Pro
- //
- // Created by liujiajie on 2023/11/7.
- //
- import Foundation
- let supportDirectory = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last
- let mainBundleIdentifier = Bundle.main.bundleIdentifier ?? ""
- let kTempSavePath = supportDirectory?.stringByAppendingPathComponent(mainBundleIdentifier)
- class KMBatchAddHeaderFooterOperation: KMBatchOperation{
- var headerFooter: KMHeaderFooterObject?
- var pdfDocument: CPDFDocument?
- var password: String?
-
- init(file: KMBatchOperateFile, headerFooter: KMHeaderFooterObject) {
- super.init(file: file)
- self.headerFooter = headerFooter
-
- }
- func currentParameter() -> KMBatchBaseParameter {
- if headerFooter!.isBates{
- return operateFile!.addBatesInfo
- }
- return operateFile!.addHeaderFooterInfo
- }
- override func start() {
- self.pdfDocument = CPDFDocument(url: URL(fileURLWithPath: self.operateFile?.filePath ?? ""))
- self.password = self.operateFile?.password
- if let data = self.pdfDocument?.isLocked, data {
- self.pdfDocument?.unlock(withPassword: self.operateFile?.password)
- }
- if !self.isCancelled {
- self.delegate?.fileBeginOperate?(self.operateFile!, info: self.currentParameter())
- willChangeValue(forKey: "isExecuting")
- self.hasExcuting = true
- didChangeValue(forKey: "isExecuting")
- if !FileManager.default.fileExists(atPath: self.operateFile!.filePath) {
- self.delegate?.fileOperateFailed?(self.operateFile!, error: self.errorWithMsg(KMLocalizedString("File Not Exist", nil)), info: self.operateFile!.removeBatesInfo)
-
- self.willChangeValue(forKey: "isFinished")
- self.hasFinished = true
- self.didChangeValue(forKey: "isFinished")
- return
- }
-
- if self.pdfDocument == nil {
- 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)
- self.willChangeValue(forKey: "isFinished")
- self.hasFinished = true
- self.didChangeValue(forKey: "isFinished")
- return
- }
-
- if !self.pdfDocument!.allowsPrinting || !self.pdfDocument!.allowsCopying {
- self.delegate?.fileOperateFailed?(self.operateFile!, error: self.errorWithMsg(KMLocalizedString("This is a secured document. Editing is not permitted.", nil)), info: self.operateFile!.removeWatermarkInfo)
- self.willChangeValue(forKey: "isFinished")
- self.hasFinished = true
- self.didChangeValue(forKey: "isFinished")
- return
- }
- if let filepath = self.operateFile?.currentOperateInfo?.fetchDestinationFilepath() {
- self.saveAsPDFToPath(filepath)
- }
-
- }else {
- willChangeValue(forKey: "isFinished")
- willChangeValue(forKey: "isExecuting")
- hasExcuting = false
- hasFinished = true
- didChangeValue(forKey: "isExecuting")
- didChangeValue(forKey: "isFinished")
- }
- }
- override func cancel() {
- // super.cancel()
- if isExecuting {
- operateFile!.removeWatermarkInfo.status = .Waiting
- if FileManager.default.fileExists(atPath: self.currentParameter().outPutPath!) { try? FileManager.default.removeItem(atPath: self.currentParameter().outPutPath!)
- }
- self.delegate?.fileOperateCanceled?(self.operateFile!, info: self.currentParameter())
-
- willChangeValue(forKey: "isFinished")
- hasFinished = true
- didChangeValue(forKey: "isFinished")
- } else {
- willChangeValue(forKey: "isCancelled")
- hasCanceled = true
- didChangeValue(forKey: "isCancelled")
- }
- }
-
- func saveAsPDFToPath(_ path: String) {
- var filePath = self.pdfDocument?.documentURL?.path
- let password = self.password
- if filePath == nil {
- let str = String(format: "%@.pdf", KMLocalizedString("Untitled", nil))
- let writeSuccess = self.pdfDocument!.write(to: URL(fileURLWithPath: (kTempSavePath?.stringByAppendingPathComponent(str))!))
- if writeSuccess {
- let newDocument: CPDFDocument = CPDFDocument(url: URL(fileURLWithPath: (kTempSavePath?.stringByAppendingPathComponent(str))!))
- filePath = newDocument.documentURL?.path
- } else {
- NSSound.beep()
- return
- }
- }
-
- guard let document = CPDFDocument(url: URL(fileURLWithPath: filePath!)) else {
- return
- }
-
- if password?.count ?? 0 > 0 {
- document.unlock(withPassword: password)
- }
-
- let font = NSFont.boldSystemFont(ofSize: self.headerFooter?.getTextFontSize() ?? 16)
- let style = NSMutableParagraphStyle()
- style.alignment = .center
- style.lineBreakMode = .byCharWrapping
- var dictionary = [NSAttributedString.Key: Any]()
- dictionary[.paragraphStyle] = style
- dictionary[.font] = font
- let size = "text".boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: CGFloat(MAXFLOAT)), options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: dictionary).size
-
- if self.headerFooter!.isBates {
- var bates: CPDFHeaderFooter = document.bates()
- 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))
-
- var arr = [NSNumber]()
- for i in 0..<(self.operateFile?.addBatesInfo.pagesArray?.count ?? 0) {
- var tmp = self.operateFile?.addBatesInfo.pagesArray?[i].intValue
- tmp! -= 1
- let number = NSNumber(value: tmp ?? 0)
- arr.append(number)
- }
- if arr.count < 1 {
- 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)])
- self.delegate?.fileOperateFailed?(self.operateFile!, error: error, info: self.operateFile!.addBatesInfo)
-
- willChangeValue(forKey: "isFinished")
- self.hasFinished = true
- didChangeValue(forKey: "isFinished")
- return
- }
- let pagesString = arr.map{ "\($0)" }.joined(separator: ",")
- if pagesString.count > 0 {
- bates.pageString = pagesString
- } else {
- let pageString = String(format: "0-%ld", document.pageCount-1)
- bates.pageString = pageString
- }
-
- let topLeftString = self.headerFooter?.topLeftString
- let topCenterString = self.headerFooter?.topCenterString
- let topRightString = self.headerFooter?.topRightString
- let bottomLeftString = self.headerFooter?.bottomLeftString
- let bottomCenterString = self.headerFooter?.bottomCenterString
- let bottomRightString = self.headerFooter?.bottomRightString
- let items = [topLeftString, topCenterString, topRightString, bottomLeftString, bottomCenterString, bottomRightString]
- for i in 0..<items.count {
- let text = items[i]
- bates.setText(text, at: UInt(Int(i)))
- bates.setTextColor(self.headerFooter?.getTextColor(), at: UInt(Int(i)))
- bates.setFontSize(self.headerFooter?.getTextFontSize() ?? 16.0, at: UInt(Int(i)))
- }
-
- bates.update()
- } else {
- let headerFooterNew = document.headerFooter()
- 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))
-
- var arr = [NSNumber]()
- for i in 0..<(self.operateFile?.addHeaderFooterInfo.pagesArray?.count ?? 0) {
- var tmp = self.operateFile?.addHeaderFooterInfo.pagesArray?[i].intValue
- tmp! -= 1
- let number = NSNumber(value: tmp ?? 0)
- arr.append(number)
- }
- if arr.count < 1 {
- 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)])
- self.delegate?.fileOperateFailed?(self.operateFile!, error: error, info: self.operateFile!.addHeaderFooterInfo)
- willChangeValue(forKey: "isFinished")
- self.hasFinished = true
- didChangeValue(forKey: "isFinished")
- return
- }
- let pagesString = arr.map{ "\($0)" }.joined(separator: ",")
- if pagesString.count > 0 {
- headerFooterNew?.pageString = pagesString
- } else {
- let pageString = String(format: "0-%ld", document.pageCount-1)
- headerFooterNew?.pageString = pageString
- }
- let num: Int = Int(self.headerFooter?.startString ?? "0") ?? 0
- let pageCount = Int(document.pageCount) + num - 1
-
- let topLeftString = convertPageFormat(oldString: self.headerFooter!.topLeftString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
- let topCenterString = convertPageFormat(oldString: self.headerFooter!.topCenterString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
- let topRightString = convertPageFormat(oldString: self.headerFooter!.topRightString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
- let bottomLeftString = convertPageFormat(oldString: self.headerFooter!.bottomLeftString, startPage: self.headerFooter!.startString, pageCount: "\(pageCount)")
- let bottomCenterString = convertPageFormat(oldString: self.headerFooter!.bottomCenterString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
- let bottomRightString = convertPageFormat(oldString: self.headerFooter!.bottomRightString, startPage: self.headerFooter!.startString,pageCount: "\(pageCount)")
- let items = [topLeftString, topCenterString, topRightString, bottomLeftString, bottomCenterString, bottomRightString]
- for i in 0..<items.count {
- let text = items[i]
- headerFooterNew?.setText(text, at: UInt(i))
- headerFooterNew?.setTextColor(self.headerFooter!.getTextColor(), at: UInt(Int(i)))
- headerFooterNew?.setFontSize(self.headerFooter!.getTextFontSize(), at: UInt(Int(i)))
- }
-
- headerFooterNew?.update()
- }
-
- let documentPath = NSTemporaryDirectory()
- let tempPath = documentPath.appending(filePath!.lastPathComponent)
- if FileManager.default.fileExists(atPath: tempPath) {
- try? FileManager.default.removeItem(atPath: tempPath)
- }
-
- let result = document.write(to: URL(fileURLWithPath: tempPath))
- if result {
- if FileManager.default.fileExists(atPath: path) {
- try? FileManager.default.removeItem(atPath: path)
- }
- try? FileManager.default.moveItem(atPath: tempPath, toPath: path)
- } else {
- try? FileManager.default.removeItem(atPath: tempPath)
- }
- if result {
- self.delegate?.fileOperateSuccessed?(self.operateFile!, info: self.currentParameter())
- } else {
- self.delegate?.fileOperateFailed?(self.operateFile!, error: self.defaultError(), info: self.currentParameter())
- }
-
- willChangeValue(forKey: "isFinished")
- self.hasFinished = true
- didChangeValue(forKey: "isFinished")
- }
- func defaultError() -> NSError {
- return errorWithMsg(NSLocalizedString("Failed", comment: ""))
- }
- }
- func convertPageFormat(oldString: String, startPage: String, pageCount: String) -> String {
- let pageFormatArray = ["1", "1 of n", "1/n", "Page 1", "Page 1 of n"]
- var newString = oldString
- for pageFormat in pageFormatArray {
- let format = "<<(pageFormat)>>"
- if newString.contains(format) {
- var tString: String? = nil
- if pageFormat == "1" {
- tString = "<<\(startPage)>>"
- } else if pageFormat == "1 of n" {
- tString = "\(startPage) of \(pageCount)"
- } else if pageFormat == "1/n" {
- tString = "\(startPage)/\(pageCount)"
- } else if pageFormat == "Page 1" {
- tString = "Page <<\(startPage)>>"
- } else if pageFormat == "Page 1 of n" {
- tString = "Page <<\(startPage)>> of \(pageCount)"
- }
-
- newString = newString.replacingOccurrences(of: format, with: tString ?? "")
- }
- }
-
- newString = convertDateFormat(oldString: newString)
- return newString
- }
- func convertDateFormat(oldString: String) -> String {
- var newString = oldString
- for dateFormat in KMHeaderFooterManager.defaultManager.dateFormatArray {
- if newString.contains(dateFormat) {
- let formatString = dateFormat.replacingOccurrences(of: "m", with: "M")
- let replace = "<<\(dateFormat)>>"
-
- let date = Date()
- let dateFormatter = DateFormatter()
- dateFormatter.dateFormat = formatString
- let dateString = dateFormatter.string(from: date)
- newString = newString.replacingOccurrences(of: replace, with: dateString)
- }
- }
-
- return newString
- }
|