// // KMBatchImageToPDFView.swift // PDF Reader Pro // // Created by lizhe on 2025/1/15. // import Cocoa import KMComponentLibrary class KMBatchImageToPDFView: KMBatchSettingItemView { @IBOutlet weak var titleLabel: NSTextField! @IBOutlet weak var titleContentView: NSView! @IBOutlet weak var subTitleLabel: NSTextField! @IBOutlet weak var newPDFDocumentButton: ComponentRadio! @IBOutlet weak var mergeAllButton: ComponentCheckBox! @IBOutlet weak var appendToFileButton: ComponentRadio! @IBOutlet weak var selectFileInputButton: ComponentInput! @IBOutlet weak var selectFileInputAddonButton: ComponentInputAddon! @IBOutlet weak var textRecognitionSettingLabel: NSTextField! @IBOutlet weak var recognizeTextButton: ComponentCheckBox! @IBOutlet weak var languageSelectButton: ComponentSelect! @IBOutlet weak var lineView: ComponentDivider! @IBOutlet weak var OCRPlan1Button: ComponentRadio! @IBOutlet weak var OCRPlan1ButtonWidthConstraint: NSLayoutConstraint! @IBOutlet weak var OCRPlan2Button: ComponentRadio! @IBOutlet weak var OCRPlan2ButtonWidthConstraint: NSLayoutConstraint! @IBOutlet weak var extractTextButton: ComponentCheckBox! @IBOutlet weak var applyButton: ComponentButton! var model: KMBatchImageToPDFModel = KMBatchImageToPDFModel() var selectIndex = 0 var password: String = "" override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) // Drawing code here. } override func updateUILanguage() { self.subTitleLabel.stringValue = KMLocalizedString("Output") self.newPDFDocumentButton.properties.text = KMLocalizedString("New PDF Document") self.newPDFDocumentButton.reloadData() self.mergeAllButton.properties.text = KMLocalizedString("Merge All") self.mergeAllButton.reloadData() self.appendToFileButton.properties.text = KMLocalizedString("Append to Existing File") self.appendToFileButton.reloadData() self.textRecognitionSettingLabel.stringValue = KMLocalizedString("Text Recognition Settings") self.recognizeTextButton.properties.text = KMLocalizedString("Recognize text if needed") self.recognizeTextButton.reloadData() self.OCRPlan1Button.properties.text = KMLocalizedString("OCR Plan 1 (Online)") self.OCRPlan1Button.toolTip = KMLocalizedString("The OCR service works via an internet connection. We would suggest you to perform OCR using a VPN connection while the service is limited.") self.OCRPlan1Button.reloadData() self.OCRPlan1ButtonWidthConstraint.constant = self.OCRPlan1Button.properties.propertyInfo.viewWidth self.OCRPlan2Button.properties.text = KMLocalizedString("OCR Plan 2 (Offline)") self.OCRPlan2Button.toolTip = KMLocalizedString("The OCR service works via an internet connection. We would suggest you to perform OCR using a VPN connection while the service is limited.") self.OCRPlan2Button.reloadData() self.OCRPlan2ButtonWidthConstraint.constant = self.OCRPlan2Button.properties.propertyInfo.viewWidth self.extractTextButton.properties.text = KMLocalizedString("Extract Text (.txt)") self.extractTextButton.reloadData() self.applyButton.properties.buttonText = KMLocalizedString("Apply") } override func updateUIThemeColor() { self.titleContentView.border(ComponentLibrary.shared.getComponentColorFromKey("colorBorder/divider"), 0.5, 0) titleLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-medium") titleLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") subTitleLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") subTitleLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") textRecognitionSettingLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") textRecognitionSettingLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") } override func setup() { self.newPDFDocumentButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, checkboxType: .normal) self.newPDFDocumentButton.setTarget(self, action: #selector(newPDFDocumentButtonAction)) self.mergeAllButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false,checkboxType: .normal) self.mergeAllButton.setTarget(self, action: #selector(mergeAllButtonAction)) self.appendToFileButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, checkboxType: .normal) self.appendToFileButton.setTarget(self, action: #selector(appendToFileButtonAction)) self.recognizeTextButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, checkboxType: .normal) self.recognizeTextButton.setTarget(self, action: #selector(OCRButtonAction)) let inputWithAddonProperty = ComponentInputProperty(size: .s, state: .normal, isError: false, showPrefix: false, showSuffix: false, showClear: false, isDisabled: true, placeholder: KMLocalizedString("Select File..."), text: "", creatable: false) selectFileInputButton.properties = inputWithAddonProperty selectFileInputButton.properties.propertyInfo.cornerRadius_topRight = 0 selectFileInputButton.properties.propertyInfo.cornerRadius_bottomRight = 0 selectFileInputButton.properties.isDisabled = true selectFileInputButton.reloadData() selectFileInputAddonButton.properties = ComponentInputAddonProperty(size: .s, state: .normal, addOnBefore: false, onlyRead: false, addonType: .imageWithColor, iconImage: NSImage(named: "KMFolderIcon")) selectFileInputAddonButton.properties.isDisabled = true selectFileInputAddonButton.reloadData() selectFileInputAddonButton.setTarget(self, action: #selector(addFilesButtonAction)) self.languageSelectButton.properties = ComponentSelectProperties(size: .s, state: .normal, isDisabled: false, isError: false, leftIcon: false, placeholder: nil, errorText: nil, creatable: false, text: KMLocalizedString("", comment: "")) self.languageSelectButton.delegate = self self.OCRPlan1Button.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: true, text: KMLocalizedString("OCR Plan 1 (Online)"), checkboxType: .normal) OCRPlan1Button.setTarget(self, action: #selector(OCRPlan1ButtonAction)) self.OCRPlan1Button.reloadData() self.OCRPlan1ButtonWidthConstraint.constant = self.OCRPlan1Button.properties.propertyInfo.viewWidth self.OCRPlan2Button.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: true, text: KMLocalizedString("OCR Plan 2 (Offline)"), checkboxType: .normal) OCRPlan2Button.setTarget(self, action: #selector(OCRPlan2ButtonAction)) self.OCRPlan2Button.reloadData() self.OCRPlan2ButtonWidthConstraint.constant = self.OCRPlan2Button.properties.propertyInfo.viewWidth self.extractTextButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, checkboxType: .normal) extractTextButton.setTarget(self, action: #selector(extractTextButtonAction)) applyButton.properties = ComponentButtonProperty(type: .primary, size: .m, showRightIcon: true, keepPressState: false) applyButton.setTarget(self, action: #selector(saveButtonClicked(_:))) self.lineView.properties = ComponentDividerProperty() super.setup() } override func reloadData() { self.updateLanguages() self.newPDFDocumentButton.properties.checkboxType = self.model.isNewPDF ? .selected : .normal self.newPDFDocumentButton.reloadData() self.mergeAllButton.properties.isDisabled = !self.model.isNewPDF self.mergeAllButton.reloadData() self.appendToFileButton.properties.checkboxType = self.model.isAppendToExistingFile ? .selected : .normal self.appendToFileButton.reloadData() self.selectFileInputButton.properties.isDisabled = !self.model.isAppendToExistingFile self.selectFileInputButton.reloadData() self.selectFileInputAddonButton.properties.isDisabled = !self.model.isAppendToExistingFile self.selectFileInputAddonButton.reloadData() self.languageSelectButton.properties.isDisabled = !self.model.isOCR self.languageSelectButton.reloadData() if self.model.ocrType == .google { self.OCRPlan1Button.properties.checkboxType = .selected self.OCRPlan2Button.properties.checkboxType = .normal } else if self.model.ocrType == .apple { self.OCRPlan1Button.properties.checkboxType = .normal self.OCRPlan2Button.properties.checkboxType = .selected } self.OCRPlan1Button.properties.isDisabled = !self.model.isOCR self.OCRPlan1Button.reloadData() self.OCRPlan2Button.properties.isDisabled = !self.model.isOCR self.OCRPlan2Button.reloadData() self.extractTextButton.properties.isDisabled = !self.model.isOCR self.extractTextButton.reloadData() languageSelectButton.selectItemAtIndex(self.selectIndex) if self.filesData.count == 0 { self.applyButton.properties.isDisabled = true } else { self.applyButton.properties.isDisabled = false } self.applyButton.reloadData() } func updateLanguages() { var menuItemArr: [ComponentMenuitemProperty] = [] var languages: [String] = KMOCRManager.manager.getLanguages(type: model.ocrType) languages.insert(KMLocalizedString("Auto Detection"), at: 0) for language in languages { let itemProperty: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false, itemSelected: false, isDisabled: false, keyEquivalent: nil, text: language, identifier: "1") menuItemArr.append(itemProperty) } languageSelectButton.updateMenuItemsArr(menuItemArr) let position = languages.firstIndex(of: model.language) ?? 0 self.selectIndex = position } override func bacthProcessingNotification() { self.newPDFDocumentButton.properties.isDisabled = self.isDisable self.newPDFDocumentButton.reloadData() self.mergeAllButton.properties.isDisabled = self.isDisable self.mergeAllButton.reloadData() self.appendToFileButton.properties.isDisabled = self.isDisable self.appendToFileButton.reloadData() self.selectFileInputButton.properties.isDisabled = self.isDisable self.selectFileInputButton.reloadData() self.selectFileInputAddonButton.properties.isDisabled = self.isDisable self.selectFileInputAddonButton.reloadData() self.recognizeTextButton.properties.isDisabled = self.isDisable self.recognizeTextButton.reloadData() self.languageSelectButton.properties.isDisabled = self.isDisable self.languageSelectButton.reloadData() self.OCRPlan1Button.properties.isDisabled = self.isDisable self.OCRPlan1Button.reloadData() self.OCRPlan2Button.properties.isDisabled = self.isDisable self.OCRPlan2Button.reloadData() self.applyButton.properties.isDisabled = self.isDisable self.applyButton.reloadData() self.extractTextButton.properties.isDisabled = self.isDisable self.extractTextButton.reloadData() } } extension KMBatchImageToPDFView: ComponentSelectDelegate { func componentSelectDidSelect(view: ComponentSelect?, menuItemProperty: ComponentMenuitemProperty?) { if (view == languageSelectButton) { var languages: [String] = KMOCRManager.manager.getLanguages(type: model.ocrType) let position = languages.firstIndex(of: menuItemProperty?.text ?? "") ?? 0 self.selectIndex = position + 1 let values: [String: String] = KMGOCRManager.languages()[position] as? [String : String] ?? [:] let key = values[KMGOCRLanguageCodeKey] model.language = key ?? "" if let unwrappedKey = key, let intValue = Int(unwrappedKey) { model.languageType = COCRLanguage(rawValue: intValue) ?? .english } else { print("转换失败") } } } } //MARK: Action extension KMBatchImageToPDFView { @objc func saveButtonClicked(_ sender: ComponentButton) { self.model.selectFilePath = self.selectFileInputButton.properties.text if !self.model.isNewPDF { let selectFilePath = self.model.selectFilePath if selectFilePath.count == 0 { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = KMLocalizedString("文件未选择") alert.runModal() return } } guard let callBack = self.batchExport else { return } callBack(self, model) } func addFilesButtonAction() { let openPanel = NSOpenPanel() openPanel.allowedFileTypes = ["pdf"] openPanel.canChooseDirectories = false openPanel.allowsMultipleSelection = false openPanel.beginSheetModal(for: self.window!) { (result) in if result == .OK { guard let url = openPanel.url else { return } guard let document = CPDFDocument(url: url) else { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = KMLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "") alert.runModal() return } if !document.allowsCopying || !document.allowsPrinting { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = KMLocalizedString("This is a secured document. Editing is not permitted.", comment: "") alert.runModal() return } if document.isLocked { NSWindowController.checkPassword(url: url, type: .owner) { [weak self] success, resultPassword in if success { self?.password = resultPassword self?.selectFileInputButton.properties.text = url.path self?.selectFileInputButton.reloadData() } } } else { self.selectFileInputButton.properties.text = url.path self.selectFileInputButton.reloadData() } } } } func newPDFDocumentButtonAction() { self.model.isNewPDF = !self.model.isNewPDF self.model.isAppendToExistingFile = !self.model.isNewPDF self.reloadData() } func mergeAllButtonAction() { self.model.isMergeAll = !self.model.isMergeAll self.reloadData() } func appendToFileButtonAction() { self.model.isAppendToExistingFile = !self.model.isAppendToExistingFile self.model.isNewPDF = !self.model.isAppendToExistingFile self.reloadData() } func OCRButtonAction() { self.model.isOCR = !self.model.isOCR self.reloadData() if self.model.isOCR { #if VERSION_DMG KMResourceDownloadManager.manager.downLoadOCRResource(window: self.window ?? NSWindow.currentWindow()) #endif } } func OCRPlan1ButtonAction() { self.model.ocrType = .google self.reloadData() } func OCRPlan2ButtonAction() { self.model.ocrType = .apple self.reloadData() } func extractTextButtonAction() { self.model.isExtractText = !self.model.isExtractText self.reloadData() } }