// // KMExtractImageWindowController.swift // PDF Reader Pro // // Created by liujiajie on 2023/11/17. // import Cocoa class KMExtractImageWindowController: NSWindowController,PDFConvertObjectDelegate,NSTextFieldDelegate{ var docPath: String = "" var password: String = "" var currentPage: Int = 0 var maskView: KMBookletMaskView? @IBOutlet var rangeTipLabel: NSTextField! @IBOutlet var rangeTextField: NSTextField! @IBOutlet var allPageButton: NSButton! @IBOutlet var currentPageButton: NSButton! @IBOutlet var singlePageButton: NSButton! @IBOutlet var doublePageButton: NSButton! @IBOutlet var customPageButton: NSButton! @IBOutlet var extractImageButton: NSButton! @IBOutlet var cancelButton: NSButton! @IBOutlet var customTextField: NSTextField! @IBOutlet var totalImagesTextField: NSTextField! lazy var pdfDocument: CPDFDocument? = { var pdfDoc = CPDFDocument(url: URL(fileURLWithPath: self.docPath)) if (self.password.count > 0){ pdfDoc?.unlock(withPassword: self.password) } return pdfDoc }() var selectPagesIndex: Int = 0 // var pdfConverter: PDFConvertObject? lazy var pdfConverter: PDFConvertObject? = { let conerter = PDFConvertObject() return conerter }() @IBOutlet var currentPageTextField: NSTextField! @IBOutlet var pageCountTextField: NSTextField! @IBOutlet var pdfViewBG: NSView! var preViewPDFView: CPDFView! private var fileAttri_: KMFileAttribute? deinit { NotificationCenter.default.removeObserver(self) } override func windowDidLoad() { super.windowDidLoad() let preView: CPDFView = CPDFView(frame: self.pdfViewBG.bounds) self.pdfViewBG.addSubview(preView) self.preViewPDFView = preView configUI() } func configUI() { if !self.docPath.isEmpty && self.docPath.count > 0 { let url = URL(fileURLWithPath: docPath) let document = CPDFDocument(url: url) if self.password.count > 0 { document?.unlock(withPassword: password) } self.preViewPDFView.document = document self.preViewPDFView.autoScales = true self.preViewPDFView.layoutDocumentView() self.preViewPDFView.go(toPageIndex: self.currentPage, animated: true) self.fileAttri_ = KMFileAttribute() self.fileAttri_?.filePath = url.path } self.allPageButton.title = NSLocalizedString("All Pages", comment: "") self.singlePageButton.title = NSLocalizedString("Odd Pages Only", comment: "") self.doublePageButton.title = NSLocalizedString("Even Pages Only", comment: "") self.currentPageButton.title = NSLocalizedString("Current Page", comment: "") self.extractImageButton.title = NSLocalizedString("Extract", comment: "") self.cancelButton.title = NSLocalizedString("Cancel", comment: "") self.rangeTextField.placeholderString = NSLocalizedString("e.g. 1,3-5,10", comment: "") self.rangeTipLabel.stringValue = NSLocalizedString("Page Range", comment: "") self.currentPageTextField.stringValue = "\(self.currentPage + 1)" self.pageCountTextField.stringValue = "/ \(self.pdfDocument?.pageCount ?? 0)" self.customTextField.stringValue = self.pageCountTextField.stringValue self.selectPagesIndex = 0 self.rangeTextField.isEnabled = false self.customTextField.isEnabled = false self.allPageButton.state = NSControl.StateValue.on if self.pdfDocument?.pageCount ?? 0 < 2 { self.doublePageButton.isEnabled = false } else { self.doublePageButton.isEnabled = true } self.preViewPDFView.setDisplay(.singlePage) self.preViewPDFView.layoutDocumentView() NotificationCenter.default.addObserver(self, selector: #selector(pageChangeNotification(notification:)), name: NSNotification.Name.PDFViewPageChanged, object: self.preViewPDFView) } func selectCurrentPageBtn() { self.customPageButton_Action(self.currentPageButton) } @IBAction func customPageButton_Action(_ sender: NSButton) { self.allPageButton.state = NSControl.StateValue.off self.currentPageButton.state = NSControl.StateValue.off self.singlePageButton.state = NSControl.StateValue.off self.doublePageButton.state = NSControl.StateValue.off self.customPageButton.state = NSControl.StateValue.off sender.state = NSControl.StateValue.on self.rangeTextField.isEnabled = false self.customTextField.textColor = NSColor.disabledControlTextColor self.selectPagesIndex = sender.tag if sender.tag == 3 { self.rangeTextField.isEnabled = true self.customTextField.textColor = NSColor.labelColor self.window?.makeFirstResponder(self.rangeTextField) if self.rangeTextField.stringValue.isEmpty { return } } } @IBAction func extractImageButton_Action(_ sender: Any) { startExtracting() } @IBAction func cancleButton_Action(_ sender: Any) { self.window?.sheetParent?.endSheet(self.window!) } @IBAction func nextPage_Action(_ sender: Any) { if self.preViewPDFView.canGoToNextPage() { self.preViewPDFView.goToNextPage(sender) } let index = self.preViewPDFView.document.index(for: self.preViewPDFView.currentPage()) self.currentPageTextField.stringValue = "\(index + 1)" } @IBAction func previousPage_Action(_ sender: Any) { if self.preViewPDFView.canGoToPreviousPage() { self.preViewPDFView.goToPreviousPage(sender) } let index = self.preViewPDFView.document.index(for: self.preViewPDFView.currentPage()) self.currentPageTextField.stringValue = "\(index + 1)" } override func close() { if ((self.window?.isSheet) != nil) { self.window?.sheetParent?.endSheet(self.window!) } else { super.close() } } func startExtracting() { let indeSet = self.selectIndexSet() if indeSet.count == 0 { return } let lastPathName = self.pdfDocument?.documentURL.deletingPathExtension().lastPathComponent ?? "" var tFileName = (String(format: "%@_Extract Images", lastPathName)) let outputSavePanel = NSSavePanel() if let data = outputSavePanel.directoryURL?.appendingPathComponent(tFileName) { let fileUrl = self.fetchUniquePath(data.path) tFileName = fileUrl.lastPathComponent } outputSavePanel.title = NSLocalizedString("Save as PDF", comment: "") outputSavePanel.allowsOtherFileTypes = true outputSavePanel.isExtensionHidden = true outputSavePanel.canCreateDirectories = true outputSavePanel.nameFieldStringValue = tFileName outputSavePanel.beginSheetModal(for: self.window!) {(result) in if result == NSApplication.ModalResponse.OK { self.showWaitting() DispatchQueue.main.async { let tDestFile = outputSavePanel.url?.path ?? "" let uniquePath = KMExtractImageWindowController.createDestFolder(path: tDestFile, isUnique: false) self.pdfConverter?.extractResourcesFromPDF(at: self.docPath, pdfPassword: self.password, selectIndexSet: indeSet as IndexSet, destDocPath: uniquePath, moreOptions: nil) self.extractOK(tDestFile) } } } } func fetchUniquePath(_ originalPath: String) -> String { var path = originalPath let dManager = FileManager.default if !dManager.fileExists(atPath: path) { if path.extension.count < 1 { path = path.stringByAppendingPathExtension("pdf") } return path } else { let originalFullFileName = path.lastPathComponent let url = URL(fileURLWithPath: path) // let originalFileName = path.lastPathComponent.deletingPathExtension.lastPathComponent // let originalFileName = url.deletingPathExtension().lastPathComponent let originalFileName = originalFullFileName // let originalExtension = path.extension let startIndex: Int = 0 let endIndex: Int = startIndex + originalPath.count - originalFullFileName.count - 1 let fileLocatePath = originalPath.substring(to: endIndex) var i = 1 while (1 != 0) { var newName = String(format: "%@(%ld)", originalFileName, i) // newName = String(format: "%@%@", newName, originalExtension) let newPath = fileLocatePath.stringByAppendingPathComponent(newName) if !dManager.fileExists(atPath: newPath) { return newPath } else { i+=1 continue } } } } func extractOK(_ folder: String) { self.hideWaitting() self.close() if FileManager.default.fileExists(atPath: folder) { let workspace = NSWorkspace.shared let url = URL(fileURLWithPath: folder) workspace.activateFileViewerSelecting([url]) } } func selectIndexSet() -> NSMutableIndexSet { let pageCount = self.pdfDocument?.pageCount let indeSet = NSMutableIndexSet() if self.selectPagesIndex == 0 { for i in 0..<(pageCount ?? 0) { indeSet.add(IndexSet(integer: IndexSet.Element(i))) } } else if self.selectPagesIndex == 1 { for i in 0..<(pageCount ?? 0) { if i % 2 == 0 { indeSet.add(IndexSet(integer: IndexSet.Element(i))) } } } else if self.selectPagesIndex == 2 { for i in 0..<(pageCount ?? 0) { if i % 2 != 0 { indeSet.add(IndexSet(integer: IndexSet.Element(i))) } } } else if self.selectPagesIndex == 4 { if let index = self.preViewPDFView.document?.index(for: self.preViewPDFView.currentPage()!) { indeSet.add(IndexSet(integer: IndexSet.Element(index))) } } else { var fileAttribute = self.fileAttri_ if fileAttribute == nil { self.fileAttri_ = KMFileAttribute() self.fileAttri_?.filePath = self.preViewPDFView.document?.documentURL?.path ?? "" fileAttribute = self.fileAttri_ } fileAttribute?.bAllPage = false if (self.customPageButton.state == .on){ fileAttribute?.pagesType = .custom } fileAttribute?.pagesString = self.rangeTextField.stringValue if let data = fileAttribute?.fetchSelectPages().isEmpty, data { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "\(fileAttribute?.filePath.lastPathComponent ?? "") \(NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: ""))" alert.runModal() return indeSet } for num in fileAttribute?.fetchSelectPages() ?? [] { indeSet.add(num-1) } } return indeSet } class func createDestFolder(path: String, isUnique: Bool) -> String { var ret = true var tUniqueName: String? = nil let tFileManager = FileManager.default if isUnique { tUniqueName = getUniqueFilePath(filePath: path) } else { tUniqueName = path } if !tFileManager.fileExists(atPath: tUniqueName!) { do { try tFileManager.createDirectory(atPath: tUniqueName!, withIntermediateDirectories: true, attributes: nil) } catch { ret = false } } return tUniqueName! } class func getUniqueFilePath(filePath: String) -> String { var i = 0 var isDirectory = ObjCBool(false) var uniqueFilePath = filePath let filemanager = FileManager.default filemanager.fileExists(atPath: uniqueFilePath, isDirectory: &isDirectory) if isDirectory.boolValue { while filemanager.fileExists(atPath: uniqueFilePath) { i += 1 uniqueFilePath = "\(filePath)(\(i))" } } else { while filemanager.fileExists(atPath: uniqueFilePath) { i += 1 let path = "\(filePath.deletingPathExtension)(\(i))" uniqueFilePath = path.stringByAppendingPathExtension(filePath.customPathExtension) } } return uniqueFilePath } @objc func pageChangeNotification(notification: Notification) { self.currentPageTextField.stringValue = self.preViewPDFView.currentPage().label ?? "" } func controlTextDidEndEditing(_ obj: Notification) { if obj.object as? NSTextField == self.currentPageTextField { if let intValue = Int(self.currentPageTextField.stringValue), intValue > (self.preViewPDFView.document?.pageCount ?? 0) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = String(format: "%@%@", self.preViewPDFView.document.documentURL.lastPathComponent.lastPathComponent,KMLocalizedString("Invalid page range or the page number is out of range. Please try again.")) alert.beginSheetModal(for: NSApp.mainWindow!, completionHandler: nil) return } self.preViewPDFView.go(to: self.preViewPDFView.document?.page(at: UInt((Int(self.currentPageTextField.stringValue) ?? 0) - 1))) } else if obj.object as? NSTextField == self.rangeTextField { if !checkPageRangeValidate(self.rangeTextField.stringValue) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = String(format: "%@%@", self.preViewPDFView.document.documentURL.lastPathComponent.lastPathComponent,KMLocalizedString("Invalid page range or the page number is out of range. Please try again.")) alert.beginSheetModal(for: NSApp.mainWindow!, completionHandler: nil) return } } } func checkPageRangeValidate(_ pageRangeString: String) -> Bool { var fileAttribute = self.fileAttri_ if fileAttribute == nil { self.fileAttri_ = KMFileAttribute() self.fileAttri_?.filePath = self.preViewPDFView.document?.documentURL?.path ?? "" fileAttribute = self.fileAttri_ } fileAttribute?.bAllPage = false fileAttribute?.pagesString = self.rangeTextField.stringValue let isEmpty = fileAttribute?.fetchSelectPages().isEmpty ?? true let cnt = fileAttribute?.fetchSelectPages().count ?? 0 if isEmpty || cnt < 1{ return false } return true } override func mouseDown(with event: NSEvent) { super.mouseDown(with: event) self.window?.makeFirstResponder(nil) } @objc func pageChangeNotification(_ notification: Notification) { self.currentPageTextField.stringValue = self.preViewPDFView.currentPage().label ?? "" } func PDFConvertObject2(_ converter: PDFConvertObject, didEndConversion error: Error?) { self.hideWaitting() self.window?.sheetParent?.endSheet(self.window!) } func showWaitting() { if self.maskView == nil { self.maskView = KMBookletMaskView(frame: CGRect(x: 0, y: 0, width: self.window?.frame.size.width ?? 0, height: self.window?.frame.size.height ?? 0)) } self.window?.contentView?.addSubview(self.maskView!) } func hideWaitting() { self.maskView?.removeFromSuperview() } func beginSheetModal(for window: NSWindow, completionHandler handler: ((NSInteger) -> Void)?) { self.window?.beginSheet(window, completionHandler: { returnCode in NSApp.endSheet(self.window!, returnCode: NSApplication.ModalResponse.abort.rawValue) if let handler = handler { handler(returnCode.rawValue) } }) } }