// // KMPDFConvert.swift // PDF Master // // Created by tangchao on 2022/12/7. // import Cocoa import PDFKit import ComPDFKit_Conversion let KMPDFConvertOptionsKeyImageDPI = "KMPDFConvertOptionsKeyImageDPI" let KMPDFConvertOptionsKeyImageWithAnnotation = "KMPDFConvertOptionsKeyImageWithAnnotation" enum KMPDFConvertType: Int { case word = 0 case excel = 1 case ppt = 2 case rtf = 3 case csv = 4 case html = 5 case text = 6 case jpeg = 7 case jpg = 8 case png = 9 case gif = 10 case tiff = 11 case tga = 12 case bmp = 13 case jp2 = 14 static let image: KMPDFConvertType = .jpeg } typealias KMPDFConvertCallback = (_ finished: Bool, _ error: Error?) -> () typealias KMPDFConvertProgress = (Int) -> () class KMPDFConvert: Operation { var type: Int = 0 var filePath: String = "" var password: String = "" var outputFileName: String = "" var outputFolderPath: String = "" var pages: [Int]! var convertType: KMPDFConvertType = .word var options: [String:Any]! var outputFilePath: String = "" var isSuccessful: Bool = false var isAllInOneSheet: Bool = false var isExtractTable: Bool = false var isExtractText: Bool = false /** 0 支持一个表格提取到单独的工作表 1 支持按页面提取表格到单独的工作表 2 支持将所有表格提取到一个工作表 */ var extractTableIndex: Int = 0 var errorInfo: Error! private var pathExtension: String = "" private var fpPDFConverter: CPDFConverterFP! private var converter: CPDFConverter! private var isCompletion: Bool = false var callback: KMPDFConvertCallback! var progress: KMPDFConvertProgress? public class func pathExtension(_ type: KMPDFConvertType) -> String { return self.pathExtension(type, nil) } public class func pathExtension(_ type: KMPDFConvertType, _ isExtractTable: Bool?) -> String { if type == .word { return "docx" } else if type == .excel { return "xlsx" } else if type == .ppt { return "pptx" } else if type == .rtf { return "rtf" } else if type == .csv { if isExtractTable != nil && isExtractTable! { return "zip" } return "csv" } else if type == .html { return "html" } else if type == .text { return "txt" } else if type == .jpeg { return "jpeg" } else if type == .jpg { return "jpg" } else if type == .png { return "png" } else if type == .gif { return "gif" } else if type == .tga { return "tga" } else if type == .bmp { return "bmp" } else if type == .jp2 { return "jp2" } else if type == .tiff { return "tiff" } return "" } override func start() { if isCancelled { return } var pathExtension = KMPDFConvert.pathExtension(self.convertType, self.isExtractTable) var fileName = outputFileName var path = outputFolderPath if convertType == .jpeg || convertType == .jpg || convertType == .png || convertType == .gif || convertType == .tga || convertType == .bmp || convertType == .jp2 || convertType == .tiff { path.append("/") path.append(fileName) // let folderPath = getUniqueFilePath(filePath: path) try?FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: false) outputFilePath = path } else { if !pathExtension.isEmpty { fileName.append(".") fileName.append(pathExtension) path.append("/") path.append(fileName) // let folderPath = getUniqueFilePath(filePath: path) outputFilePath = path } else { outputFolderPath.append("/") outputFolderPath.append(outputFileName) outputFilePath = outputFolderPath } } self.pathExtension = pathExtension convertWithFPPDFConverter() } func getUniqueFilePath(filePath: String) -> String { var i: Int = 0 var isDirectory: ObjCBool = false var uniqueFilePath = filePath let fileManager = FileManager.default fileManager.fileExists(atPath: uniqueFilePath, isDirectory: &isDirectory) if isDirectory.boolValue { var path: String = "" while fileManager.fileExists(atPath: uniqueFilePath) { i += 1 path = filePath path.append("(\(i))") uniqueFilePath = path } } else { let fileURL = URL(fileURLWithPath: filePath) var path: String = "" while fileManager.fileExists(atPath: uniqueFilePath) { i += 1 path = fileURL.deletingPathExtension().path path.append("(\(i))") path.append(".") path.append(fileURL.pathExtension) uniqueFilePath = path } } return uniqueFilePath } func convertWithFPPDFConverter() { if pathExtension.isEmpty { convertSuccessful(isSuccessful: false, errorInfo: nil) return } if convertType == .word && isAllInOneSheet { converter = CPDFConverterWord(url: URL(fileURLWithPath: filePath), password: self.password) converter.delegate = self converter.convert(toFilePath: outputFilePath, pageIndexs: pages, options: nil) return } if convertType == .excel { converter = CPDFConverterExcel(url: URL(fileURLWithPath: filePath), password: self.password) converter.delegate = self let options = CPDFConvertExcelOptions() if (isExtractText) { options.contentOptions = .onlyText } else if (isExtractTable) { options.contentOptions = .onlyTable if (extractTableIndex == 0) { options.worksheetOptions = .forEachTable } else if (extractTableIndex == 1) { options.worksheetOptions = .forEachPage } else if (extractTableIndex == 2) { options.worksheetOptions = .forTheDocument } } else { options.contentOptions = .allContent if (isAllInOneSheet) { options.worksheetOptions = .forTheDocument } else { options.worksheetOptions = .forEachPage } } converter.convert(toFilePath: outputFilePath, pageIndexs: pages, options: options) return } if (convertType == .ppt) { converter = CPDFConverterPPT(url: URL(fileURLWithPath: filePath), password: self.password) converter.delegate = self converter.convert(toFilePath: outputFilePath, pageIndexs: pages, options: nil) return } if (convertType == .text) { converter = CPDFConverterTxt(url: URL(fileURLWithPath: filePath), password: self.password) converter.delegate = self converter.convert(toFilePath: outputFilePath, pageIndexs: pages, options: nil) return } if convertType == .csv && isExtractTable { converter = CPDFConverterCsv(url: URL(fileURLWithPath: filePath), password: self.password) converter.delegate = self converter.convert(toFilePath: outputFilePath, pageIndexs: pages, options: nil) return } // if (convertType == .jpeg || convertType == .png) { // converter = CPDFConverterImg(url: URL(fileURLWithPath: filePath), password: nil) // converter.delegate = self // let options = CPDFConvertImgOptions() // if (convertType == .jpeg) { // options.type = .JPEG // } else if (convertType == .png) { // options.type = .PNG // } // converter.convert(toFilePath: outputFilePath, pageIndexs: pages, options: options) // return // } fpPDFConverter = CPDFConverterFP() fpPDFConverter.setDelegate(self) var dpi: Int = 0 if self.options != nil { dpi = self.options[KMPDFConvertOptionsKeyImageDPI] as! Int } let options: [String:Any] = [CPDFConvertOptionsKey.imageDPI.rawValue:dpi,CPDFConvertOptionsKey.allInOneSheet.rawValue:isAllInOneSheet] fpPDFConverter.convertPDF(atPath: filePath, pdfPassword: self.password, pdfPageIndexs: pages, destDocType: pathExtension, destDocPath: outputFilePath, moreOptions: options) } func convertSuccessful(isSuccessful: Bool, errorInfo: Error!) { self.isSuccessful = isSuccessful self.errorInfo = errorInfo DispatchQueue.main.async { [self] in guard let callbackBlock = callback else { return } callbackBlock(isSuccessful, errorInfo) } willChangeValue(forKey: "isFinished") isCompletion = true didChangeValue(forKey: "isFinished") } override var isFinished: Bool { return self.isCompletion } } extension KMPDFConvert: CPDFConverterDelegate { func converter(_ converter: CPDFConverter!, didStartConvert error: Error!) { } func converter(_ converter: CPDFConverter!, didEndConvert error: Error!) { if (error != nil) { convertSuccessful(isSuccessful: false, errorInfo: error) } else { convertSuccessful(isSuccessful: true, errorInfo: error) } } func converter(_ converter: CPDFConverter!, pageIndex index: UInt, pageCount count: UInt) { guard let callback = progress else { return } callback(Int(index)) } } extension KMPDFConvert: CPDFConverterFPDelegate { func fppdfConverter(_ converter: Any!, didEndConversion error: Error!) { if (error != nil) { convertSuccessful(isSuccessful: false, errorInfo: error) } else { convertSuccessful(isSuccessful: true, errorInfo: error) } } func fppdfConverter(_ converter: Any!, convertPDFPageIndex pdfPageIndexA: UInt, writeWordPageIndex wordPageIndexA: UInt, finshedWordPageCount wordPageCountA: UInt) { guard let callback = progress else { return } callback(Int(wordPageIndexA)) } }