// // KMBatchConvertOperation.swift // PDF Reader Pro // // Created by liujiajie on 2023/11/28. // import Foundation @objc enum KMConvertWay: Int { case KM = 0 case FP } class KMBatchConvertOperation: KMBatchOperation, CPDFConverterDelegate, CPDFConverterFPDelegate{ lazy var convertWay: KMConvertWay = { let way: KMConvertWay? if self.operateFile?.convertType == .WordStandard { way = .KM } else { way = .FP } return way! }() var fpPDFConverter: CPDFConverterFP? var converter: CPDFConverter? var pdfDocument: CPDFDocument? var isAllInOneSheet: Bool = false // 是否使用OCR var isAllowOCR = false var ocrLanguage: COCRLanguage? deinit { } init(file: KMBatchOperateFile, convertType: KMConvertWithPDFType) { super.init(file: file) self.operateFile?.convertType = convertType self.hasExcuting = false self.hasFinished = false // self.pdfDocument = CPDFDocument(url: URL(fileURLWithPath: file.filePath)) // if ((self.pdfDocument?.isLocked) != nil) { // self.pdfDocument?.unlock(withPassword: file.password) // } } override func start() { if !self.isCancelled { self.pdfDocument = CPDFDocument(url: URL(fileURLWithPath: self.operateFile?.filePath ?? "")) if let data = self.pdfDocument?.isLocked, data { self.pdfDocument?.unlock(withPassword: self.operateFile?.password) } 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")), info: self.operateFile!.removePasswordInfo) 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.")), 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.")), info: self.operateFile!.removeWatermarkInfo) self.willChangeValue(forKey: "isFinished") self.hasFinished = true self.didChangeValue(forKey: "isFinished") return } self.operateFile?.outputFilePath = (self.operateFile?.currentConvertParameter?.fetchDestinationFilepath()) ?? "" if self.operateFile?.currentConvertParameter?.pagesArray?.count ?? 0 < 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.")]) self.delegate?.fileOperateFailed?(self.operateFile!, error: error, info: self.operateFile!.currentConvertParameter!) self.willChangeValue(forKey: "isFinished") self.hasFinished = true self.didChangeValue(forKey: "isFinished") return } if self.operateFile?.convertType == .WordAdvance || self.operateFile?.convertType == .WordStandard { self.converter = CPDFConverterWord.init(url: URL(fileURLWithPath: operateFile?.filePath ?? ""), password: operateFile?.password) self.converter!.delegate = self let options = CPDFConvertWordOptions() options.layoutOptions = self.operateFile?.advanceWordParameter.isRetainLayout ?? false ? .retainPageLayout : .retainFlowingText options.isContainAnnotations = true options.isContainImages = true options.isAllowOCR = self.isAllowOCR if (self.isAllowOCR) { options.isContainOCRBgImage = true options.isAILayoutAnalysis = true if let language = self.ocrLanguage { options.language = language } else { options.language = .english } } else { options.isContainOCRBgImage = false options.isAILayoutAnalysis = false } self.converter!.convert(toFilePath: operateFile!.outputFilePath, pageIndexs: operateFile?.currentConvertParameter?.pagesArray, options: options) return } if self.operateFile?.convertType == .Excel { self.converter = CPDFConverterExcel.init(url: URL(fileURLWithPath: operateFile?.filePath ?? ""), password: operateFile?.password) self.converter!.delegate = self let options = CPDFConvertExcelOptions() options.isContainAnnotations = true options.isContainImages = true // options.isContainOCRBgImage = false options.isAllowOCR = self.isAllowOCR if (self.isAllowOCR) { options.isAILayoutAnalysis = true if let language = self.ocrLanguage { options.language = language } else { options.language = .english } } else { options.isAILayoutAnalysis = false } options.contentOptions = operateFile?.excelParameter.excelContentOption ?? .allContent options.worksheetOptions = operateFile?.excelParameter.excelWorksheetOption ?? .forEachPage self.converter!.convert(toFilePath: operateFile?.outputFilePath, pageIndexs: operateFile?.currentConvertParameter?.pagesArray, options: options) return } if self.operateFile?.convertType == .PowerPoint { self.converter = CPDFConverterPPT.init(url: URL(fileURLWithPath: operateFile?.filePath ?? ""), password: operateFile?.password) self.converter!.delegate = self let options = CPDFConvertPPTOptions() options.isContainAnnotations = true options.isContainImages = true options.isAllowOCR = self.isAllowOCR if (self.isAllowOCR) { options.isContainOCRBgImage = true options.isAILayoutAnalysis = true if let language = self.ocrLanguage { options.language = language } else { options.language = .english } } else { options.isContainOCRBgImage = false options.isAILayoutAnalysis = false } self.converter!.convert(toFilePath: operateFile?.outputFilePath, pageIndexs: operateFile?.currentConvertParameter?.pagesArray, options: options) return } if self.operateFile?.convertType == .CSV && self.operateFile?.CSVParameter.isExtreactTabel ?? false { self.converter = CPDFConverterCsv.init(url: URL(fileURLWithPath: operateFile?.filePath ?? ""), password: operateFile?.password) self.converter!.delegate = self let options = CPDFConvertCsvOptions() self.converter!.convert(toFilePath: operateFile?.outputFilePath, pageIndexs: operateFile?.currentConvertParameter?.pagesArray, options: options) return } if self.operateFile?.convertType == .RTF { self.converter = CPDFConverterRtf.init(url: URL(fileURLWithPath: operateFile?.filePath ?? ""), password: operateFile?.password) self.converter!.delegate = self let options = CPDFConvertRtfOptions() options.isContainAnnotations = true // options.isAllowOCR = true options.isContainImages = true options.isAllowOCR = self.isAllowOCR if (self.isAllowOCR) { options.isContainOCRBgImage = true if let language = self.ocrLanguage { options.language = language } else { options.language = .english } } else { options.isContainOCRBgImage = false } self.converter!.convert(toFilePath: operateFile?.outputFilePath, pageIndexs: operateFile?.currentConvertParameter?.pagesArray, options: options) return } if self.operateFile?.convertType == .HTML { self.converter = CPDFConverterHtml.init(url: URL(fileURLWithPath: operateFile?.filePath ?? ""), password: operateFile?.password) self.converter!.delegate = self let options = CPDFConvertHtmlOptions() options.isContainAnnotations = true options.isContainImages = true options.isAllowOCR = self.isAllowOCR if (self.isAllowOCR) { options.isContainOCRBgImage = true if let language = self.ocrLanguage { options.language = language } else { options.language = .english } } else { options.isContainOCRBgImage = false } self.converter!.convert(toFilePath: operateFile?.outputFilePath, pageIndexs: operateFile?.currentConvertParameter?.pagesArray, options: options) return } if self.operateFile?.convertType == .Text { self.converter = CPDFConverterTxt.init(url: URL(fileURLWithPath: operateFile?.filePath ?? ""), password: operateFile?.password) self.converter!.delegate = self let options = CPDFConvertTxtOptions() options.isAllowOCR = self.isAllowOCR if (self.isAllowOCR) { if let language = self.ocrLanguage { options.language = language } else { options.language = .english } } self.converter!.convert(toFilePath: operateFile?.outputFilePath, pageIndexs: operateFile?.currentConvertParameter?.pagesArray, options: options) return } if self.operateFile?.convertType == .Json { if let data = self.operateFile?.JSONParameter.isExtreactTabel, data { self.converter = CPDFConverterJsonTable(url: URL(fileURLWithPath: operateFile?.filePath ?? ""), password: self.operateFile?.password) } else { self.converter = CPDFConverterJson(url: URL(fileURLWithPath: operateFile?.filePath ?? ""), password: self.operateFile?.password) } self.converter?.delegate = self let options = CPDFConvertJsonOptions() options.isAllowOCR = self.isAllowOCR if (self.isAllowOCR) { if let language = self.ocrLanguage { options.language = language } else { options.language = .english } } else { } self.converter!.convert(toFilePath: operateFile?.outputFilePath, pageIndexs: operateFile?.currentConvertParameter?.pagesArray, options: options) return } let op: [String:Any] = [CPDFConvertOptionsKey.imageDPI.rawValue:operateFile?.dpi as Any,CPDFConvertOptionsKey.allInOneSheet.rawValue:(operateFile?.currentConvertParameter?.allInOneSheet ?? false)] self.fpPDFConverter = CPDFConverterFP() self.fpPDFConverter!.setDelegate(self) self.fpPDFConverter?.convertPDF(atPath: operateFile?.filePath, pdfPassword: operateFile?.password, pdfPageIndexs: operateFile?.currentConvertParameter?.pagesArray, destDocType: operateFile?.currentConvertParameter?.extensionString(), destDocPath: operateFile?.outputFilePath, moreOptions:op) }else { willChangeValue(forKey: "isFinished") willChangeValue(forKey: "isExecuting") hasExcuting = false hasFinished = true didChangeValue(forKey: "isExecuting") didChangeValue(forKey: "isFinished") } } override func cancel() { // super.cancel() if isExecuting { self.fpPDFConverter?.stopConvertsionIfNeed() self.operateFile?.currentConvertParameter?.status = .Waiting if FileManager.default.fileExists(atPath: (operateFile?.currentConvertParameter?.outPutPath)!) { try? FileManager.default.removeItem(atPath: (operateFile!.currentConvertParameter?.outPutPath)!) } self.delegate?.fileOperateCanceled?(self.operateFile!, info: self.operateFile!.currentConvertParameter!) willChangeValue(forKey: "isFinished") hasFinished = true didChangeValue(forKey: "isFinished") } else { willChangeValue(forKey: "isCancelled") hasCanceled = true didChangeValue(forKey: "isCancelled") } } //MARK: FPPDFConverterDelegate func fppdfConverter(_ converter: Any!, didStartConversion error: Error!) { DispatchQueue.main.async { if (error != nil){ self.delegate?.fileOperateFailed?(self.operateFile!, error: error! as NSError, info: (self.operateFile?.currentConvertParameter!)!) }else { self.delegate?.fileBeginOperate?(self.operateFile!, info: (self.operateFile?.currentConvertParameter!)!) } } } func fppdfConverter(_ converter: Any!, didEndConversion error: Error!) { // DispatchQueue.main.async { if (error != nil){ self.delegate?.fileOperateFailed?(self.operateFile!, error: error! as NSError, info: (self.operateFile?.currentConvertParameter!)!) }else { self.delegate?.fileOperateSuccessed?(self.operateFile!, info: (self.operateFile?.currentConvertParameter!)!) } self.fpPDFConverter?.setDelegate(nil) if self.viewController?.view.window?.isVisible == true { willChangeValue(forKey: "isFinished") hasFinished = true didChangeValue(forKey: "isFinished") } // } } func fppdfConverter(_ converter: Any!, pageIndex pageIndexA: UInt, progress: UInt) { } func fppdfConverter(_ converter: Any!, convertPDFPageIndex pdfPageIndexA: UInt, writeWordPageIndex wordPageIndexA: UInt, finshedWordPageCount wordPageCountA: UInt) { let totalPages: Int = self.operateFile?.convertInfo?.pagesArray?.count ?? 0 self.delegate?.fileOperating?(self.operateFile!, progress: CGFloat(wordPageCountA)/CGFloat(totalPages), info: (self.operateFile?.currentConvertParameter!)!) } //MARK: CPDFConverterDelegate func converter(_ converter: CPDFConverter!, didStartConvert error: Error!) { DispatchQueue.main.async { if (error != nil){ self.delegate?.fileOperateFailed?(self.operateFile!, error: error! as NSError, info: (self.operateFile?.currentConvertParameter!)!) }else { self.delegate?.fileBeginOperate?(self.operateFile!, info: (self.operateFile?.currentConvertParameter!)!) } } } func converter(_ converter: CPDFConverter!, pageIndex index: UInt, pageCount count: UInt) { let totalPages: Int = self.operateFile?.convertInfo?.pagesArray?.count ?? 0 self.delegate?.fileOperating?(self.operateFile!, progress: CGFloat(index)/CGFloat(totalPages), info: (self.operateFile?.currentConvertParameter!)!) } func converter(_ converter: CPDFConverter!, didEndConvert error: Error!) { if (error != nil){ var erroeString = "" let err: NSError = error! as NSError switch err.code { case CPDFConverterEncryptError: erroeString = KMLocalizedString("Password required or incorrect password. Please re-enter your password and try again") case CPDFConverterPermissionError: erroeString = KMLocalizedString("The license doesn't allow the permission"); case CPDFConverterMallocError: erroeString = KMLocalizedString("Malloc failure"); case CPDFConverterUnknownError: erroeString = KMLocalizedString("Unknown error in processing conversion. Please try again later"); case CPDFConverterPDFUnknownError: erroeString = KMLocalizedString("Unknown error in processing PDF. Please try again later"); case CPDFConverterPDFFileError: erroeString = KMLocalizedString("File not found or could not be opened. Check if your file exists or choose another file to convert"); case CPDFConverterPDFFormatError: erroeString = KMLocalizedString("File not in PDF format or corruptead. Change a PDF file and try again"); case CPDFConverterPDFSecurityError: erroeString = KMLocalizedString("Unsupported security scheme"); break; case CPDFConverterPDFPageError: erroeString = KMLocalizedString("Page not found or content error"); break; default: erroeString = KMLocalizedString("Table not found"); } let newError = NSError(domain: "", code: err.code, userInfo: [NSLocalizedFailureReasonErrorKey: erroeString]) self.delegate?.fileOperateFailed?(self.operateFile!, error: newError, info: (self.operateFile?.currentConvertParameter!)!) }else { self.delegate?.fileOperateSuccessed?(self.operateFile!, info: (self.operateFile?.currentConvertParameter!)!) } if self.converter != nil && self.converter?.delegate != nil { self.converter?.delegate = nil } if self.viewController?.view.window?.isVisible == true { willChangeValue(forKey: "isFinished") hasFinished = true didChangeValue(forKey: "isFinished") } } }