KMPDFConvert.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. //
  2. // KMPDFConvert.swift
  3. // PDF Master
  4. //
  5. // Created by tangchao on 2022/12/7.
  6. //
  7. import Cocoa
  8. import PDFKit
  9. import ComPDFKit_Conversion
  10. let KMPDFConvertOptionsKeyImageDPI = "KMPDFConvertOptionsKeyImageDPI"
  11. let KMPDFConvertOptionsKeyImageWithAnnotation = "KMPDFConvertOptionsKeyImageWithAnnotation"
  12. enum KMPDFConvertType: Int {
  13. case word = 0
  14. case excel = 1
  15. case ppt = 2
  16. case rtf = 3
  17. case csv = 4
  18. case html = 5
  19. case text = 6
  20. case jpeg = 7
  21. case jpg = 8
  22. case png = 9
  23. case gif = 10
  24. case tiff = 11
  25. case tga = 12
  26. case bmp = 13
  27. case jp2 = 14
  28. static let image: KMPDFConvertType = .jpeg
  29. }
  30. typealias KMPDFConvertCallback = (_ finished: Bool, _ error: Error?) -> ()
  31. typealias KMPDFConvertProgress = (Int) -> ()
  32. class KMPDFConvert: Operation {
  33. var type: Int = 0
  34. var filePath: String = ""
  35. var password: String = ""
  36. var outputFileName: String = ""
  37. var outputFolderPath: String = ""
  38. var pages: [Int]!
  39. var convertType: KMPDFConvertType = .word
  40. var options: [String:Any]!
  41. var outputFilePath: String = ""
  42. var isSuccessful: Bool = false
  43. var isAllInOneSheet: Bool = false
  44. var isExtractTable: Bool = false
  45. var isExtractText: Bool = false
  46. /**
  47. 0 支持一个表格提取到单独的工作表
  48. 1 支持按页面提取表格到单独的工作表
  49. 2 支持将所有表格提取到一个工作表
  50. */
  51. var extractTableIndex: Int = 0
  52. var errorInfo: Error!
  53. private var pathExtension: String = ""
  54. private var fpPDFConverter: CPDFConverterFP!
  55. private var converter: CPDFConverter!
  56. private var isCompletion: Bool = false
  57. var callback: KMPDFConvertCallback!
  58. var progress: KMPDFConvertProgress?
  59. public class func pathExtension(_ type: KMPDFConvertType) -> String {
  60. return self.pathExtension(type, nil)
  61. }
  62. public class func pathExtension(_ type: KMPDFConvertType, _ isExtractTable: Bool?) -> String {
  63. if type == .word {
  64. return "docx"
  65. } else if type == .excel {
  66. return "xlsx"
  67. } else if type == .ppt {
  68. return "pptx"
  69. } else if type == .rtf {
  70. return "rtf"
  71. } else if type == .csv {
  72. if isExtractTable != nil && isExtractTable! {
  73. return "zip"
  74. }
  75. return "csv"
  76. } else if type == .html {
  77. return "html"
  78. } else if type == .text {
  79. return "txt"
  80. } else if type == .jpeg {
  81. return "jpeg"
  82. } else if type == .jpg {
  83. return "jpg"
  84. } else if type == .png {
  85. return "png"
  86. } else if type == .gif {
  87. return "gif"
  88. } else if type == .tga {
  89. return "tga"
  90. } else if type == .bmp {
  91. return "bmp"
  92. } else if type == .jp2 {
  93. return "jp2"
  94. } else if type == .tiff {
  95. return "tiff"
  96. }
  97. return ""
  98. }
  99. override func start() {
  100. if isCancelled {
  101. return
  102. }
  103. var pathExtension = KMPDFConvert.pathExtension(self.convertType, self.isExtractTable)
  104. var fileName = outputFileName
  105. var path = outputFolderPath
  106. if convertType == .jpeg || convertType == .jpg || convertType == .png || convertType == .gif || convertType == .tga || convertType == .bmp || convertType == .jp2 || convertType == .tiff {
  107. path.append("/")
  108. path.append(fileName)
  109. // let folderPath = getUniqueFilePath(filePath: path)
  110. try?FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: false)
  111. outputFilePath = path
  112. } else {
  113. if !pathExtension.isEmpty {
  114. fileName.append(".")
  115. fileName.append(pathExtension)
  116. path.append("/")
  117. path.append(fileName)
  118. // let folderPath = getUniqueFilePath(filePath: path)
  119. outputFilePath = path
  120. } else {
  121. outputFolderPath.append("/")
  122. outputFolderPath.append(outputFileName)
  123. outputFilePath = outputFolderPath
  124. }
  125. }
  126. self.pathExtension = pathExtension
  127. convertWithFPPDFConverter()
  128. }
  129. func getUniqueFilePath(filePath: String) -> String {
  130. var i: Int = 0
  131. var isDirectory: ObjCBool = false
  132. var uniqueFilePath = filePath
  133. let fileManager = FileManager.default
  134. fileManager.fileExists(atPath: uniqueFilePath, isDirectory: &isDirectory)
  135. if isDirectory.boolValue {
  136. var path: String = ""
  137. while fileManager.fileExists(atPath: uniqueFilePath) {
  138. i += 1
  139. path = filePath
  140. path.append("(\(i))")
  141. uniqueFilePath = path
  142. }
  143. } else {
  144. let fileURL = URL(fileURLWithPath: filePath)
  145. var path: String = ""
  146. while fileManager.fileExists(atPath: uniqueFilePath) {
  147. i += 1
  148. path = fileURL.deletingPathExtension().path
  149. path.append("(\(i))")
  150. path.append(".")
  151. path.append(fileURL.pathExtension)
  152. uniqueFilePath = path
  153. }
  154. }
  155. return uniqueFilePath
  156. }
  157. func convertWithFPPDFConverter() {
  158. if pathExtension.isEmpty {
  159. convertSuccessful(isSuccessful: false, errorInfo: nil)
  160. return
  161. }
  162. if convertType == .word && isAllInOneSheet {
  163. converter = CPDFConverterWord(url: URL(fileURLWithPath: filePath), password: self.password)
  164. converter.delegate = self
  165. converter.convert(toFilePath: outputFilePath, pageIndexs: pages, options: nil)
  166. return
  167. }
  168. if convertType == .excel {
  169. converter = CPDFConverterExcel(url: URL(fileURLWithPath: filePath), password: self.password)
  170. converter.delegate = self
  171. let options = CPDFConvertExcelOptions()
  172. if (isExtractText) {
  173. options.contentOptions = .onlyText
  174. } else if (isExtractTable) {
  175. options.contentOptions = .onlyTable
  176. if (extractTableIndex == 0) {
  177. options.worksheetOptions = .forEachTable
  178. } else if (extractTableIndex == 1) {
  179. options.worksheetOptions = .forEachPage
  180. } else if (extractTableIndex == 2) {
  181. options.worksheetOptions = .forTheDocument
  182. }
  183. } else {
  184. options.contentOptions = .allContent
  185. if (isAllInOneSheet) {
  186. options.worksheetOptions = .forTheDocument
  187. } else {
  188. options.worksheetOptions = .forEachPage
  189. }
  190. }
  191. converter.convert(toFilePath: outputFilePath, pageIndexs: pages, options: options)
  192. return
  193. }
  194. if (convertType == .ppt) {
  195. converter = CPDFConverterPPT(url: URL(fileURLWithPath: filePath), password: self.password)
  196. converter.delegate = self
  197. converter.convert(toFilePath: outputFilePath, pageIndexs: pages, options: nil)
  198. return
  199. }
  200. if (convertType == .text) {
  201. converter = CPDFConverterTxt(url: URL(fileURLWithPath: filePath), password: self.password)
  202. converter.delegate = self
  203. converter.convert(toFilePath: outputFilePath, pageIndexs: pages, options: nil)
  204. return
  205. }
  206. if convertType == .csv && isExtractTable {
  207. converter = CPDFConverterCsv(url: URL(fileURLWithPath: filePath), password: self.password)
  208. converter.delegate = self
  209. converter.convert(toFilePath: outputFilePath, pageIndexs: pages, options: nil)
  210. return
  211. }
  212. // if (convertType == .jpeg || convertType == .png) {
  213. // converter = CPDFConverterImg(url: URL(fileURLWithPath: filePath), password: nil)
  214. // converter.delegate = self
  215. // let options = CPDFConvertImgOptions()
  216. // if (convertType == .jpeg) {
  217. // options.type = .JPEG
  218. // } else if (convertType == .png) {
  219. // options.type = .PNG
  220. // }
  221. // converter.convert(toFilePath: outputFilePath, pageIndexs: pages, options: options)
  222. // return
  223. // }
  224. fpPDFConverter = CPDFConverterFP()
  225. fpPDFConverter.setDelegate(self)
  226. var dpi: Int = 0
  227. if self.options != nil {
  228. dpi = self.options[KMPDFConvertOptionsKeyImageDPI] as! Int
  229. }
  230. let options: [String:Any] = [CPDFConvertOptionsKey.imageDPI.rawValue:dpi,CPDFConvertOptionsKey.allInOneSheet.rawValue:isAllInOneSheet]
  231. fpPDFConverter.convertPDF(atPath: filePath, pdfPassword: self.password, pdfPageIndexs: pages, destDocType: pathExtension, destDocPath: outputFilePath, moreOptions: options)
  232. }
  233. func convertSuccessful(isSuccessful: Bool, errorInfo: Error!) {
  234. self.isSuccessful = isSuccessful
  235. self.errorInfo = errorInfo
  236. DispatchQueue.main.async { [self] in
  237. guard let callbackBlock = callback else {
  238. return
  239. }
  240. callbackBlock(isSuccessful, errorInfo)
  241. }
  242. willChangeValue(forKey: "isFinished")
  243. isCompletion = true
  244. didChangeValue(forKey: "isFinished")
  245. }
  246. override var isFinished: Bool {
  247. return self.isCompletion
  248. }
  249. }
  250. extension KMPDFConvert: CPDFConverterDelegate {
  251. func converter(_ converter: CPDFConverter!, didStartConvert error: Error!) {
  252. }
  253. func converter(_ converter: CPDFConverter!, didEndConvert error: Error!) {
  254. if (error != nil) {
  255. convertSuccessful(isSuccessful: false, errorInfo: error)
  256. } else {
  257. convertSuccessful(isSuccessful: true, errorInfo: error)
  258. }
  259. }
  260. func converter(_ converter: CPDFConverter!, pageIndex index: UInt, pageCount count: UInt) {
  261. guard let callback = progress else {
  262. return
  263. }
  264. callback(Int(index))
  265. }
  266. }
  267. extension KMPDFConvert: CPDFConverterFPDelegate {
  268. func fppdfConverter(_ converter: Any!, didEndConversion error: Error!) {
  269. if (error != nil) {
  270. convertSuccessful(isSuccessful: false, errorInfo: error)
  271. } else {
  272. convertSuccessful(isSuccessful: true, errorInfo: error)
  273. }
  274. }
  275. func fppdfConverter(_ converter: Any!, convertPDFPageIndex pdfPageIndexA: UInt, writeWordPageIndex wordPageIndexA: UInt, finshedWordPageCount wordPageCountA: UInt) {
  276. guard let callback = progress else {
  277. return
  278. }
  279. callback(Int(wordPageIndexA))
  280. }
  281. }