// // KMOCRPDFWindowController.swift // PDF Reader Pro // // Created by liujiajie on 2023/11/14. // import Cocoa import PDFKit class KMOCRPDFWindowController: NSWindowController, NSWindowDelegate, KMGOCRManagerDelegate, NSPopoverDelegate,NSTextFieldDelegate{ @IBOutlet var prePdfBGView: NSView! @IBOutlet var currentPageLabel: NSTextField! @IBOutlet var totalPageLabel: NSTextField! @IBOutlet var pageLabel: NSTextField! @IBOutlet var planLabel: NSTextField! @IBOutlet var ocrCopyButton: NSButton! @IBOutlet var pageRangeBox: NSComboBox! @IBOutlet var planComboBox: NSPopUpButton! @IBOutlet var progressIndicator: NSProgressIndicator! @IBOutlet var progressControl: NSProgressIndicator! @IBOutlet var failedBox: NSBox! @IBOutlet var failedLabel: NSTextField! @IBOutlet var cancelButton: NSButton! @IBOutlet var startButton: NSButton! @IBOutlet var languageLabel: NSTextField! @IBOutlet var ocrResultLabel: NSTextField! @IBOutlet var languageButton: NSButton! @IBOutlet var txtTextView: NSTextView! @IBOutlet var deleteButton: NSButton! @IBOutlet var emptyBox: NSBox! @IBOutlet var emptyLabel: NSTextField! @IBOutlet var saveButton: NSButton! @IBOutlet var box1: NSBox! @IBOutlet var boxLabel1: NSTextField! @IBOutlet var previewLabel: NSTextField! @IBOutlet var savePDFButton: NSButton! var resultString: String = "" var ocrDictionary: NSMutableDictionary? var currentIndexPage: Int = 0 var PDFView: CPDFView! var errorOCRArrays: Array? var pageIndexs: Array? var password: String = "" var pathFile: String = "" var pdfDocument: CPDFDocument? var ocrCurrentIndex: Int = 0 var appleOCRManger: KMGOCRManager? var googleOCRManger: KMGOCRManager? var savedFileName: String = "" private var _fileAttri: KMFileAttribute? func getOCRResrultsFolderPath() -> String { var path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last path?.append("/") path?.append(Bundle.main.bundleIdentifier!) if (FileManager.default.fileExists(atPath: path!) == false) { try?FileManager.default.createDirectory(atPath: path!, withIntermediateDirectories: false) } path?.append("/") path?.append("OCR_Resrults") return path! } func releaseSomething() { KMGOCRManager.default().delegate = nil appleOCRManger?.cancelRecognition() appleOCRManger?.delegate = nil googleOCRManger?.cancelRecognition() googleOCRManger?.delegate = nil self.PDFView.document = nil } convenience init(cpdfDocument: CPDFDocument, pwd: String?) { self.init(windowNibName: "KMOCRPDFWindowController") self.pdfDocument = cpdfDocument self.password = pwd ?? "" let url: URL? = cpdfDocument.documentURL let lastPathComponent = url?.deletingPathExtension() if let str = lastPathComponent?.lastPathComponent { if str.count > 0 { self.pathFile = str }else { self.pathFile = NSLocalizedString("Untitled", comment: "") } } else { self.pathFile = NSLocalizedString("Untitled", comment: "") } self._fileAttri = KMFileAttribute() self._fileAttri?.password = self.pdfDocument?.password ?? "" if self.pdfDocument?.documentURL != nil && self.pdfDocument?.documentURL.path != nil{ self._fileAttri?.filePath = self.pdfDocument?.documentURL.path ?? "" }else { self._fileAttri?.filePath = "" } } convenience init(filePath: String, pwd: String?) { self.init(windowNibName: "KMOCRPDFWindowController") self.password = pwd ?? "" let pathExtension = filePath.lastPathComponent.customPathExtension if pathExtension.count > 0{ if pathExtension.lowercased() == "pdf" { pdfDocument = CPDFDocument(url: URL(fileURLWithPath: filePath)) } else { if let image = NSImage(contentsOf: URL(fileURLWithPath: filePath)) { self.pdfDocument = CPDFDocument() _ = pdfDocument?.km_insertPage(image.size, withImage: filePath, at: pdfDocument?.pageCount ?? 0) } } } self.pathFile = filePath.lastPathComponent.deletingPathExtension self._fileAttri = KMFileAttribute() self._fileAttri?.password = self.pdfDocument?.password ?? "" self._fileAttri?.filePath = self.pdfDocument?.documentURL.path ?? "" } deinit { NotificationCenter.default.removeObserver(self) releaseSomething() } override func windowDidLoad() { super.windowDidLoad() let preView: CPDFView = CPDFView(frame: self.prePdfBGView.bounds) self.prePdfBGView.addSubview(preView) self.PDFView = preView self.PDFView.setDisplay(.singlePage) //self.displayViewMode = CPDFDisplayViewSinglePageContinuous; self.pageLabel.stringValue = NSLocalizedString("Page Range", comment: "") self.planLabel.stringValue = NSLocalizedString("OCR Plan", comment: "") self.planComboBox.removeAllItems() self.planComboBox.addItems(withTitles: [NSLocalizedString("Plan 1 (Online)", comment: ""), NSLocalizedString("Plan 2 (Offline)", comment: "")]) let plan = UserDefaults.standard.integer(forKey: "KMOCRCurrentPlanKey") if plan == 0 { KMGOCRManager.default().ocrType = .google self.planComboBox.selectItem(at: 0) } else { KMGOCRManager.default().ocrType = .apple self.planComboBox.selectItem(at: 1) } self.pageRangeBox.addItems(withObjectValues: [NSLocalizedString("All Pages", comment: ""), NSLocalizedString("Current Page", comment: ""), NSLocalizedString("Odd Pages Only", comment: ""), NSLocalizedString("Even Pages Only", comment: ""), NSLocalizedString("e.g. 1,3-5,10", comment: "")]) self.pageRangeBox.placeholderString = NSLocalizedString("e.g. 1,3-5,10", comment: "") self.pageRangeBox.selectItem(at: 0) self.pageRangeBox.isEditable = false if self.pageRangeBox.indexOfSelectedItem == 4 { self.window?.makeFirstResponder(self.pageRangeBox) self.pageRangeBox.stringValue = "" self.pageRangeBox.isEditable = true } self.emptyLabel.stringValue = NSLocalizedString("Recognize text from Image-based or Scanned PDF with OCR", comment: "") self.failedLabel.stringValue = NSLocalizedString("OCR failed. Please try to change the OCR Plan to \"Plan 2 (Offline)\"", comment: "") self.txtTextView.textColor = NSColor.textColor self.txtTextView.enclosingScrollView?.autohidesScrollers = true self.ocrResultLabel.stringValue = NSLocalizedString("OCR Results", comment: "") self.ocrCopyButton?.toolTip = KMLocalizedString("Copy and edit text from documents with OCR.", nil) self.deleteButton?.toolTip = NSLocalizedString("Delete", comment: "") self.deleteButton?.title = NSLocalizedString("Delete", comment: "") self.ocrCopyButton?.title = NSLocalizedString("Copy", comment: "") self.errorOCRArrays = [] self.pageIndexs = [] self.ocrCopyButton.isEnabled = false self.deleteButton.isEnabled = false self.saveButton.isEnabled = false self.savePDFButton.isEnabled = false self.boxLabel1.stringValue = NSLocalizedString("Settings", comment: "") self.previewLabel.stringValue = NSLocalizedString("Preview", comment: "") self.saveButton.title = NSLocalizedString("Save as TXT", comment: "") self.savePDFButton.title = NSLocalizedString("Save as PDF", comment: "") self.saveButton.toolTip = NSLocalizedString("Export as a searchable PDF or text file.", comment: "") self.savePDFButton.toolTip = NSLocalizedString("Export as a searchable PDF or text file.", comment: "") self.cancelButton.title = NSLocalizedString("Cancel", comment: "") self.startButton.title = NSLocalizedString("OCR", comment: "") self.languageLabel.stringValue = NSLocalizedString("Select OCR Language:", comment: "") self.updateLanguageButton((KMGOCRManager.default().selectedLanguages?.value(forKeyPath: KMGOCRLanguageStringKey) as? [String])) NotificationCenter.default.addObserver(self, selector: #selector(OCRSelectedLanguagesChangeNotification(notification:)), name: NSNotification.Name("KMOCRSelectedLanguagesChangeNotification"), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(OCRSelectedPlanChangeNotification(notification:)), name: NSNotification.Name("KMOCRSelectedPlanChangeNotification"), object: nil) self.progressControl.isHidden = true emptyBox.isHidden = false failedBox.isHidden = true self.PDFView.document = self.pdfDocument self.PDFView.go(toPageIndex: self.currentIndexPage, animated: false) self.PDFView.autoScales = true self.reloadPDFData() if !(self.pdfDocument?.isLocked ?? false) && ((self.pdfDocument?.unlock(withPassword: self.password)) != nil) { } else { if let docUrl = self.pdfDocument?.documentURL { KMBaseWindowController.checkPassword(url: self.pdfDocument!.documentURL, type: .owner) { success, pwd in if success { self.pdfDocument?.unlock(withPassword: pwd) self.password = pwd self.reloadPDFData() } else { self.close() } } } else { KMPrint("document url is nil") } } NotificationCenter.default.addObserver(self, selector: #selector(PDFViewDocumentChangedNotification(notification:)), name: NSNotification.Name.CPDFViewPageChanged, object: nil) } func windowShouldClose(_ sender: NSWindow) -> Bool { close() return true } override func close() { releaseSomething() if ((self.window?.isSheet) != nil) { self.window?.sheetParent?.endSheet(self.window!) } else { super.close() } } //MARK: - Public Method func reloadPDFData() { // 隐藏PDFView滑动条 self.PDFView.documentView()?.enclosingScrollView?.hasVerticalScroller = false self.PDFView.documentView()?.enclosingScrollView?.hasHorizontalScroller = false let pageCount: Int = Int(self.pdfDocument?.pageCount ?? 0) let currentPageIndex = self.pdfDocument?.index(for: self.PDFView.currentPage()) self.currentPageLabel.stringValue = "\((currentPageIndex ?? 0) + 1)" self.totalPageLabel.stringValue = "/ \(pageCount)" } func updateLanguageButton(_ languages: [String]?) { if languages?.count ?? 0 < 1 { self.languageButton.title = NSLocalizedString("Auto Detection", comment: "") return } var languageName: String? = nil if languages?.count ?? 0 > 0 { for i in 0..<(languages?.count ?? 0) { let language = languages?[i] if i == 0 { languageName = language } else { languageName = languageName?.appendingFormat(",%@", language ?? "") } } } else { languageName = "" } self.languageButton.title = languageName ?? "" } func imageRep(withSize size: NSSize, scale: CGFloat, drawingHandler: (NSRect) -> Void) -> Any? { let bmpImageRep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(size.width * scale), pixelsHigh: Int(size.height * scale), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .calibratedRGB, bitmapFormat: .alphaFirst, bytesPerRow: 0, bitsPerPixel: 0) // bmpImageRep?.bitmapImageRepByRetaggingWithColorSpace = .sRGB bmpImageRep?.size = size NSGraphicsContext.saveGraphicsState() NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: bmpImageRep!) // drawingHandler(.zero, size) drawingHandler(NSRect(origin: NSZeroPoint, size: size)) NSGraphicsContext.restoreGraphicsState() return bmpImageRep } func bitmapImage(withSize size: NSSize, drawingHandler: (NSRect) -> Void) -> NSImage? { let image = NSImage(size: size) let scale = KMImageScale image.addRepresentation(imageRep(withSize: size, scale: scale, drawingHandler: drawingHandler) as! NSBitmapImageRep) return image } func thumbnail(with page: CPDFPage) -> NSImage? { let bounds = page.bounds(for: .cropBox) var pageSize = bounds.size var scale: CGFloat = 1.0 var thumbnailSize: NSSize var pageRect = NSZeroRect var image: NSImage? let aSize = pageSize.width if page.rotation % 180 == 90 { pageSize = NSSize(width: pageSize.height, height: pageSize.width) } if aSize > 0.0 { if pageSize.height > pageSize.width { thumbnailSize = NSSize(width: round(aSize * pageSize.width / pageSize.height), height: aSize) } else { thumbnailSize = NSSize(width: aSize, height: round(aSize * pageSize.height / pageSize.width)) } let kKMMaxPixelsLimit = 75000000 let totalPixelNumber = Int((thumbnailSize.width * KMImageScale) * (thumbnailSize.height * KMImageScale)) if totalPixelNumber >= kKMMaxPixelsLimit { let sizeScale = sqrt(Float(kKMMaxPixelsLimit - 1000) / Float(totalPixelNumber)) thumbnailSize = NSSize(width: floor(thumbnailSize.width * CGFloat(sizeScale)), height: floor(thumbnailSize.height * CGFloat(sizeScale))) } scale = max(thumbnailSize.width / pageSize.width, (thumbnailSize.height) / pageSize.height) } else { thumbnailSize = NSSize(width: pageSize.width, height: pageSize.height) } if thumbnailSize.width.isNaN || thumbnailSize.height.isNaN || thumbnailSize.width == 0.0 || thumbnailSize.height == 0.0 { thumbnailSize = NSSize(width: 186.0, height: 256.0) } pageRect.size = thumbnailSize image = bitmapImage(withSize: thumbnailSize) { rect in NSGraphicsContext.current?.imageInterpolation = .high NSGraphicsContext.saveGraphicsState() NSColor.white.setFill() pageRect.fill() NSGraphicsContext.restoreGraphicsState() if abs(scale - 1.0) > 0.0 { let transform = NSAffineTransform() transform.scale(by: scale) transform.concat() } page.draw(with: .cropBox, to: (NSGraphicsContext.current?.cgContext as! CGContext)) NSGraphicsContext.current?.imageInterpolation = .default } return image } func savedName() -> String { var resultArrays: Array = [] var ocrIndexArrays: Array = [] let sortedKeys = self.ocrDictionary?.allKeys.sorted(by: { ($0 as? String)?.compare($1 as? String ?? "") == .orderedAscending }) for i in 0 ..< (sortedKeys?.count ?? 0) { let keyS = sortedKeys?[i] ocrIndexArrays.append(keyS as Any) resultArrays.append(self.ocrDictionary?[keyS as Any] as Any) } var fileName = self.savedFileName if fileName.count > 50 { fileName = String(fileName.prefix(50)) } if sortedKeys?.count ?? 0 > 1 { fileName = "\(self.pathFile) Pages \(fileName) _OCR" } else { fileName = "\(self.pathFile) Page \(fileName) _OCR" } var returnName = fileName switch self.pageRangeBox.indexOfSelectedItem { case 0: returnName = "\(self.pathFile)_OCR" case 2: returnName = "\(self.pathFile) Odd_OCR" case 3: returnName = "\(self.pathFile) Even_OCR" default: break } return returnName } func savePDF() { var resultArrays: Array = [] var ocrIndexArrays: Array = [] let sortedKeys = self.ocrDictionary?.allKeys.sorted(by: { ($0 as? NSNumber)?.compare(($1 as? NSNumber) ?? .init(value: 0)) == .orderedAscending }) for i in 0 ..< (sortedKeys?.count ?? 0) { let keyS = sortedKeys?[i] ocrIndexArrays.append(keyS as Any) resultArrays.append(self.ocrDictionary?[keyS as Any] as Any) } let fileName = self.savedFileName let saveAccessCtr = KMSavePanelAccessoryController() let outputSavePanel = NSSavePanel() outputSavePanel.allowedFileTypes = ["pdf"] outputSavePanel.nameFieldStringValue = fileName outputSavePanel.accessoryView = saveAccessCtr.view outputSavePanel.beginSheetModal(for: self.window!) { [self] (result) in if result == .OK { let savePDFPath = outputSavePanel.url?.path ?? "" if !FileManager.default.fileExists(atPath: getOCRResrultsFolderPath()) { try? FileManager.default.createDirectory(atPath: getOCRResrultsFolderPath(), withIntermediateDirectories: false, attributes: nil) } var imagePath = [Any]() for i in 0.. String { var fileName: String? = nil if nums.count > 0 { if nums.count == 1 { if let num = nums.first { let idx = num.intValue + 1 return "\(idx)" } } var sortIndex = NSSet() for num in nums { let idx = num.intValue + 1 // sortIndex.insert(NSNumber(value: idx)) sortIndex.adding(NSNumber(value: idx)) } let sort = NSSortDescriptor(key: nil, ascending: true) let sortDesc = [sort] let sortArray = sortIndex.sortedArray(using: sortDesc) var a = 0 var b = 0 if sortArray.count == 1 { let num: NSNumber = sortArray.last as! NSNumber fileName = "\(num.intValue)" return fileName ?? "" } for i in 0 ..< sortArray.count { let num = sortArray[i] if fileName?.count ?? 0 > 0 { if (num as AnyObject).intValue == b + 1 { b = (num as AnyObject).intValue if (i == sortArray.count - 1) { fileName = (fileName ?? "") + "\(a)-\(b)" } } else { if a == b { fileName = (fileName ?? "") + "\(a)," } else { fileName = (fileName ?? "") + "\(a)-\(b)," } a = (num as AnyObject).intValue b = (num as AnyObject).intValue if (i == sortArray.count - 1) { fileName = (fileName ?? "") + "\(a)" } } } else { fileName = "" a = (num as AnyObject).intValue b = (num as AnyObject).intValue } } return fileName ?? "" } return "" } func batchesOCR() { savedFileName = savedName() let intervalOCR: UInt = 10 let selctPageImages: NSMutableArray = NSMutableArray() for i in 0..= self.pageIndexs?.count ?? 0 { continue } autoreleasepool { let index = self.pageIndexs?[self.ocrCurrentIndex + Int(i)] as! NSNumber let page = self.pdfDocument?.page(at: UInt(index.intValue)) let img: NSImage = thumbnail(with: page!)! let data: NSData = img.tiffRepresentation! as NSData selctPageImages.add(data) } } if selctPageImages.count < 1 && ocrCurrentIndex == 0 { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: "") if #available(OSX 10.11, *) { alert.beginSheetModal(for: self.window!, completionHandler: nil) } else { alert.runModal() } } if appleOCRManger != nil { appleOCRManger?.cancelRecognition() appleOCRManger?.delegate = nil appleOCRManger = nil } if googleOCRManger != nil { googleOCRManger?.cancelRecognition() googleOCRManger?.delegate = nil googleOCRManger = nil } if selctPageImages.count < 1 { return } ocrCopyButton.isEnabled = false saveButton.isEnabled = false savePDFButton.isEnabled = false startButton.isEnabled = false deleteButton.isEnabled = false progressControl.isHidden = false progressControl.startAnimation(nil) emptyBox.isHidden = true failedBox.isHidden = true DispatchQueue.main.async { let languages = KMGOCRManager.default().selectedLanguages?.value(forKeyPath: KMGOCRLanguageCodeKey) if self.planComboBox.indexOfSelectedItem == 0 { self.googleOCRManger = KMGOCRManager() self.googleOCRManger?.ocrType = .google self.googleOCRManger?.delegate = self self.googleOCRManger?.recognitionImages((selctPageImages as! [Any]), withLanguages: languages as? [Any]) } else { self.appleOCRManger = KMGOCRManager() self.appleOCRManger?.ocrType = .apple self.appleOCRManger?.delegate = self self.appleOCRManger?.recognitionImages((selctPageImages as! [Any]), withLanguages: languages as? [Any]) } } } //MARK: - IBAction @IBAction func cancelButtonAction(_ sender: Any) { if FileManager.default.fileExists(atPath: getOCRResrultsFolderPath()) { try? FileManager.default.removeItem(atPath: getOCRResrultsFolderPath()) } KMGOCRManager.default().cancelRecognition() self.close() } @IBAction func startButtonAction(_ sender: Any) { self.ocrCurrentIndex = 0 txtTextView.string = "" ocrDictionary = NSMutableDictionary() let pdfDocument = self.pdfDocument errorOCRArrays?.removeAll() pageIndexs?.removeAll() if self.pageRangeBox.indexOfSelectedItem == 0 { for i in 0..<(pdfDocument?.pageCount ?? 0) { pageIndexs?.append(NSNumber(value: i)) } } else if self.pageRangeBox.indexOfSelectedItem == 1 { let page = PDFView.currentPage() let pageIndex = PDFView.document?.index(for: page) pageIndexs?.append(NSNumber(value: pageIndex!)) } else if self.pageRangeBox.indexOfSelectedItem == 2 { for i in 0..<(pdfDocument?.pageCount ?? 0) where i % 2 == 0 { pageIndexs?.append(NSNumber(value: i)) } } else if self.pageRangeBox.indexOfSelectedItem == 3 { for i in 0..<(pdfDocument?.pageCount ?? 0) where i % 2 != 0 { pageIndexs?.append(NSNumber(value: i)) } } else { var attribute = self._fileAttri if attribute == nil { attribute = KMFileAttribute() self._fileAttri = attribute attribute?.password = self.pdfDocument?.password ?? "" attribute?.filePath = self.pdfDocument?.documentURL.path ?? "" } // attribute.pdfDocument = pdfDocument attribute?.bAllPage = false attribute?.pagesType = .custom attribute?.pagesString = self.pageRangeBox.stringValue let selectPages = attribute?.fetchSelectPages() ?? [] if selectPages.count > 0 { for num in selectPages { pageIndexs?.append(NSNumber(value: num - 1)) } } } batchesOCR() } @IBAction func planSelectButtonAction(_ sender: NSPopUpButton) { let plan = UserDefaults.standard.integer(forKey: "KMOCRCurrentPlanKey") if plan != sender.indexOfSelectedItem { KMGOCRManager.default().selectedLanguages = NSMutableArray() updateLanguageButton(KMGOCRManager.default().selectedLanguages?.value(forKeyPath: KMGOCRLanguageStringKey) as? [String]) } UserDefaults.standard.set(sender.indexOfSelectedItem, forKey: "KMOCRCurrentPlanKey") UserDefaults.standard.synchronize() if self.planComboBox.indexOfSelectedItem == 0 { KMGOCRManager.default().ocrType = .google } else { KMGOCRManager.default().ocrType = .apple } NotificationCenter.default.post(name: NSNotification.Name("KMOCRSelectedPlanChangeNotification"), object: nil) } @IBAction func languageButtonAction(_ sender: Any) { let popover = NSPopover() popover.delegate = self popover.contentViewController = KMLanguageViewController(nibName: "KMLanguageViewController", bundle: Bundle.main) popover.animates = true popover.behavior = .transient popover.show(relativeTo: (sender as! NSView).bounds, of: sender as! NSView, preferredEdge: .minX) } @IBAction func helpButtonAction(_ sender: Any) { let helpController = NSViewController() let textView = NSTextView(frame: NSRectToCGRect(NSMakeRect(0, 0, 300.0, 50.0))) textView.backgroundColor = NSColor.clear textView.isEditable = false textView.layer?.cornerRadius = 6 let tStrAuto = NSLocalizedString("Choose automatic language detection for better OCR results.", comment: "") textView.alignment = .justified textView.string = "\n\(tStrAuto)" helpController.view = textView let popover = NSPopover() popover.delegate = self popover.contentViewController = helpController popover.animates = true popover.behavior = .transient popover.show(relativeTo: (sender as! NSView).bounds, of: sender as! NSView, preferredEdge: .minY) } @IBAction func buttonItemClick_CopyTxt(_ sender: NSButton) { let pasteboard = NSPasteboard.general pasteboard.clearContents() let str: NSPasteboardWriting = self.txtTextView.string as NSPasteboardWriting pasteboard.writeObjects([str]) let _ = CustomAlertView.alertView(message: NSLocalizedString("Copy successful!", comment: ""), fromView: sender.superview!, withStyle: .black) } @IBAction func buttonItemClick_Delete(_ sender: NSButton) { ocrCopyButton.isEnabled = false saveButton.isEnabled = false savePDFButton.isEnabled = false deleteButton.isEnabled = false emptyBox.isHidden = false failedBox.isHidden = true resultString = "" txtTextView.string = "" ocrDictionary = NSMutableDictionary() } @IBAction func boxItemClicked_PageRange(_ sender: NSButton) { if 4 != pageRangeBox.indexOfSelectedItem { self.window?.makeFirstResponder(self) pageRangeBox.isEditable = false } else { pageRangeBox.stringValue = "" pageRangeBox.isEditable = true self.window?.makeFirstResponder(pageRangeBox) } } @IBAction func nextButtonAction(_ sender: NSButton) { self.PDFView.goToNextPage(nil) self.reloadPDFData() } @IBAction func previousButtonAction(_ sender: NSButton) { self.PDFView.goToPreviousPage(nil) self.reloadPDFData() } @IBAction func buttonClicked_SaveButton(_ sender: NSButton) { self.saveText() } @IBAction func savePDFButtonAction(_ sender: NSButton) { self.savePDF() } //MARK: - ControlDelegate func controlTextDidEndEditing(_ notification: Notification) { guard let textField = notification.object as? NSTextField else { return } if textField == currentPageLabel { let index = Int(currentPageLabel.stringValue) ?? 0 let pageCount = pdfDocument?.pageCount let currentPageIndex = pdfDocument?.index(for: PDFView.currentPage()) if index > 0 && index <= pageCount ?? 0 { PDFView.go(to: pdfDocument?.page(at: UInt(index-1))!) reloadPDFData() } else { currentPageLabel.stringValue = "\((currentPageIndex ?? 0)+1)" } } } func controlTextDidChange(_ notification: Notification) { guard let textField = notification.object as? NSTextField else { return } if textField == currentPageLabel { let string = textField.formatter?.string(for: NSNumber(value: Int(textField.stringValue) ?? 0)) textField.stringValue = string ?? "" } } func popoverDidClose(_ notification: Notification) { } func gocrManagerDidStartOCR(_ manager: KMGOCRManager!) { } //MARK: - KMGOCRManagerDelegate func gocrManagerDidFinishOCR(_ manager: KMGOCRManager!) { self.batchesOCR() } func gocrManager(_ manager: KMGOCRManager!, didCancelOCRImageAt index: Int) { } func gocrManager(_ manager: KMGOCRManager!, didStartOCRImageAt index: Int) { DispatchQueue.main.async { self.pageRangeBox.isEnabled = false self.languageButton.isEnabled = false self.planComboBox.isEnabled = false } } func gocrManager(_ manager: KMGOCRManager!, didFinishOCRImageAt index: Int, results: [KMGOCRResult]!) { self.dealWithResults(results, OCRImageAtIndex: index) } func gocrManager(_ manager: KMGOCRManager!, didFailureOCRImageAt index: Int, error: Error!) { let pagenum = self.pageIndexs?[index] as! NSNumber if (error != nil) { self.errorOCRArrays?.append(pagenum) } self.dealWithResults([], OCRImageAtIndex: index) } func dealWithResults(_ rlts: [KMGOCRResult]?, OCRImageAtIndex index: Int) { if index >= self.pageIndexs?.count ?? 0 { return } let key = self.pageIndexs?[self.ocrCurrentIndex] as! NSNumber if ocrDictionary == nil { ocrDictionary = NSMutableDictionary() } ocrDictionary?.setObject(rlts as Any, forKey: key) let sortedKeys = self.ocrDictionary?.allKeys.sorted(by: { ($0 as! NSNumber).compare($1 as! NSNumber) == .orderedAscending }) var textString = "" for key in sortedKeys! { let results: Array = self.ocrDictionary?.object(forKey: key) as! Array var rStr = "" if results.count > 0 { rStr = results[0].text } if textString.count > 0 { textString += "\n\n" } textString += String(format: NSLocalizedString("Page %ld", comment: ""), (key as! NSNumber).intValue + 1) textString += "\n" textString += rStr } self.txtTextView.string = textString self.resultString = textString self.ocrCurrentIndex += 1 if self.ocrCurrentIndex >= (self.pageIndexs?.count ?? 0) - 1 { self.progressControl.stopAnimation(nil) self.progressControl.isHidden = true self.saveButton.isEnabled = true self.savePDFButton.isEnabled = true self.ocrCopyButton.isEnabled = true self.deleteButton.isEnabled = true self.startButton.isEnabled = true DispatchQueue.main.async { self.pageRangeBox.isEnabled = true self.languageButton.isEnabled = true self.planComboBox.isEnabled = true } // if appleOCRManger != nil { // appleOCRManger?.cancelRecognition() // appleOCRManger?.delegate = nil // appleOCRManger = nil // } // // if googleOCRManger != nil { // googleOCRManger?.cancelRecognition() // googleOCRManger?.delegate = nil // googleOCRManger = nil // } // // KMGOCRManager.default().delegate = nil if self.errorOCRArrays?.count ?? 0 < 1 { } else if self.errorOCRArrays?.count == self.pageIndexs?.count { if KMGOCRManager.default().ocrType == .google { self.failedLabel.stringValue = NSLocalizedString("OCR failed.Please try to change the OCR Plan to \"Plan 2 (Offline)\"", comment: "") self.failedBox.isHidden = false } else { let alert = NSAlert() alert.alertStyle = NSAlert.Style.critical alert.messageText = "" if #available(macOS 10.15, *) { alert.informativeText = NSLocalizedString("Unable to perform OCR on this document. Please try again later.", comment: "") } else { alert.informativeText = NSLocalizedString("OCR failed, please try again. Note: OCR Plan 2(Offline) is supported in macOS 10.15+.", comment: "") self.failedLabel.stringValue = NSLocalizedString("OCR failed, please try again. Note: OCR Plan 2(Offline) is supported in macOS 10.15+.", comment: "") self.failedBox.isHidden = false } alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) let response = alert.runModal() if response == NSApplication.ModalResponse.alertFirstButtonReturn { } } } else { var contextString = String(format: "%@", NSLocalizedString("Some problems occurred during the last operation:", comment: "")) contextString += "\n" if self.errorOCRArrays?.count ?? 0 > 1 { contextString += NSLocalizedString("Pages", comment: "") } else { contextString += NSLocalizedString("Page", comment: "") } if self.errorOCRArrays?.count ?? 0 > 0 { contextString += String(format: ": %@", self.fileNameWithNums(self.errorOCRArrays as! Array)) } let alert = NSAlert() alert.alertStyle = NSAlert.Style.critical alert.messageText = NSLocalizedString("Completed", comment: "") alert.informativeText = contextString alert.addButton(withTitle: NSLocalizedString("OK", comment: "")) let response = alert.runModal() if response == NSApplication.ModalResponse.alertFirstButtonReturn { } } } } //MARK: KMOCRSelectedLanguagesChangeNotification @objc func OCRSelectedLanguagesChangeNotification(notification: NSNotification) { if let selectedLanguages = notification.object as? [String] { updateLanguageButton(selectedLanguages) } } @objc func OCRSelectedPlanChangeNotification(notification: NSNotification) { let plan = UserDefaults.standard.integer(forKey: "KMOCRCurrentPlanKey") if plan == 0 { self.planComboBox.selectItem(at: 0) } else { self.planComboBox.selectItem(at: 1) } KMGOCRManager.default().selectedLanguages = NSMutableArray() updateLanguageButton(KMGOCRManager.default().selectedLanguages?.value(forKeyPath: KMGOCRLanguageStringKey) as? [String]) } @objc func PDFViewDocumentChangedNotification(notification: NSNotification) { let pageIndex = self.PDFView.currentPageIndex+1 self.currentPageLabel.stringValue = "\(pageIndex)" } }