KMBatchManager.swift 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. //
  2. // KMBatchManager.swift
  3. // PDF Master
  4. //
  5. // Created by lizhe on 2023/2/17.
  6. //
  7. import Cocoa
  8. enum KMBatchManagerSate: Int, CaseIterable {
  9. case unknow = 0
  10. case processing
  11. case complete
  12. case error
  13. }
  14. let kBacthFilesProcessNotification = "kBacthFilesProcessNotification"
  15. let kBacthProcessNotification = "kBacthProcessNotification"
  16. class KMBatchManager: NSObject {
  17. public static let manager = KMBatchManager()
  18. fileprivate(set) var state: KMBatchManagerSate = .unknow
  19. var filesData: [KMBatchProcessingTableViewModel] = []
  20. var batchFilesData: [KMBatchProcessingTableViewModel] {
  21. get {
  22. var resultArray:[KMBatchProcessingTableViewModel] = []
  23. for item in filesData {
  24. if !item.isLock {
  25. resultArray.append(item)
  26. }
  27. }
  28. return resultArray
  29. }
  30. }
  31. func batch(type: KMBatchCollectionViewType, data: KMBatchSettingItemViewModel) {
  32. let panel = NSOpenPanel()
  33. panel.canChooseFiles = false
  34. panel.canChooseDirectories = true
  35. panel.canCreateDirectories = true
  36. panel.beginSheetModal(for: NSWindow.currentWindow()) { response in
  37. if response == .cancel {
  38. return
  39. }
  40. let outputFolderPath = (panel.url?.path)!
  41. //
  42. self.batchUnkown()
  43. switch type {
  44. case .convertPDF:
  45. self.convertPDFExport(data: data, outputFolderPath: outputFolderPath)
  46. break
  47. case .OCR:
  48. self.convertOCRExport(data: data, outputFolderPath: outputFolderPath)
  49. break
  50. case .compress:
  51. self.compressExport(data: data, outputFolderPath: outputFolderPath)
  52. break
  53. case .security:
  54. self.securityExport(data: data, outputFolderPath: outputFolderPath)
  55. break
  56. case .watermark:
  57. self.waterMarkApplay(data: data, outputFolderPath: outputFolderPath)
  58. break
  59. case .background:
  60. self.backgroundApplay(data: data, outputFolderPath: outputFolderPath)
  61. break
  62. case .headerAndFooter:
  63. self.headAndFooterApplay(data: data, outputFolderPath: outputFolderPath)
  64. break
  65. case .batesNumber:
  66. self.batesApplay(data: data, outputFolderPath: outputFolderPath)
  67. break
  68. case .batchRemove:
  69. self.removeApplay(data: data, outputFolderPath: outputFolderPath)
  70. break
  71. case .imageToPDF:
  72. self.imageToPDFExport(data: data, outputFolderPath: outputFolderPath)
  73. break
  74. default:
  75. KMPrint("找不到")
  76. break
  77. }
  78. //
  79. self.batchProgress()
  80. }
  81. }
  82. }
  83. //MARK: 批量
  84. extension KMBatchManager {
  85. //MARK: 转档
  86. func convertPDFExport(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  87. self.convertFile(outputFolderPath: outputFolderPath, data: data, filesData: self.batchFilesData)
  88. }
  89. func convertFile(outputFolderPath: String, data: KMBatchSettingItemViewModel, filesData: [KMBatchProcessingTableViewModel]) {
  90. if filesData.count != 0 {
  91. DispatchQueue.global().async {
  92. for i in 0..<filesData.count {
  93. let item = filesData[i]
  94. //创建Document
  95. let filePath = item.filePath
  96. let document = self.fetchDocument(filePath: filePath, model: item)
  97. let settingData = data as? KMBatchConvertPDFViewModel ?? KMBatchConvertPDFViewModel()
  98. var fileName = filePath.deletingPathExtension.lastPathComponent
  99. if ((fileName.isEmpty)) {
  100. fileName = NSLocalizedString("Untitled", comment: "")
  101. }
  102. let convert = self.addConvertParameter(settingData)
  103. let pageCount = document.pageCount
  104. //获取page
  105. var pages:[Int] = []
  106. for i in 0..<pageCount {
  107. pages.append(Int(i)+1)
  108. }
  109. convert.outputFolderPath = outputFolderPath
  110. convert.filePath = filePath
  111. convert.outputFileName = fileName
  112. convert.pages = pages
  113. convert.isAllowOCR = settingData.needRecognizeText
  114. convert.ocrLanguage = settingData.languageType
  115. item.state = .clock
  116. KMPDFConvertManager.defaultManager.convert(convert: convert, progress: { [unowned self] progressValue in
  117. print("转档进度 - \(progressValue)")
  118. let progress = Float(progressValue) / Float(pageCount)
  119. self.itemProgress(item: item, processValue: progress)
  120. }, completion: { [unowned self] finished, error in
  121. if finished {
  122. if FileManager.default.fileExists(atPath: outputFolderPath) {
  123. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)])
  124. }
  125. self.itemSuccess(item: item)
  126. } else {
  127. self.itemFailure(item: item, error: error! as NSError)
  128. }
  129. if i == filesData.count - 1 {
  130. self.batchSuccess()
  131. }
  132. })
  133. }
  134. }
  135. }
  136. }
  137. func addConvertParameter(_ data: KMBatchConvertPDFViewModel) -> KMPDFConvert {
  138. let settingData = data
  139. var convert = KMPDFConvert()
  140. switch settingData.convertPDFType {
  141. case .word:
  142. convert = KMPDFConvertWord()
  143. if settingData.layoutSettingType == .flowingText {
  144. convert.isAllInOneSheet = false
  145. } else {
  146. convert.isAllInOneSheet = true
  147. }
  148. case .excel:
  149. convert = KMPDFConvertExcel()
  150. if settingData.excelSetting == .separate {
  151. convert.isAllInOneSheet = false
  152. convert.isExtractTable = false
  153. } else if settingData.excelSetting == .format {
  154. convert.isAllInOneSheet = true
  155. convert.isExtractTable = false
  156. } else if settingData.excelSetting == .tables {
  157. convert.isAllInOneSheet = false
  158. convert.isExtractTable = true
  159. switch settingData.excelTablesType {
  160. case .oneTable:
  161. convert.extractTableIndex = 0
  162. case .pageTable:
  163. convert.extractTableIndex = 1
  164. case .allTable:
  165. convert.extractTableIndex = 2
  166. default:
  167. KMPrint("未找到")
  168. }
  169. }
  170. case .ppt:
  171. convert = KMPDFConvertPPT()
  172. case .csv:
  173. convert = KMPDFConvertCSV()
  174. if settingData.csvOnlyTables {
  175. convert.isExtractTable = true
  176. switch settingData.excelTablesType {
  177. case .oneTable:
  178. convert.extractTableIndex = 0
  179. case .pageTable:
  180. convert.extractTableIndex = 1
  181. case .allTable:
  182. convert.extractTableIndex = 2
  183. default:
  184. KMPrint("未找到")
  185. }
  186. } else {
  187. convert.isExtractTable = false
  188. }
  189. case .image:
  190. convert = KMPDFConvertImage()
  191. convert.convertType = data.imageType
  192. var dpi: Int = 150
  193. if data.imageDpiIndex == 0 {
  194. dpi = 50
  195. } else if data.imageDpiIndex == 1 {
  196. dpi = 72
  197. } else if data.imageDpiIndex == 2 {
  198. dpi = 96
  199. } else if data.imageDpiIndex == 3 {
  200. dpi = 150
  201. } else if data.imageDpiIndex == 4 {
  202. dpi = 300
  203. } else if data.imageDpiIndex == 5 {
  204. dpi = 600
  205. } else {
  206. dpi = 150
  207. }
  208. if (convert.convertType == .jpeg) {
  209. (convert as! KMPDFConvertImage).imageType = .JPEG
  210. (convert as! KMPDFConvertImage).imageDpi = dpi
  211. } else if (convert.convertType == .png) {
  212. (convert as! KMPDFConvertImage).imageType = .PNG
  213. (convert as! KMPDFConvertImage).imageDpi = dpi
  214. } else {
  215. (convert as! KMPDFConvertImage).imageDpi = 150
  216. }
  217. case .html:
  218. convert = KMPDFConvertHTML()
  219. case .rtf:
  220. convert = KMPDFConvertRTF()
  221. case .json:
  222. convert = KMPDFConvertJson()
  223. if settingData.jsonType == .extractText {
  224. convert.isAllInOneSheet = false
  225. } else {
  226. convert.isAllInOneSheet = true
  227. }
  228. case .text:
  229. convert = KMPDFConvertText()
  230. default:
  231. KMPrint("不清楚")
  232. }
  233. return convert
  234. }
  235. //MARK: OCR
  236. func convertOCRExport(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  237. self.convertOCR(outputFolderPath: outputFolderPath, data: data as! KMOCRModel, filesData: self.batchFilesData)
  238. }
  239. func convertOCR(outputFolderPath: String, data: KMOCRModel, filesData: [KMBatchProcessingTableViewModel]?) {
  240. guard let filesData = filesData else { return }
  241. for i in 0..<filesData.count {
  242. let item = (filesData[i])
  243. let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  244. if document != nil {
  245. //计算需要处理的页面
  246. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  247. if ((fileName.isEmpty)) {
  248. fileName = NSLocalizedString("Untitled", comment: "")
  249. }
  250. let path = outputFolderPath + "/" + fileName + ".pdf"
  251. self.convertOCR(outputFolderPath: outputFolderPath, document: document!, fileName: fileName, data: data) { [unowned self] progress in
  252. self.itemProgress(item: item, processValue: progress)
  253. } complete: { [unowned self] document, text, error in
  254. if error == nil {
  255. self.itemSuccess(item: item)
  256. } else {
  257. self.itemFailure(item: item, error: error! as NSError)
  258. }
  259. if i == filesData.count - 1 {
  260. self.batchSuccess()
  261. }
  262. }
  263. }
  264. }
  265. }
  266. func convertOCR(outputFolderPath: String,
  267. document: CPDFDocument,
  268. fileName: String,
  269. data: KMOCRModel,
  270. progress: @escaping KMOCRManagerOCRProgress,
  271. complete: @escaping KMOCRManagerOCRComplete) {
  272. //计算需要处理的页面
  273. let path = outputFolderPath + "/" + fileName + ".pdf"
  274. KMOCRManager.manager.convertBatchOCR(document: document, saveFilePath: path, model: data, progress: { [unowned self] progressValue in
  275. progress(progressValue)
  276. }) { [unowned self] document, text, error in
  277. complete(document, text, error)
  278. }
  279. }
  280. //MARK: 压缩
  281. func compressExport(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  282. self.compressFile(outputFolderPath: outputFolderPath, data: (data as? KMCompressSettingModel)!, filesData: self.batchFilesData)
  283. }
  284. func compressFile(outputFolderPath: String, data: KMCompressSettingModel, filesData: [KMBatchProcessingTableViewModel]) {
  285. if filesData.count != 0 {
  286. for i in 0..<filesData.count {
  287. let item = filesData[i]
  288. let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  289. if document != nil {
  290. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  291. if ((fileName.isEmpty)) {
  292. fileName = NSLocalizedString("Untitled", comment: "")
  293. }
  294. let path = outputFolderPath + "/" + fileName + ".pdf"
  295. KMCompressManager.shared.compress(documentURL: URL(fileURLWithPath: item.filePath), fileURL: URL(fileURLWithPath: path), limit: false, model: data) { currentPage, totalPages in
  296. let progress = Float(currentPage) / Float(totalPages)
  297. self.itemProgress(item: item, processValue: progress)
  298. } cancelHandler: {
  299. return false
  300. } completionHandler: { [unowned self] isFinish in
  301. if isFinish {
  302. self.itemSuccess(item: item)
  303. } else {
  304. self.itemFailure(item: item, error: nil)
  305. }
  306. if i == filesData.count - 1 {
  307. self.batchSuccess()
  308. }
  309. }
  310. }
  311. }
  312. }
  313. }
  314. //MARK: 安全
  315. func securityExport(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  316. self.securityFile(outputFolderPath: outputFolderPath, data: data as! KMBatchSecurityViewModel, filesData: self.batchFilesData)
  317. }
  318. func securityFile(outputFolderPath: String, data: KMBatchSecurityViewModel, filesData: [KMBatchProcessingTableViewModel]) {
  319. if filesData.count != 0 {
  320. for i in 0..<filesData.count {
  321. let item = filesData[i]
  322. let docuemt = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  323. if (docuemt != nil) {
  324. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  325. if ((fileName.isEmpty)) {
  326. fileName = NSLocalizedString("Untitled", comment: "")
  327. }
  328. let path = outputFolderPath + "/" + fileName + ".pdf"
  329. var options: [CPDFDocumentWriteOption : Any] = [:]
  330. //开启密码
  331. if data.isOpenPassword &&
  332. !data.openPasswordString.isEmpty {
  333. options.updateValue(data.openPasswordString, forKey: .userPasswordOption)
  334. }
  335. //
  336. //权限密码
  337. if data.isPermission &&
  338. !data.permissionString.isEmpty {
  339. options.updateValue(data.permissionString, forKey: .ownerPasswordOption)
  340. }
  341. // 限制打印
  342. if data.restrictOptions.contains(.print) {
  343. options.updateValue(false, forKey: .allowsPrintingOption)
  344. } else {
  345. options.updateValue(true, forKey: .allowsPrintingOption)
  346. }
  347. //限制复制
  348. if data.restrictOptions.contains(.copy) {
  349. options.updateValue(false, forKey: .allowsCopyingOption)
  350. } else {
  351. options.updateValue(true, forKey: .allowsCopyingOption)
  352. }
  353. let result = docuemt!.write(toFile: path, withOptions: options)
  354. // let result = docuemt!.write(to: URL(fileURLWithPath: path), withOptions: options)
  355. if result {
  356. KMPrint("成功")
  357. self.itemSuccess(item: item)
  358. } else {
  359. KMPrint("失败")
  360. self.itemFailure(item: item, error: nil)
  361. }
  362. if i == filesData.count - 1 {
  363. self.batchSuccess()
  364. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)])
  365. }
  366. }
  367. }
  368. }
  369. }
  370. //MARK: 水印
  371. func waterMarkApplay(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  372. }
  373. func waterMarkFile(outputFolderPath: String, data: KMBatchSettingItemViewModel, filesData: [KMBatchProcessingTableViewModel]?) {
  374. }
  375. //MARK: 背景
  376. func backgroundApplay(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  377. if let data = data as? KMBatchBackgroundModel {
  378. self.backgroundFile(outputFolderPath: outputFolderPath, data: data, filesData: self.batchFilesData)
  379. }
  380. }
  381. func backgroundFile(outputFolderPath: String, data: KMBatchBackgroundModel, filesData: [KMBatchProcessingTableViewModel]) {
  382. if filesData.count != 0 {
  383. for i in 0..<filesData.count {
  384. let item = filesData[i]
  385. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  386. if ((fileName.isEmpty)) {
  387. fileName = NSLocalizedString("Untitled", comment: "")
  388. }
  389. let path = outputFolderPath + "/" + fileName + ".pdf"
  390. let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  391. if (document?.allowsPrinting == false || document?.allowsCopying == false) {
  392. let alert = NSAlert()
  393. alert.alertStyle = .critical
  394. alert.messageText = "此文档不允许修改"
  395. alert.runModal()
  396. return
  397. }
  398. if let background = document?.background(), let model = data.backgroundModel, let document = document {
  399. KMBackgroundManager.defaultManager.updateBackground(background, withModel: model)
  400. let pageIndexString = self.fetchValidPageIndexString(document, model: item)
  401. background.pageString = pageIndexString
  402. background.update()
  403. }
  404. if (FileManager.default.fileExists(atPath: path)) {
  405. try?FileManager.default.removeItem(atPath: path)
  406. }
  407. let result = document?.write(to: URL(fileURLWithPath: path)) ?? false
  408. if (result) {
  409. KMPrint("removeFile成功")
  410. self.itemSuccess(item: item)
  411. } else {
  412. KMPrint("removeFile失败")
  413. self.itemFailure(item: item, error: nil)
  414. }
  415. if i == filesData.count - 1 {
  416. self.batchSuccess()
  417. }
  418. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: path)])
  419. }
  420. }
  421. }
  422. //MARK: 页眉页脚
  423. func headAndFooterApplay(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  424. if let data = data as? KMBatchHeaderAndFooterModel {
  425. self.headAndFooterFile(outputFolderPath: outputFolderPath, data: data, filesData: self.batchFilesData)
  426. }
  427. }
  428. func headAndFooterFile(outputFolderPath: String, data: KMBatchHeaderAndFooterModel, filesData: [KMBatchProcessingTableViewModel]) {
  429. if filesData.count != 0 {
  430. for i in 0..<filesData.count {
  431. let item = filesData[i]
  432. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  433. if ((fileName.isEmpty)) {
  434. fileName = NSLocalizedString("Untitled", comment: "")
  435. }
  436. let path = outputFolderPath + "/" + fileName + ".pdf"
  437. let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  438. if (document?.allowsPrinting == false || document?.allowsCopying == false) {
  439. let alert = NSAlert()
  440. alert.alertStyle = .critical
  441. alert.messageText = "此文档不允许修改"
  442. alert.runModal()
  443. return
  444. }
  445. if let headerFooter = document?.headerFooter(), let model = data.headerFooterModel, let document = document {
  446. let pageString = self.fetchValidPageIndexString(document, model: item)
  447. KMHeaderFooterManager.defaultManager.updateCPDFHeaderFooter(headerFooter, withModel: model, Int(document.pageCount))
  448. headerFooter.pageString = pageString
  449. headerFooter.update()
  450. }
  451. if (FileManager.default.fileExists(atPath: path)) {
  452. try?FileManager.default.removeItem(atPath: path)
  453. }
  454. let result = document?.write(to: URL(fileURLWithPath: path)) ?? false
  455. if (result) {
  456. KMPrint("removeFile成功")
  457. self.itemSuccess(item: item)
  458. } else {
  459. KMPrint("removeFile失败")
  460. self.itemFailure(item: item, error: nil)
  461. }
  462. if i == filesData.count - 1 {
  463. self.batchSuccess()
  464. }
  465. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: path)])
  466. }
  467. }
  468. }
  469. //MARK: 贝茨码
  470. func batesApplay(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  471. }
  472. func batesFile(outputFolderPath: String, data: KMBatchSettingItemViewModel, filesData: [KMBatchProcessingTableViewModel]?) {
  473. }
  474. //MARK: 移除
  475. func removeApplay(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  476. self.removeFile(outputFolderPath: outputFolderPath, data: data as! KMBatchRemoveViewModel, filesData: self.batchFilesData)
  477. }
  478. func removeFile(outputFolderPath: String, data: KMBatchRemoveViewModel, filesData: [KMBatchProcessingTableViewModel]) {
  479. if filesData.count != 0 {
  480. for i in 0..<filesData.count {
  481. let item = filesData[i]
  482. // DispatchQueue.global().async {
  483. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  484. if ((fileName.isEmpty)) {
  485. fileName = NSLocalizedString("Untitled", comment: "")
  486. }
  487. let path = outputFolderPath + "/" + fileName + ".pdf"
  488. let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  489. if document != nil {
  490. if (document!.allowsPrinting == false || document!.allowsCopying == false) {
  491. let alert = NSAlert()
  492. alert.alertStyle = .critical
  493. alert.messageText = "此文档不允许修改"
  494. alert.runModal()
  495. return
  496. }
  497. if (data.options.contains(.security)) {
  498. }
  499. if (data.options.contains(.batesNumber)) {
  500. let property = document!.bates()
  501. property?.clear()
  502. }
  503. if (data.options.contains(.headerAndFooter)) {
  504. let property = document!.headerFooter()
  505. property?.clear()
  506. }
  507. if (data.options.contains(.background)) {
  508. let property = document!.background()
  509. property?.clear()
  510. }
  511. if (data.options.contains(.watermark)) {
  512. let array: Array<CPDFWatermark> = document!.watermarks() ?? []
  513. for model in array {
  514. document!.removeWatermark(model)
  515. }
  516. }
  517. if (FileManager.default.fileExists(atPath: path)) {
  518. try?FileManager.default.removeItem(atPath: path)
  519. }
  520. let result = document!.write(to: URL(fileURLWithPath: path))
  521. if (result) {
  522. KMPrint("removeFile成功")
  523. self.itemSuccess(item: item)
  524. } else {
  525. KMPrint("removeFile失败")
  526. self.itemFailure(item: item, error: nil)
  527. }
  528. if i == filesData.count - 1 {
  529. self.batchSuccess()
  530. }
  531. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)])
  532. }
  533. // }
  534. }
  535. }
  536. }
  537. //MARK: 图片转PDF
  538. func imageToPDFExport(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  539. self.imageToPDFFile(outputFolderPath: outputFolderPath, data: data as! KMBatchImageToPDFModel, filesData: self.batchFilesData)
  540. }
  541. func imageToPDFFile(outputFolderPath: String, data: KMBatchImageToPDFModel, filesData: [KMBatchProcessingTableViewModel]) {
  542. if filesData.count != 0 {
  543. self.batchProgress()
  544. if data.isNewPDF {
  545. if data.isMergeAll {
  546. let item = filesData[0]
  547. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  548. let path = outputFolderPath + "/" + fileName + ".pdf"
  549. var pdfDocument = CPDFDocument()
  550. for item in filesData {
  551. pdfDocument?.km_insert(image: item.image, at: pdfDocument?.pageCount ?? 0)
  552. }
  553. if data.isOCR {
  554. let model = KMOCRModel()
  555. model.showType = .page
  556. model.saveAsPDF = true
  557. model.ocrType = data.ocrType
  558. model.languageType = data.languageType
  559. model.needTxT = data.isExtractText
  560. model.pageRangeType = .all
  561. //计算需要处理的页面
  562. let pages:[Int] = KMOCRManager.fetchPageIndex(document: pdfDocument!, model: model)
  563. model.pageRange = pages
  564. self.batchProgress()
  565. self.convertOCR(outputFolderPath: outputFolderPath, document: pdfDocument!, fileName: fileName, data: model) { progress in
  566. self.batchProgress()
  567. } complete: { document, text, error in
  568. self.batchSuccess()
  569. }
  570. } else {
  571. pdfDocument?.write(toFile: path)
  572. }
  573. self.batchSuccess()
  574. } else {
  575. for i in 0..<filesData.count {
  576. let item = filesData[i]
  577. if data.isOCR {
  578. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  579. let path = outputFolderPath + "/" + fileName + ".pdf"
  580. var pdfDocument = CPDFDocument()
  581. for item in filesData {
  582. pdfDocument?.km_insert(image: item.image, at: pdfDocument?.pageCount ?? 0)
  583. }
  584. let model = KMOCRModel()
  585. model.showType = .page
  586. model.saveAsPDF = true
  587. model.ocrType = data.ocrType
  588. model.languageType = data.languageType
  589. model.needTxT = data.isExtractText
  590. model.pageRangeType = .all
  591. //计算需要处理的页面
  592. let pages:[Int] = KMOCRManager.fetchPageIndex(document: pdfDocument!, model: model)
  593. model.pageRange = pages
  594. self.itemProgress(item: item, processValue: 0)
  595. self.convertOCR(outputFolderPath: outputFolderPath, document: pdfDocument!, fileName: fileName, data: model) { [unowned self] progress in
  596. self.itemProgress(item: item, processValue: progress)
  597. } complete: { [unowned self] document, text, error in
  598. self.itemSuccess(item: item)
  599. if i == filesData.count - 1 {
  600. self.batchSuccess()
  601. }
  602. }
  603. } else {
  604. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  605. let path = outputFolderPath + "/" + fileName + ".pdf"
  606. var pdfDocument = CPDFDocument()
  607. pdfDocument?.km_insert(image: item.image, at: pdfDocument?.pageCount ?? 0)
  608. let success = pdfDocument?.write(toFile: path)
  609. if success != nil {
  610. self.batchSuccess()
  611. } else {
  612. self.batchFailure()
  613. }
  614. }
  615. }
  616. }
  617. } else {
  618. var fileName = data.selectFilePath.deletingPathExtension.lastPathComponent
  619. let path = outputFolderPath + "/" + fileName + ".pdf"
  620. var pdfDocument = CPDFDocument(url: NSURL(fileURLWithPath: data.selectFilePath) as URL)
  621. let count: Int = Int(pdfDocument?.pageCount ?? 0)
  622. for item in filesData {
  623. pdfDocument?.km_insert(image: item.image, at: pdfDocument?.pageCount ?? 0)
  624. }
  625. if data.isOCR {
  626. let model = KMOCRModel()
  627. model.showType = .page
  628. model.saveAsPDF = true
  629. model.ocrType = data.ocrType
  630. model.languageType = data.languageType
  631. model.needTxT = data.isExtractText
  632. model.pageRangeType = .all
  633. //计算需要处理的页面
  634. let pages:[Int] = KMOCRManager.fetchPageIndex(document: pdfDocument!, model: model)
  635. model.pageRange = pages
  636. self.convertOCR(outputFolderPath: outputFolderPath, document: pdfDocument!, fileName: fileName, data: model) { progress in
  637. } complete: { document, text, error in
  638. if (error != nil) {
  639. self.batchFailure()
  640. } else {
  641. self.batchSuccess()
  642. }
  643. }
  644. } else {
  645. pdfDocument?.write(toFile: path)
  646. }
  647. self.batchSuccess()
  648. }
  649. }
  650. }
  651. }
  652. //MARK: private
  653. extension KMBatchManager {
  654. func fetchValidPageIndexString(_ document: CPDFDocument, model: KMBatchProcessingTableViewModel) -> String? {
  655. if model.pageRange == .all {
  656. let pages = Array(0..<Int(document.pageCount))
  657. let pageIndexString = pages.isEmpty ? "" : pages.map { "\($0)" }.joined(separator: ",")
  658. return pageIndexString
  659. } else {
  660. let data = KMOCRModel()
  661. data.pageRangeType = model.pageRange
  662. data.pageRangeString = model.pageRangeString
  663. let pages:[Int] = KMOCRManager.fetchPageIndex(document: document, model: data)
  664. let pageIndexString = pages.isEmpty ? "" : pages.map { "\($0)" }.joined(separator: ",")
  665. return pageIndexString
  666. }
  667. return nil
  668. }
  669. func fetchDocument(filePath: String, model: KMBatchProcessingTableViewModel) -> CPDFDocument {
  670. var document = CPDFDocument(url: URL(fileURLWithPath: filePath))
  671. if model.pageRange == .all {
  672. } else {
  673. let data = KMOCRModel()
  674. data.pageRangeType = model.pageRange
  675. data.pageRangeString = model.pageRangeString
  676. let pages:[Int] = KMOCRManager.fetchPageIndex(document: document!, model: data)
  677. var tempDocument = CPDFDocument()
  678. for i in 0..<pages.count {
  679. let page = document?.page(at: UInt(i))
  680. tempDocument?.insertPageObject(page, at: tempDocument?.pageCount ?? 0)
  681. }
  682. let fileName = filePath.deletingPathExtension.lastPathComponent
  683. let isSuccess = tempDocument?.write(toFile: self.fetchTempFilePath(fileName: fileName))
  684. if isSuccess != nil {
  685. document = tempDocument
  686. }
  687. }
  688. return document ?? CPDFDocument()
  689. }
  690. func fetchTempFilePath(fileName: String) -> String {
  691. let floderPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!).stringByAppendingPathComponent("BatchTemp")
  692. let filePath = floderPath?.stringByAppendingPathComponent("\(fileName).pdf")
  693. if let data = floderPath, !FileManager.default.fileExists(atPath: data) {
  694. try?FileManager.default.createDirectory(atPath: data, withIntermediateDirectories: false)
  695. }
  696. if let data = filePath, !FileManager.default.fileExists(atPath: data) {
  697. FileManager.default.createFile(atPath: data, contents: nil)
  698. }
  699. return filePath ?? ""
  700. }
  701. func removeTempFilePath(filePath: String) {
  702. let fileName = filePath.deletingPathExtension.lastPathComponent
  703. let path = self.fetchTempFilePath(fileName: fileName)
  704. if (FileManager.default.fileExists(atPath: path)) {
  705. try?FileManager.default.removeItem(atPath: path)
  706. }
  707. }
  708. }
  709. //MARK: Alert
  710. extension KMBatchManager {
  711. func batchUnkown() {
  712. self.state = .unknow
  713. NotificationCenter.default.post(name: NSNotification.Name(kBacthProcessNotification), object: nil)
  714. }
  715. func batchProgress() {
  716. self.state = .processing
  717. NotificationCenter.default.post(name: NSNotification.Name(kBacthProcessNotification), object: nil)
  718. }
  719. func batchSuccess() {
  720. self.state = .complete
  721. NotificationCenter.default.post(name: NSNotification.Name(kBacthProcessNotification), object: nil)
  722. }
  723. func batchFailure() {
  724. self.state = .error
  725. NotificationCenter.default.post(name: NSNotification.Name(kBacthProcessNotification), object: nil)
  726. }
  727. func itemProgress(item: KMBatchProcessingTableViewModel, processValue: Float) {
  728. if processValue > 0.7 {
  729. item.state = .loading70
  730. } else {
  731. item.state = .loading
  732. }
  733. NotificationCenter.default.post(name: NSNotification.Name(kBacthFilesProcessNotification), object: item)
  734. }
  735. func itemSuccess(item: KMBatchProcessingTableViewModel) {
  736. self.removeTempFilePath(filePath: item.filePath)
  737. item.state = .success
  738. NotificationCenter.default.post(name: NSNotification.Name(kBacthFilesProcessNotification), object: item)
  739. }
  740. func itemFailure(item: KMBatchProcessingTableViewModel, error: NSError?) {
  741. self.removeTempFilePath(filePath: item.filePath)
  742. item.state = .error
  743. NotificationCenter.default.post(name: NSNotification.Name(kBacthFilesProcessNotification), object: item)
  744. guard let error = error else { return }
  745. var errorString = ""
  746. let myError: NSError = error as NSError
  747. if myError.code == 1 {
  748. errorString = NSLocalizedString("Password required or incorrect password. Please re-enter your password and try again", comment: "")
  749. } else if myError.code == 2 {
  750. errorString = NSLocalizedString("The license doesn't allow the permission", comment: "")
  751. } else if myError.code == 3 {
  752. errorString = NSLocalizedString("Malloc failure", comment: "")
  753. } else if myError.code == 4 {
  754. errorString = NSLocalizedString("Unknown error in processing conversion. Please try again later", comment: "")
  755. } else if myError.code == 5 {
  756. errorString = NSLocalizedString("Unknown error in processing PDF. Please try again later", comment: "")
  757. } else if myError.code == 6 {
  758. errorString = NSLocalizedString("File not found or could not be opened. Check if your file exists or choose another file to convert", comment: "")
  759. } else if myError.code == 7 {
  760. errorString = NSLocalizedString("File not in PDF format or corruptead. Change a PDF file and try again", comment: "")
  761. } else if myError.code == 8 {
  762. errorString = NSLocalizedString("Unsupported security scheme", comment: "")
  763. } else if myError.code == 9 {
  764. errorString = NSLocalizedString("Page not found or content error", comment: "")
  765. } else {
  766. errorString = NSLocalizedString("Table not found", comment: "")
  767. }
  768. let alert = NSAlert()
  769. alert.alertStyle = .critical
  770. alert.messageText = NSLocalizedString("Conversion Failed", comment: "")
  771. alert.informativeText = errorString
  772. alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
  773. alert.runModal()
  774. }
  775. }