KMBatchManager.swift 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067
  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. //
  98. // let settingData = data as? KMBatchConvertPDFViewModel ?? KMBatchConvertPDFViewModel()
  99. // var fileName = filePath.deletingPathExtension.lastPathComponent
  100. // if ((fileName.isEmpty)) {
  101. // fileName = NSLocalizedString("Untitled", comment: "")
  102. // }
  103. //
  104. // let convert = self.addConvertParameter(settingData)
  105. //
  106. // let pageCount = document.pageCount
  107. // //获取page
  108. // var pages:[Int] = []
  109. // for i in 0..<pageCount {
  110. // pages.append(Int(i)+1)
  111. // }
  112. //
  113. // convert.outputFolderPath = outputFolderPath
  114. // convert.filePath = filePath
  115. // convert.outputFileName = fileName
  116. // convert.pages = pages
  117. //
  118. // convert.isAllowOCR = settingData.needRecognizeText
  119. // convert.ocrLanguage = settingData.languageType
  120. //
  121. // item.state = .clock
  122. // KMPDFConvertManager.defaultManager.convert(convert: convert, progress: { [unowned self] progressValue in
  123. // print("转档进度 - \(progressValue)")
  124. // let progress = Float(progressValue) / Float(pageCount)
  125. // self.itemProgress(item: item, processValue: progress)
  126. // }, completion: { [unowned self] finished, error in
  127. // if finished {
  128. // if FileManager.default.fileExists(atPath: outputFolderPath) {
  129. // NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)])
  130. // }
  131. // self.itemSuccess(item: item)
  132. // } else {
  133. // self.itemFailure(item: item, error: error! as NSError)
  134. // }
  135. //
  136. // if i == filesData.count - 1 {
  137. // self.batchSuccess()
  138. // }
  139. // })
  140. // }
  141. // }
  142. // }
  143. // }
  144. func convertFile(outputFolderPath: String, data: KMBatchSettingItemViewModel, filesData: [KMBatchProcessingTableViewModel]) {
  145. guard !filesData.isEmpty else { return }
  146. func processFile(at index: Int) {
  147. guard index < filesData.count else {
  148. self.batchSuccess()
  149. return
  150. }
  151. let item = filesData[index]
  152. let filePath = item.filePath
  153. let document = self.fetchDocument(filePath: filePath, model: item)
  154. let settingData = data as? KMBatchConvertPDFViewModel ?? KMBatchConvertPDFViewModel()
  155. var fileName = filePath.deletingPathExtension.lastPathComponent
  156. if fileName.isEmpty {
  157. fileName = NSLocalizedString("Untitled", comment: "")
  158. }
  159. let convert = self.addConvertParameter(settingData)
  160. let pageCount = document.pageCount
  161. // 获取页面
  162. let pages: [Int] = Array(1...Int(pageCount))
  163. convert.outputFolderPath = outputFolderPath
  164. convert.filePath = filePath
  165. convert.outputFileName = fileName
  166. convert.pages = pages
  167. convert.isAllowOCR = settingData.needRecognizeText
  168. convert.ocrLanguage = settingData.languageType
  169. item.state = .clock
  170. KMPDFConvertManager.defaultManager.convert(convert: convert, progress: { [unowned self] progressValue in
  171. print("转档进度 - \(progressValue)")
  172. let progress = Float(progressValue) / Float(pageCount)
  173. self.itemProgress(item: item, processValue: progress)
  174. }, completion: { [unowned self] finished, error in
  175. if finished {
  176. if FileManager.default.fileExists(atPath: outputFolderPath) {
  177. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)])
  178. }
  179. self.itemSuccess(item: item)
  180. } else {
  181. self.itemFailure(item: item, error: error! as NSError)
  182. }
  183. processFile(at: index + 1)
  184. })
  185. }
  186. // 开始处理第一个文件
  187. processFile(at: 0)
  188. }
  189. func addConvertParameter(_ data: KMBatchConvertPDFViewModel) -> KMPDFConvert {
  190. let settingData = data
  191. var convert = KMPDFConvert()
  192. switch settingData.convertPDFType {
  193. case .word:
  194. convert = KMPDFConvertWord()
  195. if settingData.layoutSettingType == .flowingText {
  196. convert.isAllInOneSheet = false
  197. } else {
  198. convert.isAllInOneSheet = true
  199. }
  200. case .excel:
  201. convert = KMPDFConvertExcel()
  202. if settingData.excelSetting == .separate {
  203. convert.isAllInOneSheet = false
  204. convert.isExtractTable = false
  205. } else if settingData.excelSetting == .format {
  206. convert.isAllInOneSheet = true
  207. convert.isExtractTable = false
  208. } else if settingData.excelSetting == .tables {
  209. convert.isAllInOneSheet = false
  210. convert.isExtractTable = true
  211. switch settingData.excelTablesType {
  212. case .oneTable:
  213. convert.extractTableIndex = 0
  214. case .pageTable:
  215. convert.extractTableIndex = 1
  216. case .allTable:
  217. convert.extractTableIndex = 2
  218. default:
  219. KMPrint("未找到")
  220. }
  221. }
  222. case .ppt:
  223. convert = KMPDFConvertPPT()
  224. case .csv:
  225. convert = KMPDFConvertCSV()
  226. if settingData.csvOnlyTables {
  227. convert.isExtractTable = true
  228. switch settingData.excelTablesType {
  229. case .oneTable:
  230. convert.extractTableIndex = 0
  231. case .pageTable:
  232. convert.extractTableIndex = 1
  233. case .allTable:
  234. convert.extractTableIndex = 2
  235. default:
  236. KMPrint("未找到")
  237. }
  238. } else {
  239. convert.isExtractTable = false
  240. }
  241. case .image:
  242. convert = KMPDFConvertImage()
  243. convert.convertType = data.imageType
  244. var dpi: Int = 150
  245. if data.imageDpiIndex == 0 {
  246. dpi = 50
  247. } else if data.imageDpiIndex == 1 {
  248. dpi = 72
  249. } else if data.imageDpiIndex == 2 {
  250. dpi = 96
  251. } else if data.imageDpiIndex == 3 {
  252. dpi = 150
  253. } else if data.imageDpiIndex == 4 {
  254. dpi = 300
  255. } else if data.imageDpiIndex == 5 {
  256. dpi = 600
  257. } else {
  258. dpi = 150
  259. }
  260. if (convert.convertType == .jpeg) {
  261. (convert as! KMPDFConvertImage).imageType = .JPEG
  262. (convert as! KMPDFConvertImage).imageDpi = dpi
  263. } else if (convert.convertType == .png) {
  264. (convert as! KMPDFConvertImage).imageType = .PNG
  265. (convert as! KMPDFConvertImage).imageDpi = dpi
  266. } else {
  267. (convert as! KMPDFConvertImage).imageDpi = 150
  268. }
  269. case .html:
  270. convert = KMPDFConvertHTML()
  271. case .rtf:
  272. convert = KMPDFConvertRTF()
  273. case .json:
  274. convert = KMPDFConvertJson()
  275. if settingData.jsonType == .extractText {
  276. convert.isAllInOneSheet = false
  277. } else {
  278. convert.isAllInOneSheet = true
  279. }
  280. case .text:
  281. convert = KMPDFConvertText()
  282. default:
  283. KMPrint("不清楚")
  284. }
  285. return convert
  286. }
  287. //MARK: OCR
  288. func convertOCRExport(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  289. self.convertOCR(outputFolderPath: outputFolderPath, data: data as! KMOCRModel, filesData: self.batchFilesData)
  290. }
  291. func convertOCR(outputFolderPath: String, data: KMOCRModel, filesData: [KMBatchProcessingTableViewModel]?) {
  292. guard let filesData = filesData else { return }
  293. for i in 0..<filesData.count {
  294. let item = (filesData[i])
  295. let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  296. if document != nil {
  297. //计算需要处理的页面
  298. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  299. if ((fileName.isEmpty)) {
  300. fileName = NSLocalizedString("Untitled", comment: "")
  301. }
  302. let path = outputFolderPath + "/" + fileName + ".pdf"
  303. self.convertOCR(outputFolderPath: outputFolderPath, document: document!, fileName: fileName, data: data) { [unowned self] progress in
  304. self.itemProgress(item: item, processValue: progress)
  305. } complete: { [unowned self] document, text, error in
  306. if error == nil {
  307. self.itemSuccess(item: item)
  308. } else {
  309. self.itemFailure(item: item, error: error! as NSError)
  310. }
  311. if i == filesData.count - 1 {
  312. self.batchSuccess()
  313. }
  314. }
  315. }
  316. }
  317. }
  318. func convertOCR(outputFolderPath: String,
  319. document: CPDFDocument,
  320. fileName: String,
  321. data: KMOCRModel,
  322. progress: @escaping KMOCRManagerOCRProgress,
  323. complete: @escaping KMOCRManagerOCRComplete) {
  324. //计算需要处理的页面
  325. let path = outputFolderPath + "/" + fileName + ".pdf"
  326. KMOCRManager.manager.convertBatchOCR(document: document, saveFilePath: path, model: data, progress: { [unowned self] progressValue in
  327. progress(progressValue)
  328. }) { [unowned self] document, text, error in
  329. complete(document, text, error)
  330. }
  331. }
  332. //MARK: 压缩
  333. func compressExport(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  334. self.compressFile(outputFolderPath: outputFolderPath, data: (data as? KMCompressSettingModel)!, filesData: self.batchFilesData)
  335. }
  336. func compressFile(outputFolderPath: String, data: KMCompressSettingModel, filesData: [KMBatchProcessingTableViewModel]) {
  337. if filesData.count != 0 {
  338. for i in 0..<filesData.count {
  339. let item = filesData[i]
  340. let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  341. if document != nil {
  342. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  343. if ((fileName.isEmpty)) {
  344. fileName = NSLocalizedString("Untitled", comment: "")
  345. }
  346. let path = outputFolderPath + "/" + fileName + ".pdf"
  347. KMCompressManager.shared.compress(documentURL: URL(fileURLWithPath: item.filePath), fileURL: URL(fileURLWithPath: path), limit: false, model: data) { currentPage, totalPages in
  348. let progress = Float(currentPage) / Float(totalPages)
  349. self.itemProgress(item: item, processValue: progress)
  350. } cancelHandler: {
  351. return false
  352. } completionHandler: { [unowned self] isFinish in
  353. if isFinish {
  354. self.itemSuccess(item: item)
  355. } else {
  356. self.itemFailure(item: item, error: nil)
  357. }
  358. if i == filesData.count - 1 {
  359. self.batchSuccess()
  360. }
  361. }
  362. }
  363. }
  364. }
  365. }
  366. //MARK: 安全
  367. func securityExport(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  368. self.securityFile(outputFolderPath: outputFolderPath, data: data as! KMBatchSecurityViewModel, filesData: self.batchFilesData)
  369. }
  370. func securityFile(outputFolderPath: String, data: KMBatchSecurityViewModel, filesData: [KMBatchProcessingTableViewModel]) {
  371. if filesData.count != 0 {
  372. for i in 0..<filesData.count {
  373. let item = filesData[i]
  374. let docuemt = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  375. if (docuemt != nil) {
  376. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  377. if ((fileName.isEmpty)) {
  378. fileName = NSLocalizedString("Untitled", comment: "")
  379. }
  380. let path = outputFolderPath + "/" + fileName + ".pdf"
  381. var options: [CPDFDocumentWriteOption : Any] = [:]
  382. //开启密码
  383. if data.isOpenPassword &&
  384. !data.openPasswordString.isEmpty {
  385. options.updateValue(data.openPasswordString, forKey: .userPasswordOption)
  386. }
  387. //
  388. //权限密码
  389. if data.isPermission &&
  390. !data.permissionString.isEmpty {
  391. options.updateValue(data.permissionString, forKey: .ownerPasswordOption)
  392. }
  393. // 限制打印
  394. if data.restrictOptions.contains(.print) {
  395. options.updateValue(false, forKey: .allowsPrintingOption)
  396. } else {
  397. options.updateValue(true, forKey: .allowsPrintingOption)
  398. }
  399. //限制复制
  400. if data.restrictOptions.contains(.copy) {
  401. options.updateValue(false, forKey: .allowsCopyingOption)
  402. } else {
  403. options.updateValue(true, forKey: .allowsCopyingOption)
  404. }
  405. let result = docuemt!.write(toFile: path, withOptions: options)
  406. // let result = docuemt!.write(to: URL(fileURLWithPath: path), withOptions: options)
  407. if result {
  408. KMPrint("成功")
  409. self.itemSuccess(item: item)
  410. } else {
  411. KMPrint("失败")
  412. self.itemFailure(item: item, error: nil)
  413. }
  414. if i == filesData.count - 1 {
  415. self.batchSuccess()
  416. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)])
  417. }
  418. }
  419. }
  420. }
  421. }
  422. //MARK: 水印
  423. func waterMarkApplay(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  424. if let data = data as? KMBatchWatermarkModel {
  425. self.waterMarkFile(outputFolderPath: outputFolderPath, data: data, filesData: self.batchFilesData)
  426. }
  427. }
  428. func waterMarkFile(outputFolderPath: String, data: KMBatchWatermarkModel, 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 watermarks = document?.watermarks(), let model = data.watermarkModel, let document = document {
  446. let pageString = self.fetchValidPageIndexString(document, model: item)
  447. let watermark = KMPDFWatermarkData.returnWaterMarkWith(model, document)
  448. watermark.pageString = pageString
  449. document.addWatermark(watermark)
  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 backgroundApplay(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  471. if let data = data as? KMBatchBackgroundModel {
  472. self.backgroundFile(outputFolderPath: outputFolderPath, data: data, filesData: self.batchFilesData)
  473. }
  474. }
  475. func backgroundFile(outputFolderPath: String, data: KMBatchBackgroundModel, filesData: [KMBatchProcessingTableViewModel]) {
  476. if filesData.count != 0 {
  477. for i in 0..<filesData.count {
  478. let item = filesData[i]
  479. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  480. if ((fileName.isEmpty)) {
  481. fileName = NSLocalizedString("Untitled", comment: "")
  482. }
  483. let path = outputFolderPath + "/" + fileName + ".pdf"
  484. let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  485. if (document?.allowsPrinting == false || document?.allowsCopying == false) {
  486. let alert = NSAlert()
  487. alert.alertStyle = .critical
  488. alert.messageText = "此文档不允许修改"
  489. alert.runModal()
  490. return
  491. }
  492. if let background = document?.background(), let model = data.backgroundModel, let document = document {
  493. KMBackgroundManager.defaultManager.updateBackground(background, withModel: model)
  494. let pageIndexString = self.fetchValidPageIndexString(document, model: item)
  495. background.pageString = pageIndexString
  496. background.update()
  497. }
  498. if (FileManager.default.fileExists(atPath: path)) {
  499. try?FileManager.default.removeItem(atPath: path)
  500. }
  501. let result = document?.write(to: URL(fileURLWithPath: path)) ?? false
  502. if (result) {
  503. KMPrint("removeFile成功")
  504. self.itemSuccess(item: item)
  505. } else {
  506. KMPrint("removeFile失败")
  507. self.itemFailure(item: item, error: nil)
  508. }
  509. if i == filesData.count - 1 {
  510. self.batchSuccess()
  511. }
  512. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: path)])
  513. }
  514. }
  515. }
  516. //MARK: 页眉页脚
  517. func headAndFooterApplay(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  518. if let data = data as? KMBatchHeaderAndFooterModel {
  519. self.headAndFooterFile(outputFolderPath: outputFolderPath, data: data, filesData: self.batchFilesData)
  520. }
  521. }
  522. func headAndFooterFile(outputFolderPath: String, data: KMBatchHeaderAndFooterModel, filesData: [KMBatchProcessingTableViewModel]) {
  523. if filesData.count != 0 {
  524. for i in 0..<filesData.count {
  525. let item = filesData[i]
  526. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  527. if ((fileName.isEmpty)) {
  528. fileName = NSLocalizedString("Untitled", comment: "")
  529. }
  530. let path = outputFolderPath + "/" + fileName + ".pdf"
  531. let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  532. if (document?.allowsPrinting == false || document?.allowsCopying == false) {
  533. let alert = NSAlert()
  534. alert.alertStyle = .critical
  535. alert.messageText = "此文档不允许修改"
  536. alert.runModal()
  537. return
  538. }
  539. if let headerFooter = document?.headerFooter(), let model = data.headerFooterModel, let document = document {
  540. let pageString = self.fetchValidPageIndexString(document, model: item)
  541. KMHeaderFooterManager.defaultManager.updateCPDFHeaderFooter(headerFooter, withModel: model, Int(document.pageCount))
  542. headerFooter.pageString = pageString
  543. headerFooter.update()
  544. }
  545. if (FileManager.default.fileExists(atPath: path)) {
  546. try?FileManager.default.removeItem(atPath: path)
  547. }
  548. let result = document?.write(to: URL(fileURLWithPath: path)) ?? false
  549. if (result) {
  550. KMPrint("removeFile成功")
  551. self.itemSuccess(item: item)
  552. } else {
  553. KMPrint("removeFile失败")
  554. self.itemFailure(item: item, error: nil)
  555. }
  556. if i == filesData.count - 1 {
  557. self.batchSuccess()
  558. }
  559. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: path)])
  560. }
  561. }
  562. }
  563. //MARK: 贝茨码
  564. func batesApplay(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  565. if let data = data as? KMBatchBatesModel {
  566. self.batesFile(outputFolderPath: outputFolderPath, data: data, filesData: self.batchFilesData)
  567. }
  568. }
  569. func batesFile(outputFolderPath: String, data: KMBatchBatesModel, filesData: [KMBatchProcessingTableViewModel]) {
  570. if filesData.count != 0 {
  571. for i in 0..<filesData.count {
  572. let item = filesData[i]
  573. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  574. if ((fileName.isEmpty)) {
  575. fileName = NSLocalizedString("Untitled", comment: "")
  576. }
  577. let path = outputFolderPath + "/" + fileName + ".pdf"
  578. let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  579. if (document?.allowsPrinting == false || document?.allowsCopying == false) {
  580. let alert = NSAlert()
  581. alert.alertStyle = .critical
  582. alert.messageText = "此文档不允许修改"
  583. alert.runModal()
  584. return
  585. }
  586. if let bates = document?.bates(), let model = data.batesModel, let document = document {
  587. let pageString = self.fetchValidPageIndexString(document, model: item)
  588. KMBatesManager.defaultManager.updateCPDFBates(bates, withModel: model, Int(document.pageCount))
  589. bates.pageString = pageString
  590. bates.update()
  591. }
  592. if (FileManager.default.fileExists(atPath: path)) {
  593. try?FileManager.default.removeItem(atPath: path)
  594. }
  595. let result = document?.write(to: URL(fileURLWithPath: path)) ?? false
  596. if (result) {
  597. KMPrint("removeFile成功")
  598. self.itemSuccess(item: item)
  599. } else {
  600. KMPrint("removeFile失败")
  601. self.itemFailure(item: item, error: nil)
  602. }
  603. if i == filesData.count - 1 {
  604. self.batchSuccess()
  605. }
  606. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: path)])
  607. }
  608. }
  609. }
  610. //MARK: 移除
  611. func removeApplay(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  612. self.removeFile(outputFolderPath: outputFolderPath, data: data as! KMBatchRemoveViewModel, filesData: self.batchFilesData)
  613. }
  614. func removeFile(outputFolderPath: String, data: KMBatchRemoveViewModel, filesData: [KMBatchProcessingTableViewModel]) {
  615. if filesData.count != 0 {
  616. for i in 0..<filesData.count {
  617. let item = filesData[i]
  618. // DispatchQueue.global().async {
  619. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  620. if ((fileName.isEmpty)) {
  621. fileName = NSLocalizedString("Untitled", comment: "")
  622. }
  623. let path = outputFolderPath + "/" + fileName + ".pdf"
  624. let document = CPDFDocument.init(url: URL(fileURLWithPath: item.filePath))
  625. if document != nil {
  626. if (document!.allowsPrinting == false || document!.allowsCopying == false) {
  627. let alert = NSAlert()
  628. alert.alertStyle = .critical
  629. alert.messageText = "此文档不允许修改"
  630. alert.runModal()
  631. return
  632. }
  633. if (data.options.contains(.security)) {
  634. }
  635. if (data.options.contains(.batesNumber)) {
  636. let property = document!.bates()
  637. property?.clear()
  638. }
  639. if (data.options.contains(.headerAndFooter)) {
  640. let property = document!.headerFooter()
  641. property?.clear()
  642. }
  643. if (data.options.contains(.background)) {
  644. let property = document!.background()
  645. property?.clear()
  646. }
  647. if (data.options.contains(.watermark)) {
  648. let array: Array<CPDFWatermark> = document!.watermarks() ?? []
  649. for model in array {
  650. document!.removeWatermark(model)
  651. }
  652. }
  653. if (FileManager.default.fileExists(atPath: path)) {
  654. try?FileManager.default.removeItem(atPath: path)
  655. }
  656. let result = document!.write(to: URL(fileURLWithPath: path))
  657. if (result) {
  658. KMPrint("removeFile成功")
  659. self.itemSuccess(item: item)
  660. } else {
  661. KMPrint("removeFile失败")
  662. self.itemFailure(item: item, error: nil)
  663. }
  664. if i == filesData.count - 1 {
  665. self.batchSuccess()
  666. }
  667. NSWorkspace.shared.activateFileViewerSelecting([URL(fileURLWithPath: outputFolderPath)])
  668. }
  669. // }
  670. }
  671. }
  672. }
  673. //MARK: 图片转PDF
  674. func imageToPDFExport(data: KMBatchSettingItemViewModel, outputFolderPath: String) {
  675. self.imageToPDFFile(outputFolderPath: outputFolderPath, data: data as! KMBatchImageToPDFModel, filesData: self.batchFilesData)
  676. }
  677. func imageToPDFFile(outputFolderPath: String, data: KMBatchImageToPDFModel, filesData: [KMBatchProcessingTableViewModel]) {
  678. if filesData.count != 0 {
  679. self.batchProgress()
  680. if data.isNewPDF {
  681. if data.isMergeAll {
  682. let item = filesData[0]
  683. var fileName = item.filePath.deletingPathExtension.lastPathComponent
  684. let path = outputFolderPath + "/" + fileName + ".pdf"
  685. var pdfDocument = CPDFDocument()
  686. for item in filesData {
  687. pdfDocument?.km_insert(image: item.image, at: pdfDocument?.pageCount ?? 0)
  688. }
  689. if data.isOCR {
  690. let model = KMOCRModel()
  691. model.showType = .page
  692. model.saveAsPDF = true
  693. model.ocrType = data.ocrType
  694. model.languageType = data.languageType
  695. model.needTxT = data.isExtractText
  696. model.pageRangeType = .all
  697. //计算需要处理的页面
  698. let pages:[Int] = KMOCRManager.fetchPageIndex(document: pdfDocument!, model: model)
  699. model.pageRange = pages
  700. self.batchProgress()
  701. self.convertOCR(outputFolderPath: outputFolderPath, document: pdfDocument!, fileName: fileName, data: model) { progress in
  702. self.batchProgress()
  703. } complete: { document, text, error in
  704. self.batchSuccess()
  705. }
  706. } else {
  707. let success = pdfDocument?.write(toFile: path)
  708. if success != nil {
  709. for item in filesData {
  710. self.itemSuccess(item: item)
  711. }
  712. self.batchSuccess()
  713. } else {
  714. self.batchFailure()
  715. }
  716. }
  717. } else {
  718. processFile(at: 0, outputFolderPath: outputFolderPath, data: data)
  719. }
  720. } else {
  721. var fileName = data.selectFilePath.deletingPathExtension.lastPathComponent
  722. let path = outputFolderPath + "/" + fileName + ".pdf"
  723. var pdfDocument = CPDFDocument(url: NSURL(fileURLWithPath: data.selectFilePath) as URL)
  724. let count: Int = Int(pdfDocument?.pageCount ?? 0)
  725. for item in filesData {
  726. pdfDocument?.km_insert(image: item.image, at: pdfDocument?.pageCount ?? 0)
  727. }
  728. if data.isOCR {
  729. let model = KMOCRModel()
  730. model.showType = .page
  731. model.saveAsPDF = true
  732. model.ocrType = data.ocrType
  733. model.languageType = data.languageType
  734. model.needTxT = data.isExtractText
  735. model.pageRangeType = .all
  736. //计算需要处理的页面
  737. let pages:[Int] = KMOCRManager.fetchPageIndex(document: pdfDocument!, model: model)
  738. model.pageRange = pages
  739. self.convertOCR(outputFolderPath: outputFolderPath, document: pdfDocument!, fileName: fileName, data: model) { progress in
  740. } complete: { document, text, error in
  741. if (error != nil) {
  742. self.batchFailure()
  743. } else {
  744. for item in filesData {
  745. self.itemSuccess(item: item)
  746. }
  747. self.batchSuccess()
  748. }
  749. }
  750. } else {
  751. let success = pdfDocument?.write(toFile: path)
  752. if success != nil {
  753. for item in filesData {
  754. self.itemSuccess(item: item)
  755. }
  756. self.batchSuccess()
  757. } else {
  758. self.batchFailure()
  759. }
  760. }
  761. }
  762. }
  763. }
  764. func processFile(at index: Int, outputFolderPath: String, data: KMBatchImageToPDFModel) {
  765. guard index < filesData.count else {
  766. self.batchSuccess()
  767. return
  768. }
  769. let item = filesData[index]
  770. if data.isOCR {
  771. let fileName = item.filePath.deletingPathExtension.lastPathComponent
  772. let path = outputFolderPath + "/" + fileName + ".pdf"
  773. let pdfDocument = CPDFDocument()
  774. pdfDocument?.km_insert(image: item.image, at: pdfDocument?.pageCount ?? 0)
  775. let model = KMOCRModel()
  776. model.showType = .page
  777. model.saveAsPDF = true
  778. model.ocrType = data.ocrType
  779. model.languageType = data.languageType
  780. model.needTxT = data.isExtractText
  781. model.pageRangeType = .all
  782. let pages: [Int] = KMOCRManager.fetchPageIndex(document: pdfDocument!, model: model)
  783. model.pageRange = pages
  784. self.itemProgress(item: item, processValue: 0)
  785. self.convertOCR(outputFolderPath: outputFolderPath, document: pdfDocument!, fileName: fileName, data: model) { [unowned self] progress in
  786. self.itemProgress(item: item, processValue: progress)
  787. } complete: { [unowned self] document, text, error in
  788. self.itemSuccess(item: filesData[index])
  789. processFile(at: index + 1, outputFolderPath: outputFolderPath, data: data)
  790. }
  791. } else {
  792. let fileName = item.filePath.deletingPathExtension.lastPathComponent
  793. let path = outputFolderPath + "/" + fileName + ".pdf"
  794. let pdfDocument = CPDFDocument()
  795. pdfDocument?.km_insert(image: item.image, at: pdfDocument?.pageCount ?? 0)
  796. let success = pdfDocument?.write(toFile: path)
  797. if success != nil {
  798. self.itemSuccess(item: item)
  799. processFile(at: index + 1, outputFolderPath: outputFolderPath, data: data)
  800. } else {
  801. self.itemFailure(item: item, error: nil)
  802. }
  803. }
  804. }
  805. }
  806. //MARK: private
  807. extension KMBatchManager {
  808. func fetchValidPageIndexString(_ document: CPDFDocument, model: KMBatchProcessingTableViewModel) -> String? {
  809. if model.pageRange == .all {
  810. let pages = Array(0..<Int(document.pageCount))
  811. let pageIndexString = pages.isEmpty ? "" : pages.map { "\($0)" }.joined(separator: ",")
  812. return pageIndexString
  813. } else {
  814. let data = KMOCRModel()
  815. data.pageRangeType = model.pageRange
  816. data.pageRangeString = model.pageRangeString
  817. let pages:[Int] = KMOCRManager.fetchPageIndex(document: document, model: data)
  818. let pageIndexString = pages.isEmpty ? "" : pages.map { "\($0)" }.joined(separator: ",")
  819. return pageIndexString
  820. }
  821. return nil
  822. }
  823. func fetchDocument(filePath: String, model: KMBatchProcessingTableViewModel) -> CPDFDocument {
  824. var document = CPDFDocument(url: URL(fileURLWithPath: filePath))
  825. if model.pageRange == .all {
  826. } else {
  827. let data = KMOCRModel()
  828. data.pageRangeType = model.pageRange
  829. data.pageRangeString = model.pageRangeString
  830. let pages:[Int] = KMOCRManager.fetchPageIndex(document: document!, model: data)
  831. var tempDocument = CPDFDocument()
  832. for i in 0..<pages.count {
  833. let page = document?.page(at: UInt(i))
  834. tempDocument?.insertPageObject(page, at: tempDocument?.pageCount ?? 0)
  835. }
  836. let fileName = filePath.deletingPathExtension.lastPathComponent
  837. let isSuccess = tempDocument?.write(toFile: self.fetchTempFilePath(fileName: fileName))
  838. if isSuccess != nil {
  839. document = tempDocument
  840. }
  841. }
  842. return document ?? CPDFDocument()
  843. }
  844. func fetchTempFilePath(fileName: String) -> String {
  845. let floderPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!).stringByAppendingPathComponent("BatchTemp")
  846. let filePath = floderPath?.stringByAppendingPathComponent("\(fileName).pdf")
  847. if let data = floderPath, !FileManager.default.fileExists(atPath: data) {
  848. try?FileManager.default.createDirectory(atPath: data, withIntermediateDirectories: false)
  849. }
  850. if let data = filePath, !FileManager.default.fileExists(atPath: data) {
  851. FileManager.default.createFile(atPath: data, contents: nil)
  852. }
  853. return filePath ?? ""
  854. }
  855. func removeTempFilePath(filePath: String) {
  856. let fileName = filePath.deletingPathExtension.lastPathComponent
  857. let path = self.fetchTempFilePath(fileName: fileName)
  858. if (FileManager.default.fileExists(atPath: path)) {
  859. try?FileManager.default.removeItem(atPath: path)
  860. }
  861. }
  862. }
  863. //MARK: Alert
  864. extension KMBatchManager {
  865. func batchUnkown() {
  866. self.state = .unknow
  867. NotificationCenter.default.post(name: NSNotification.Name(kBacthProcessNotification), object: nil)
  868. }
  869. func batchProgress() {
  870. for item in filesData {
  871. self.itemProgress(item: item, processValue: 0)
  872. }
  873. self.state = .processing
  874. NotificationCenter.default.post(name: NSNotification.Name(kBacthProcessNotification), object: nil)
  875. }
  876. func batchSuccess() {
  877. self.state = .complete
  878. NotificationCenter.default.post(name: NSNotification.Name(kBacthProcessNotification), object: nil)
  879. }
  880. func batchFailure() {
  881. self.state = .error
  882. NotificationCenter.default.post(name: NSNotification.Name(kBacthProcessNotification), object: nil)
  883. }
  884. func itemProgress(item: KMBatchProcessingTableViewModel, processValue: Float) {
  885. if processValue > 0.7 {
  886. item.state = .loading70
  887. } else {
  888. item.state = .loading
  889. }
  890. NotificationCenter.default.post(name: NSNotification.Name(kBacthFilesProcessNotification), object: item)
  891. }
  892. func itemSuccess(item: KMBatchProcessingTableViewModel) {
  893. self.removeTempFilePath(filePath: item.filePath)
  894. item.state = .success
  895. NotificationCenter.default.post(name: NSNotification.Name(kBacthFilesProcessNotification), object: item)
  896. }
  897. func itemFailure(item: KMBatchProcessingTableViewModel, error: NSError?) {
  898. self.removeTempFilePath(filePath: item.filePath)
  899. item.state = .error
  900. NotificationCenter.default.post(name: NSNotification.Name(kBacthFilesProcessNotification), object: item)
  901. guard let error = error else { return }
  902. var errorString = ""
  903. let myError: NSError = error as NSError
  904. if myError.code == 1 {
  905. errorString = NSLocalizedString("Password required or incorrect password. Please re-enter your password and try again", comment: "")
  906. } else if myError.code == 2 {
  907. errorString = NSLocalizedString("The license doesn't allow the permission", comment: "")
  908. } else if myError.code == 3 {
  909. errorString = NSLocalizedString("Malloc failure", comment: "")
  910. } else if myError.code == 4 {
  911. errorString = NSLocalizedString("Unknown error in processing conversion. Please try again later", comment: "")
  912. } else if myError.code == 5 {
  913. errorString = NSLocalizedString("Unknown error in processing PDF. Please try again later", comment: "")
  914. } else if myError.code == 6 {
  915. errorString = NSLocalizedString("File not found or could not be opened. Check if your file exists or choose another file to convert", comment: "")
  916. } else if myError.code == 7 {
  917. errorString = NSLocalizedString("File not in PDF format or corruptead. Change a PDF file and try again", comment: "")
  918. } else if myError.code == 8 {
  919. errorString = NSLocalizedString("Unsupported security scheme", comment: "")
  920. } else if myError.code == 9 {
  921. errorString = NSLocalizedString("Page not found or content error", comment: "")
  922. } else {
  923. errorString = NSLocalizedString("Table not found", comment: "")
  924. }
  925. let alert = NSAlert()
  926. alert.alertStyle = .critical
  927. alert.messageText = NSLocalizedString("Conversion Failed", comment: "")
  928. alert.informativeText = errorString
  929. alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
  930. alert.runModal()
  931. }
  932. }