// // KMMainViewController+Action.swift // PDF Reader Pro // // Created by wanjun on 2022/12/15. // import Foundation extension KMNThumbnailBaseViewController { public func fileNameWithSelectedPages(_ itemIndexes: IndexSet) -> String { var pagesName = "" if (itemIndexes.count > 1) { pagesName.append(" pages") } else { pagesName.append(" page") } let docmentName = showDocument?.documentURL.deletingPathExtension().lastPathComponent ?? "" let tFileName = String(format: "%@ %@", pagesName,KMNTools.parseIndexSet(indexSet: itemIndexes)) return String(format: "%@%@", docmentName,tFileName) } private func convertTIFFDataToPDF(_ tiffData: Data) -> Data? { guard let imsrc = CGImageSourceCreateWithData(tiffData as CFData, [kCGImageSourceTypeIdentifierHint: kUTTypeTIFF] as CFDictionary), CGImageSourceGetCount(imsrc) > 0, let cgImage = CGImageSourceCreateImageAtIndex(imsrc, 0, nil) else { return nil } let pdfData = NSMutableData(capacity: tiffData.count) let consumer = CGDataConsumer(data: pdfData! as CFMutableData)! var rect = CGRect(x: 0, y: 0, width: CGFloat(cgImage.width), height: CGFloat(cgImage.height)) let ctxt = CGContext(consumer: consumer, mediaBox: &rect, nil) ctxt!.beginPDFPage(nil) ctxt!.draw(cgImage, in: rect) ctxt!.endPDFPage() ctxt!.closePDF() return pdfData as? Data } public func selectPages(with array: [Int]) { var selectIndexPaths: Set = [] for i in 0..<(showDocument?.pageCount ?? 0) { if array.contains(Int(i)) { selectIndexPaths.insert(IndexPath(item: Int(i), section: 0)) } } collectionView.selectionIndexPaths = selectIndexPaths if selectIndexPaths.isEmpty { return } let firstIndexPath = selectIndexPaths.first collectionView.scrollToItems(at: [firstIndexPath ?? IndexPath(item: 0, section: 0)], scrollPosition: .top) } public func indexpathsToIndexs(indexpaths: Set) -> IndexSet { var indexs = IndexSet() for indexPath in indexpaths { indexs.insert(indexPath.item) } return indexs } public func indexsToIndexpaths(indexs: IndexSet) -> Set { var indexpaths = Set() for index in indexs { indexpaths.insert(IndexPath(item: index, section: 0)) } return indexpaths } public func insertFormPDF(insertPages: [CPDFPage],pageDex:Int) { var pageIndexDex: Int = pageDex var indexpaths = Set() for page in insertPages { let isSuccessFul = showDocument?.insertPageObject(page, at: UInt(pageIndexDex)) if(isSuccessFul == true) { indexpaths.insert(IndexPath(item: pageIndexDex, section: 0)) pageIndexDex += 1 } } refreshDatas() collectionView.reloadData() collectionView.scrollToItems(at: indexpaths, scrollPosition: .centeredVertically) collectionView.selectionIndexPaths = indexpaths } public func insertBlankPage(pageSize: CGSize,pageDex:Int) { var indexpaths = Set() let isSuccessFul = showDocument?.insertBlankPage(pageSize: pageSize, at: pageDex) if(isSuccessFul == true) { indexpaths.insert(IndexPath(item: pageDex, section: 0)) } refreshDatas() collectionView.reloadData() collectionView.scrollToItems(at: indexpaths, scrollPosition: .centeredVertically) collectionView.selectionIndexPaths = indexpaths } public func openDocumentWithImageFromPasteboard(_ pboard: NSPasteboard, error outError: AutoreleasingUnsafeMutablePointer?) -> CPDFDocument? { var document: CPDFDocument? = nil var data: Data? = nil if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.pdf.rawValue]) { data = pboard.data(forType: NSPasteboard.PasteboardType.pdf) } else if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.postScript.rawValue]) { data = pboard.data(forType: NSPasteboard.PasteboardType.postScript) } else if pboard.canReadItem(withDataConformingToTypes: [NSPasteboard.PasteboardType.tiff.rawValue]) { data = convertTIFFDataToPDF(pboard.data(forType: NSPasteboard.PasteboardType.tiff) ?? Data()) } else { let images = pboard.readObjects(forClasses: [NSImage.self], options: [:]) let strings = pboard.readObjects(forClasses: [NSAttributedString.self], options: [:]) if images?.count ?? 0 > 0 { data = convertTIFFDataToPDF((images![0] as AnyObject).tiffRepresentation!) } else if strings?.count ?? 0 > 0 { data = KMOCTool.convertStringsToPDF(withString: strings ?? [""]) // convertStringsToPDF(strings!) } } if let data = data { document = CPDFDocument(data: data) } else if let outError = outError { outError.pointee = NSError(domain: "SKDocumentErrorDomain", code: 3, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("Unable to load data from clipboard", comment: "Error description")]) } return document } public func insertImageFilePath(imagePath:String,pageDex:Int)->Bool{ var isSuccessFul:Bool = false if (FileManager.default.fileExists(atPath: imagePath)) { if let image = NSImage(contentsOfFile: imagePath) { isSuccessFul = showDocument?.km_insertPage(image.size, withImage: imagePath, at: UInt(pageDex)) == true } } return isSuccessFul } public func rotatePages(indexPaths: Set, rotateAngle: Int) { var tIndexPaths: Set = [] tIndexPaths = indexPaths for targetIndexPath in indexPaths { if let page = showDocument?.page(at: UInt(targetIndexPath.item)) { var pageRotate = page.rotation + rotateAngle if(pageRotate == -90) { pageRotate = 270 } else if (pageRotate == 450) { pageRotate = 90 } page.rotation = pageRotate let cellView = collectionView.item(at: targetIndexPath) as? KMNThumbnailCollectionViewItem if(cellView != nil) { cellView?.thumbnailMode.removeCacheImage() } } } collectionView.reloadItems(at: tIndexPaths) // Ensure correct type conversion collectionView.selectionIndexPaths = tIndexPaths } public func reversePages(indexs: IndexSet) { if let doc = showDocument { var theIdxs = indexs var res = false for _ in 0 ..< indexs.count { guard let first = theIdxs.first else { break } guard let last = theIdxs.last else { break } if first == last { break } res = doc.exchangePage(at: UInt(first), withPageAt: UInt(last)) if res { theIdxs.remove(first) theIdxs.remove(last) } } if res { refreshDatas() let selected_indexpaths = self.indexsToIndexpaths(indexs: indexs) collectionView.reloadItems(at: selected_indexpaths) collectionView.selectionIndexPaths = selected_indexpaths } } } public func replacePages(of targetIndexpaths: Set, with documents: [CPDFDocument]) { if (targetIndexpaths.count == 0 || documents.count == 0) { KMPrint("replace invalid.") return } var index = targetIndexpaths.sorted().first!.item var tIndexPaths: Set = [] var indexSet = indexpathsToIndexs(indexpaths: targetIndexpaths) showDocument?.removePage(at: indexSet) for document in documents { for i in 0 ..< document.pageCount { let page = document.page(at: i) self.showDocument?.insertPageObject(page, at: UInt(index)) tIndexPaths.insert(IndexPath(item: index, section: 0)) index += 1 } thumbnailBaseViewDelegate?.insertPDFThumbnailViewControlle?(pageEditVC: self, pdfDocment: document) } refreshDatas() collectionView.reloadData() collectionView.selectionIndexPaths = tIndexPaths } public func deletePages(indexpaths:Set) { var changeIndex:IndexSet = [] var tIndexPaths: Set = [] tIndexPaths = indexpaths for targetIndexPath in tIndexPaths { changeIndex.insert(targetIndexPath.item) let cellView = collectionView.item(at: targetIndexPath) as? KMNThumbnailCollectionViewItem if(cellView != nil) { cellView?.thumbnailMode.removeCacheImage() } } showDocument?.removePage(at: changeIndex) refreshDatas() collectionView.deleteItems(at: tIndexPaths) } public func movePages(pages:[CPDFPage],destinationDex:Int) { var destinationIndex = destinationDex for dragPage in dragLocalityPages { let dragIndex = dragPage.pageIndex() if destinationIndex > dragIndex { destinationIndex -= 1 showDocument?.movePage(at: dragIndex, withPageAt: UInt(destinationIndex)) } else { showDocument?.movePage(at: dragIndex, withPageAt: UInt(destinationIndex)) } destinationIndex += 1 } var selectArray:[Int] = [] for dragPage in dragLocalityPages { let dragIndex = dragPage.pageIndex() selectArray.append(Int(dragIndex)) } refreshDatas() collectionView.reloadData() self.selectPages(with: selectArray) } public func insertFromFilePath(fileNames:[String],formDex:Int,indexDex:UInt,selectIndexs:[Int],completionBlock:@escaping ([Int])->Void)-> Void { let path = fileNames[formDex] var insertDex = indexDex var tSelectIndex = selectIndexs let pathExtension = URL(fileURLWithPath: path).pathExtension.lowercased() if pathExtension == "pdf", let pdf = CPDFDocument(url: URL(fileURLWithPath: path)) { if pdf.isLocked { KMNBaseWindowController.checkPassword(url: pdf.documentURL, type: .owner) { success, resultPassword in if (resultPassword.isEmpty == false) { pdf.unlock(withPassword: resultPassword) for i in 0 ..< pdf.pageCount { let insertPage = pdf.page(at: i) self.showDocument?.insertPageObject(insertPage, at: insertDex) tSelectIndex.append(Int(insertDex)) insertDex += 1 } var tFormDex = formDex tFormDex += 1 self.thumbnailBaseViewDelegate?.insertPDFThumbnailViewControlle?(pageEditVC: self, pdfDocment: pdf) if(tFormDex < fileNames.count) { return self.insertFromFilePath(fileNames: fileNames, formDex: tFormDex, indexDex: indexDex, selectIndexs: tSelectIndex,completionBlock: completionBlock) } else { return completionBlock(tSelectIndex) } } } } else { for i in 0 ..< pdf.pageCount { let insertPage = pdf.page(at: i) showDocument?.insertPageObject(insertPage ?? CPDFPage(), at: insertDex) tSelectIndex.append(Int(insertDex)) insertDex += 1 } var tFormDex = formDex tFormDex += 1 self.thumbnailBaseViewDelegate?.insertPDFThumbnailViewControlle?(pageEditVC: self, pdfDocment: pdf) if(tFormDex < fileNames.count) { return self.insertFromFilePath(fileNames: fileNames, formDex: tFormDex, indexDex: indexDex, selectIndexs: tSelectIndex,completionBlock: completionBlock) } else { return completionBlock(tSelectIndex) } } } else if supportDragFileTypes().contains(pathExtension) { if KMConvertPDFManager.supportImages().contains(pathExtension) { let isSueccessFul = insertImageFilePath(imagePath: path, pageDex: Int(indexDex)) if(isSueccessFul) { tSelectIndex.append(Int(insertDex)) insertDex += 1 } var tFormDex = formDex tFormDex += 1 if(tFormDex < fileNames.count) { return self.insertFromFilePath(fileNames: fileNames, formDex: tFormDex, indexDex: indexDex, selectIndexs: tSelectIndex,completionBlock: completionBlock) } else { return completionBlock(tSelectIndex) } } else { convertOffice(filePath: path) { convertPDFPath in if (convertPDFPath != nil) { let pathExtension = URL(fileURLWithPath: convertPDFPath!).pathExtension.lowercased() if pathExtension == "pdf", let pdf = CPDFDocument(url: URL(fileURLWithPath: convertPDFPath!)) { for i in 0 ..< pdf.pageCount { let insertPage = pdf.page(at: i) self.showDocument?.insertPageObject(insertPage, at: insertDex) tSelectIndex.append(Int(insertDex)) insertDex += 1 } self.thumbnailBaseViewDelegate?.insertPDFThumbnailViewControlle?(pageEditVC: self, pdfDocment: pdf) var tFormDex = formDex tFormDex += 1 if(tFormDex < fileNames.count) { return self.insertFromFilePath(fileNames: fileNames, formDex: tFormDex, indexDex: indexDex, selectIndexs: tSelectIndex,completionBlock: completionBlock) } else { return completionBlock(tSelectIndex) } } } } } } } private func convertOffice(filePath: String, completionBlock:@escaping (String?)->Void) -> Void { let today = Date() let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" let dateString = dateFormatter.string(from: today) let folderPath = "convertToPDF_office_" + dateString + "." + "pdf" let savePath: String? = folderPath.kUrlToPDFFolderPath() as String KMConvertPDFManager.convertFile(filePath, savePath: savePath!) { success, errorDic in if errorDic != nil || !success || !FileManager.default.fileExists(atPath: savePath!) { if FileManager.default.fileExists(atPath: savePath!) { try?FileManager.default.removeItem(atPath: savePath!) } let alert = NSAlert.init() alert.alertStyle = .critical var infoString = "" if errorDic != nil { for key in (errorDic! as Dictionary).keys { infoString = infoString.appendingFormat("%@\n", errorDic![key] as! CVarArg) } } alert.informativeText = NSLocalizedString("Please install Microsoft Office to create PDFs from Office files", comment: "") alert.messageText = NSLocalizedString("Failed to Create PDF", comment: "") alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) alert.runModal() completionBlock(nil) return } if !savePath!.isPDFValid() { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "") alert.runModal() completionBlock(nil) return } completionBlock(savePath) } } public func extractPages(indexpaths: Set, oneDocumentPerPage: Bool, callback: @escaping KMResultBlock) { let pageIndexs = self.indexpathsToIndexs(indexpaths: indexpaths) let oneDocument = !oneDocumentPerPage let document = self.showDocument! /// 提取的页面 var extractPages: Array = [] for i in pageIndexs { extractPages.append(document.page(at: UInt(i))) } if (oneDocument) { /// 提取为一个文档 var fileName = document.documentURL.deletingPathExtension().lastPathComponent fileName.append(" pages ") fileName.append(KMNTools.newParseSelectedIndexs(selectedIndex: pageIndexs.sorted())) fileName.append(".pdf") NSPanel.savePanel(self.view.window!, true) { panel in panel.nameFieldStringValue = fileName } completion: { response, url, isOpen in if (response != .OK) { callback(.cancel) return } DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { DispatchQueue.global().async { var success = false let pdf = CPDFDocument.init() success = pdf!.extractAsOneDocument(withPages: extractPages, savePath: url!.path) DispatchQueue.main.async { if (success == false) { callback(.failure) return } if (isOpen == false) { NSWorkspace.shared.activateFileViewerSelecting([url!]) } else { NSDocumentController.shared.km_safe_openDocument(withContentsOf: url!, display: true) { _, _, _ in } } callback(.success, [url!]) } } } } return } else { let panel = NSOpenPanel() panel.canChooseFiles = false panel.canChooseDirectories = true panel.canCreateDirectories = true panel.allowsMultipleSelection = false panel.beginSheetModal(for: self.view.window!) { response in if response != .OK { callback(.cancel) return } DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { let outputURL = panel.url DispatchQueue.global().async { let folderName = String((document.documentURL.lastPathComponent.split(separator: ".")[0])) + "_extract" var filePath = URL(fileURLWithPath: outputURL!.path).appendingPathComponent(folderName).path var i = 1 let testFilePath = filePath while FileManager.default.fileExists(atPath: filePath) { filePath = testFilePath + "\(i)" i += 1 } try? FileManager.default.createDirectory(atPath: filePath, withIntermediateDirectories: false, attributes: nil) var successArray: [URL]? successArray = document.extractPerPageDocument(withPages: extractPages, folerPath: filePath) DispatchQueue.main.async { if successArray!.count == 0 { callback(.failure) return } NSWorkspace.shared.activateFileViewerSelecting(successArray!) callback(.success, successArray ?? NSURL()) } } } } } } }