KMNThumbnailBaseViewController+Action.swift 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. //
  2. // KMMainViewController+Action.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by wanjun on 2022/12/15.
  6. //
  7. import Foundation
  8. extension KMNThumbnailBaseViewController {
  9. public func fileNameWithSelectedPages(_ itemIndexes: IndexSet) -> String {
  10. var pagesName = ""
  11. if (itemIndexes.count > 1) {
  12. pagesName.append(" pages")
  13. } else {
  14. pagesName.append(" page")
  15. }
  16. let docmentName = showDocument?.documentURL.deletingPathExtension().lastPathComponent ?? ""
  17. let tFileName = String(format: "%@ %@", pagesName,KMNTools.parseIndexSet(indexSet: itemIndexes))
  18. return String(format: "%@%@", docmentName,tFileName)
  19. }
  20. private func convertTIFFDataToPDF(_ tiffData: Data) -> Data? {
  21. guard let imsrc = CGImageSourceCreateWithData(tiffData as CFData, [kCGImageSourceTypeIdentifierHint: kUTTypeTIFF] as CFDictionary), CGImageSourceGetCount(imsrc) > 0, let cgImage = CGImageSourceCreateImageAtIndex(imsrc, 0, nil) else { return nil }
  22. let pdfData = NSMutableData(capacity: tiffData.count)
  23. let consumer = CGDataConsumer(data: pdfData! as CFMutableData)!
  24. var rect = CGRect(x: 0, y: 0, width: CGFloat(cgImage.width), height: CGFloat(cgImage.height))
  25. let ctxt = CGContext(consumer: consumer, mediaBox: &rect, nil)
  26. ctxt!.beginPDFPage(nil)
  27. ctxt!.draw(cgImage, in: rect)
  28. ctxt!.endPDFPage()
  29. ctxt!.closePDF()
  30. return pdfData as? Data
  31. }
  32. public func selectPages(with array: [Int]) {
  33. var selectIndexPaths: Set<IndexPath> = []
  34. for i in 0..<(showDocument?.pageCount ?? 0) {
  35. if array.contains(Int(i)) {
  36. selectIndexPaths.insert(IndexPath(item: Int(i), section: 0))
  37. }
  38. }
  39. collectionView.selectionIndexPaths = selectIndexPaths
  40. if selectIndexPaths.isEmpty { return }
  41. let firstIndexPath = selectIndexPaths.first
  42. collectionView.scrollToItems(at: [firstIndexPath ?? IndexPath(item: 0, section: 0)], scrollPosition: .top)
  43. }
  44. public func indexpathsToIndexs(indexpaths: Set<IndexPath>) -> IndexSet {
  45. var indexs = IndexSet()
  46. for indexPath in indexpaths {
  47. indexs.insert(indexPath.item)
  48. }
  49. return indexs
  50. }
  51. public func indexsToIndexpaths(indexs: IndexSet) -> Set<IndexPath> {
  52. var indexpaths = Set<IndexPath>()
  53. for index in indexs {
  54. indexpaths.insert(IndexPath(item: index, section: 0))
  55. }
  56. return indexpaths
  57. }
  58. public func insertFormPDF(insertPages: [CPDFPage],pageDex:Int) {
  59. var pageIndexDex: Int = pageDex
  60. var indexpaths = Set<IndexPath>()
  61. for page in insertPages {
  62. let isSuccessFul = showDocument?.insertPageObject(page, at: UInt(pageIndexDex))
  63. if(isSuccessFul == true) {
  64. indexpaths.insert(IndexPath(item: pageIndexDex, section: 0))
  65. pageIndexDex += 1
  66. }
  67. }
  68. refreshDatas()
  69. collectionView.reloadData()
  70. collectionView.scrollToItems(at: indexpaths, scrollPosition: .centeredVertically)
  71. collectionView.selectionIndexPaths = indexpaths
  72. }
  73. public func insertBlankPage(pageSize: CGSize,pageDex:Int) {
  74. var indexpaths = Set<IndexPath>()
  75. let isSuccessFul = showDocument?.insertBlankPage(pageSize: pageSize, at: pageDex)
  76. if(isSuccessFul == true) {
  77. indexpaths.insert(IndexPath(item: pageDex, section: 0))
  78. }
  79. refreshDatas()
  80. collectionView.reloadData()
  81. collectionView.scrollToItems(at: indexpaths, scrollPosition: .centeredVertically)
  82. collectionView.selectionIndexPaths = indexpaths
  83. }
  84. public func openDocumentWithImageFromPasteboard(_ pboard: NSPasteboard, error outError: AutoreleasingUnsafeMutablePointer<NSError?>?) -> CPDFDocument? {
  85. var document: CPDFDocument? = nil
  86. var data: Data? = nil
  87. if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.pdf.rawValue]) {
  88. data = pboard.data(forType: NSPasteboard.PasteboardType.pdf)
  89. } else if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.postScript.rawValue]) {
  90. data = pboard.data(forType: NSPasteboard.PasteboardType.postScript)
  91. } else if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.tiff.rawValue]) {
  92. data = convertTIFFDataToPDF(pboard.data(forType: NSPasteboard.PasteboardType.tiff) ?? Data())
  93. } else {
  94. let images = pboard.readObjects(forClasses: [NSImage.self], options: [:])
  95. let strings = pboard.readObjects(forClasses: [NSAttributedString.self], options: [:])
  96. if images?.count ?? 0 > 0 {
  97. data = convertTIFFDataToPDF((images![0] as AnyObject).tiffRepresentation!)
  98. } else if strings?.count ?? 0 > 0 {
  99. data = KMOCTool.convertStringsToPDF(withString: strings ?? [""]) // convertStringsToPDF(strings!)
  100. }
  101. }
  102. if let data = data {
  103. document = CPDFDocument(data: data)
  104. } else if let outError = outError {
  105. outError.pointee = NSError(domain: "SKDocumentErrorDomain", code: 3, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("Unable to load data from clipboard", comment: "Error description")])
  106. }
  107. return document
  108. }
  109. public func insertImageFilePath(imagePath:String,pageDex:Int)->Bool{
  110. var isSuccessFul:Bool = false
  111. if (FileManager.default.fileExists(atPath: imagePath)) {
  112. if let image = NSImage(contentsOfFile: imagePath) {
  113. isSuccessFul = showDocument?.km_insertPage(image.size, withImage: imagePath, at: UInt(pageDex)) == true
  114. }
  115. }
  116. return isSuccessFul
  117. }
  118. public func rotatePages(indexPaths: Set<IndexPath>, rotateAngle: Int) {
  119. var tIndexPaths: Set<IndexPath> = []
  120. tIndexPaths = indexPaths
  121. for targetIndexPath in indexPaths {
  122. if let page = showDocument?.page(at: UInt(targetIndexPath.item)) {
  123. var pageRotate = page.rotation + rotateAngle
  124. if(pageRotate == -90) {
  125. pageRotate = 270
  126. } else if (pageRotate == 450) {
  127. pageRotate = 90
  128. }
  129. page.rotation = pageRotate
  130. let cellView = collectionView.item(at: targetIndexPath) as? KMNThumbnailCollectionViewItem
  131. if(cellView != nil) {
  132. cellView?.thumbnailMode.removeCacheImage()
  133. }
  134. }
  135. }
  136. collectionView.reloadItems(at: tIndexPaths) // Ensure correct type conversion
  137. collectionView.selectionIndexPaths = tIndexPaths
  138. }
  139. public func reversePages(indexs: IndexSet) {
  140. if let doc = showDocument {
  141. var theIdxs = indexs
  142. var res = false
  143. for _ in 0 ..< indexs.count {
  144. guard let first = theIdxs.first else {
  145. break
  146. }
  147. guard let last = theIdxs.last else {
  148. break
  149. }
  150. if first == last {
  151. break
  152. }
  153. res = doc.exchangePage(at: UInt(first), withPageAt: UInt(last))
  154. if res {
  155. theIdxs.remove(first)
  156. theIdxs.remove(last)
  157. }
  158. }
  159. if res {
  160. refreshDatas()
  161. let selected_indexpaths = self.indexsToIndexpaths(indexs: indexs)
  162. collectionView.reloadItems(at: selected_indexpaths)
  163. collectionView.selectionIndexPaths = selected_indexpaths
  164. }
  165. }
  166. }
  167. public func replacePages(of targetIndexpaths: Set<IndexPath>, with documents: [CPDFDocument]) {
  168. if (targetIndexpaths.count == 0 || documents.count == 0) {
  169. KMPrint("replace invalid.")
  170. return
  171. }
  172. var index = targetIndexpaths.sorted().first!.item
  173. var tIndexPaths: Set<IndexPath> = []
  174. var indexSet = indexpathsToIndexs(indexpaths: targetIndexpaths)
  175. showDocument?.removePage(at: indexSet)
  176. for document in documents {
  177. for i in 0 ..< document.pageCount {
  178. let page = document.page(at: i)
  179. self.showDocument?.insertPageObject(page, at: UInt(index))
  180. tIndexPaths.insert(IndexPath(item: index, section: 0))
  181. index += 1
  182. }
  183. thumbnailBaseViewDelegate?.insertPDFThumbnailViewControlle?(pageEditVC: self, pdfDocment: document)
  184. }
  185. refreshDatas()
  186. collectionView.reloadData()
  187. collectionView.selectionIndexPaths = tIndexPaths
  188. }
  189. public func deletePages(indexpaths:Set<IndexPath>) {
  190. var changeIndex:IndexSet = []
  191. var tIndexPaths: Set<IndexPath> = []
  192. tIndexPaths = indexpaths
  193. for targetIndexPath in tIndexPaths {
  194. changeIndex.insert(targetIndexPath.item)
  195. let cellView = collectionView.item(at: targetIndexPath) as? KMNThumbnailCollectionViewItem
  196. if(cellView != nil) {
  197. cellView?.thumbnailMode.removeCacheImage()
  198. }
  199. }
  200. showDocument?.removePage(at: changeIndex)
  201. refreshDatas()
  202. collectionView.deleteItems(at: tIndexPaths)
  203. }
  204. public func movePages(pages:[CPDFPage],destinationDex:Int) {
  205. var destinationIndex = destinationDex
  206. for dragPage in dragLocalityPages {
  207. let dragIndex = dragPage.pageIndex()
  208. if destinationIndex > dragIndex {
  209. destinationIndex -= 1
  210. showDocument?.movePage(at: dragIndex, withPageAt: UInt(destinationIndex))
  211. } else {
  212. showDocument?.movePage(at: dragIndex, withPageAt: UInt(destinationIndex))
  213. }
  214. destinationIndex += 1
  215. }
  216. var selectArray:[Int] = []
  217. for dragPage in dragLocalityPages {
  218. let dragIndex = dragPage.pageIndex()
  219. selectArray.append(Int(dragIndex))
  220. }
  221. refreshDatas()
  222. collectionView.reloadData()
  223. self.selectPages(with: selectArray)
  224. }
  225. public func insertFromFilePath(fileNames:[String],formDex:Int,indexDex:UInt,selectIndexs:[Int],completionBlock:@escaping ([Int])->Void)-> Void {
  226. let path = fileNames[formDex]
  227. var insertDex = indexDex
  228. var tSelectIndex = selectIndexs
  229. let pathExtension = URL(fileURLWithPath: path).pathExtension.lowercased()
  230. if pathExtension == "pdf", let pdf = CPDFDocument(url: URL(fileURLWithPath: path)) {
  231. if pdf.isLocked {
  232. KMNBaseWindowController.checkPassword(url: pdf.documentURL, type: .owner) { success, resultPassword in
  233. if (resultPassword.isEmpty == false) {
  234. pdf.unlock(withPassword: resultPassword)
  235. for i in 0 ..< pdf.pageCount {
  236. let insertPage = pdf.page(at: i)
  237. self.showDocument?.insertPageObject(insertPage, at: insertDex)
  238. tSelectIndex.append(Int(insertDex))
  239. insertDex += 1
  240. }
  241. var tFormDex = formDex
  242. tFormDex += 1
  243. self.thumbnailBaseViewDelegate?.insertPDFThumbnailViewControlle?(pageEditVC: self, pdfDocment: pdf)
  244. if(tFormDex < fileNames.count) {
  245. return self.insertFromFilePath(fileNames: fileNames, formDex: tFormDex, indexDex: indexDex, selectIndexs: tSelectIndex,completionBlock: completionBlock)
  246. } else {
  247. return completionBlock(tSelectIndex)
  248. }
  249. }
  250. }
  251. } else {
  252. for i in 0 ..< pdf.pageCount {
  253. let insertPage = pdf.page(at: i)
  254. showDocument?.insertPageObject(insertPage ?? CPDFPage(), at: insertDex)
  255. tSelectIndex.append(Int(insertDex))
  256. insertDex += 1
  257. }
  258. var tFormDex = formDex
  259. tFormDex += 1
  260. self.thumbnailBaseViewDelegate?.insertPDFThumbnailViewControlle?(pageEditVC: self, pdfDocment: pdf)
  261. if(tFormDex < fileNames.count) {
  262. return self.insertFromFilePath(fileNames: fileNames, formDex: tFormDex, indexDex: indexDex, selectIndexs: tSelectIndex,completionBlock: completionBlock)
  263. } else {
  264. return completionBlock(tSelectIndex)
  265. }
  266. }
  267. } else if supportDragFileTypes().contains(pathExtension) {
  268. if KMConvertPDFManager.supportImages().contains(pathExtension) {
  269. let isSueccessFul = insertImageFilePath(imagePath: path, pageDex: Int(indexDex))
  270. if(isSueccessFul) {
  271. tSelectIndex.append(Int(insertDex))
  272. insertDex += 1
  273. }
  274. var tFormDex = formDex
  275. tFormDex += 1
  276. if(tFormDex < fileNames.count) {
  277. return self.insertFromFilePath(fileNames: fileNames, formDex: tFormDex, indexDex: indexDex, selectIndexs: tSelectIndex,completionBlock: completionBlock)
  278. } else {
  279. return completionBlock(tSelectIndex)
  280. }
  281. } else {
  282. convertOffice(filePath: path) { convertPDFPath in
  283. if (convertPDFPath != nil) {
  284. let pathExtension = URL(fileURLWithPath: convertPDFPath!).pathExtension.lowercased()
  285. if pathExtension == "pdf", let pdf = CPDFDocument(url: URL(fileURLWithPath: convertPDFPath!)) {
  286. for i in 0 ..< pdf.pageCount {
  287. let insertPage = pdf.page(at: i)
  288. self.showDocument?.insertPageObject(insertPage, at: insertDex)
  289. tSelectIndex.append(Int(insertDex))
  290. insertDex += 1
  291. }
  292. self.thumbnailBaseViewDelegate?.insertPDFThumbnailViewControlle?(pageEditVC: self, pdfDocment: pdf)
  293. var tFormDex = formDex
  294. tFormDex += 1
  295. if(tFormDex < fileNames.count) {
  296. return self.insertFromFilePath(fileNames: fileNames, formDex: tFormDex, indexDex: indexDex, selectIndexs: tSelectIndex,completionBlock: completionBlock)
  297. } else {
  298. return completionBlock(tSelectIndex)
  299. }
  300. }
  301. }
  302. }
  303. }
  304. }
  305. }
  306. private func convertOffice(filePath: String, completionBlock:@escaping (String?)->Void) -> Void {
  307. let today = Date()
  308. let dateFormatter = DateFormatter()
  309. dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
  310. let dateString = dateFormatter.string(from: today)
  311. let folderPath = "convertToPDF_office_" + dateString + "." + "pdf"
  312. let savePath: String? = folderPath.kUrlToPDFFolderPath() as String
  313. KMConvertPDFManager.convertFile(filePath, savePath: savePath!) { success, errorDic in
  314. if errorDic != nil || !success || !FileManager.default.fileExists(atPath: savePath!) {
  315. if FileManager.default.fileExists(atPath: savePath!) {
  316. try?FileManager.default.removeItem(atPath: savePath!)
  317. }
  318. let alert = NSAlert.init()
  319. alert.alertStyle = .critical
  320. var infoString = ""
  321. if errorDic != nil {
  322. for key in (errorDic! as Dictionary).keys {
  323. infoString = infoString.appendingFormat("%@\n", errorDic![key] as! CVarArg)
  324. }
  325. }
  326. alert.informativeText = NSLocalizedString("Please install Microsoft Office to create PDFs from Office files", comment: "")
  327. alert.messageText = NSLocalizedString("Failed to Create PDF", comment: "")
  328. alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
  329. alert.runModal()
  330. completionBlock(nil)
  331. return
  332. }
  333. if !savePath!.isPDFValid() {
  334. let alert = NSAlert()
  335. alert.alertStyle = .critical
  336. alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "")
  337. alert.runModal()
  338. completionBlock(nil)
  339. return
  340. }
  341. completionBlock(savePath)
  342. }
  343. }
  344. public func extractPages(indexpaths: Set<IndexPath>, oneDocumentPerPage: Bool, callback: @escaping KMResultBlock) {
  345. let pageIndexs = self.indexpathsToIndexs(indexpaths: indexpaths)
  346. let oneDocument = !oneDocumentPerPage
  347. let document = self.showDocument!
  348. /// 提取的页面
  349. var extractPages: Array<CPDFPage> = []
  350. for i in pageIndexs {
  351. extractPages.append(document.page(at: UInt(i)))
  352. }
  353. if (oneDocument) { /// 提取为一个文档
  354. var fileName = document.documentURL.deletingPathExtension().lastPathComponent
  355. fileName.append(" pages ")
  356. fileName.append(KMNTools.newParseSelectedIndexs(selectedIndex: pageIndexs.sorted()))
  357. fileName.append(".pdf")
  358. NSPanel.savePanel(self.view.window!, true) { panel in
  359. panel.nameFieldStringValue = fileName
  360. } completion: { response, url, isOpen in
  361. if (response != .OK) {
  362. callback(.cancel)
  363. return
  364. }
  365. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
  366. DispatchQueue.global().async {
  367. var success = false
  368. let pdf = CPDFDocument.init()
  369. success = pdf!.extractAsOneDocument(withPages: extractPages, savePath: url!.path)
  370. DispatchQueue.main.async {
  371. if (success == false) {
  372. callback(.failure)
  373. return
  374. }
  375. if (isOpen == false) {
  376. NSWorkspace.shared.activateFileViewerSelecting([url!])
  377. } else {
  378. NSDocumentController.shared.km_safe_openDocument(withContentsOf: url!, display: true) { _, _, _ in
  379. }
  380. }
  381. callback(.success, [url!])
  382. }
  383. }
  384. }
  385. }
  386. return
  387. } else {
  388. let panel = NSOpenPanel()
  389. panel.canChooseFiles = false
  390. panel.canChooseDirectories = true
  391. panel.canCreateDirectories = true
  392. panel.allowsMultipleSelection = false
  393. panel.beginSheetModal(for: self.view.window!) { response in
  394. if response != .OK {
  395. callback(.cancel)
  396. return
  397. }
  398. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
  399. let outputURL = panel.url
  400. DispatchQueue.global().async {
  401. let folderName = String((document.documentURL.lastPathComponent.split(separator: ".")[0])) + "_extract"
  402. var filePath = URL(fileURLWithPath: outputURL!.path).appendingPathComponent(folderName).path
  403. var i = 1
  404. let testFilePath = filePath
  405. while FileManager.default.fileExists(atPath: filePath) {
  406. filePath = testFilePath + "\(i)"
  407. i += 1
  408. }
  409. try? FileManager.default.createDirectory(atPath: filePath, withIntermediateDirectories: false, attributes: nil)
  410. var successArray: [URL]?
  411. successArray = document.extractPerPageDocument(withPages: extractPages, folerPath: filePath)
  412. DispatchQueue.main.async {
  413. if successArray!.count == 0 {
  414. callback(.failure)
  415. return
  416. }
  417. NSWorkspace.shared.activateFileViewerSelecting(successArray!)
  418. callback(.success, successArray ?? NSURL())
  419. }
  420. }
  421. }
  422. }
  423. }
  424. }
  425. }