// // KMBatchOperateImageToPDFViewController.swift // PDF Reader Pro // // Created by liujiajie on 2023/12/5. // import Cocoa import KMComponentLibrary class KMBatchOperateImageToPDFViewController: KMBatchOperateBaseViewController { @IBOutlet weak var headerBox: NSBox! @IBOutlet weak var titleLabel: NSTextField! @IBOutlet weak var headerBottomLine: ComponentDivider! @IBOutlet var outputTypeLabel: NSTextField! @IBOutlet var ocrLabel: NSTextField! @IBOutlet weak var newPDFBox: NSBox! @IBOutlet weak var mergeAllBox: NSBox! @IBOutlet weak var appendBox: NSBox! @IBOutlet weak var appendBackBox: NSBox! @IBOutlet weak var ocrSelectBox: NSBox! @IBOutlet weak var languageBox: NSBox! @IBOutlet weak var ocrPlanBox: NSBox! @IBOutlet weak var ocrPlan2Box: NSBox! @IBOutlet weak var hLine: NSView! @IBOutlet weak var extractTextBox: NSBox! @IBOutlet weak var bottomBox: NSBox! @IBOutlet weak var bottomTopLine: ComponentDivider! @IBOutlet weak var applyButton: ComponentButton! var password: String = "" lazy var method: KMImageToPDFMethod = { let method = KMImageToPDFMethod() method.imageTopdfDelegate = self return method }() private lazy var topLine: NSView = { let view = NSView() view.wantsLayer = true return view }() private var createNewPDFRadio_: ComponentRadio = { let view = ComponentRadio() view.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: KMLocalizedString("New PDF Document", comment: ""), checkboxType: .normal) return view }() private lazy var mergeAllCheckBox_: ComponentCheckBox = { let view = ComponentCheckBox() view.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: KMLocalizedString("Merge All", comment: ""),checkboxType: .normal) return view }() private var appendRadio_: ComponentRadio = { let view = ComponentRadio() view.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: KMLocalizedString("Append To Existing File", comment: ""), checkboxType: .normal) return view }() private var appendBackInput: ComponentInputWithAddon = { let view = ComponentInputWithAddon() view.properties = ComponentInputWithAddonProperty(size: .s, isDisabled: true, addonType: .button) return view }() private lazy var appendBackInput_: ComponentInput = { let view = ComponentInput() return view }() private lazy var appendBackButtonInput_: ComponentInputAddon = { let view = ComponentInputAddon() return view }() private lazy var ocrCheckBox_: ComponentCheckBox = { let view = ComponentCheckBox() view.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: KMLocalizedString("Recognize text if needed", comment: ""), checkboxType: .normal) return view }() private lazy var languageView_: ComponentSelect = { let view = ComponentSelect() view.properties = ComponentSelectProperties(size: .s, state: .normal, isDisabled: false, isError: false, leftIcon: false, placeholder: nil, errorText: nil, creatable: false, text: KMLocalizedString("", comment: "")) view.delegate = self return view }() private var ocrPlanRadio_: ComponentRadio = { let view = ComponentRadio() view.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: true, text: KMLocalizedString("OCR Plan 1-Online", comment: ""), checkboxType: .normal) view.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.") return view }() private var ocrPlanRadio2_: ComponentRadio = { let view = ComponentRadio() view.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: true, text: KMLocalizedString("OCR Plan 2-Online", comment: ""), checkboxType: .normal) view.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.") return view }() private var vLine_: ComponentDivider = { let view = ComponentDivider() view.properties = ComponentDividerProperty(type: .horizontal, dash: false) return view }() private lazy var extractTextCheckBox_: ComponentCheckBox = { let view = ComponentCheckBox() view.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, text: KMLocalizedString("Extract Text (.txt)", comment: ""), checkboxType: .normal) return view }() override var interfaceStatus: KMBatchOperateInterfaceStatus?{ set{ super.interfaceStatus = newValue if newValue == .PrepareProcess { DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) { let files = NSMutableArray() for url in self.successFilePathURLArray! { if FileManager.default.fileExists(atPath: url.path) { files.add(url) } } if files.count > 0 { let workspace = NSWorkspace.shared workspace.activateFileViewerSelecting(files as! [URL]) } } self._updateActionButtonEnable(true) } else { self._updateActionButtonEnable(false) } } get{ return super.interfaceStatus } } private func _updateActionButtonEnable(_ enabled: Bool) { applyButton.properties.isDisabled = !enabled applyButton.reloadData() } override func viewDidLoad() { super.viewDidLoad() headerBox.borderWidth = 0 titleLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-bold") createNewPDFRadio_.properties.checkboxType = .selected createNewPDFRadio_.reloadData() appendBackBox.borderWidth = 0 let color = KMNColorTools.compField_colorBorderDis() appendBackBox.borderColor = color let inputWithAddonProperty = ComponentInputProperty(size: .s, state: .normal, isError: false, showPrefix: false, showSuffix: false, showClear: false, isDisabled: true, placeholder: KMLocalizedString("Select File..."), text: "", creatable: false) appendBackInput_.properties = inputWithAddonProperty appendBackInput_.properties.propertyInfo.cornerRadius_topRight = 0 appendBackInput_.properties.propertyInfo.cornerRadius_bottomRight = 0 appendBackInput_.properties.isDisabled = true appendBackInput_.reloadData() appendBackButtonInput_.properties = ComponentInputAddonProperty(size: .s, state: .normal, addOnBefore: false, onlyRead: false, addonType: .imageWithColor, iconImage: NSImage(named: "KMFolderIcon")) appendBackButtonInput_.properties.isDisabled = true appendBackButtonInput_.reloadData() appendBackButtonInput_.setTarget(self, action: #selector(buttonItemClicked_AppendOtherPDF)) appendBackBox.contentView?.addSubview(appendBackInput_) appendBackBox.contentView?.addSubview(appendBackButtonInput_) let boxH: CGFloat = 30 appendBackInput_.frame = NSMakeRect(0, 0, 204, boxH) appendBackButtonInput_.frame = NSMakeRect(NSMaxX(appendBackInput_.frame), 0, boxH+2, boxH) let hView = NSView() appendBackBox.contentView?.addSubview(hView) hView.frame = NSMakeRect(NSMaxX(appendBackInput_.frame), 0, 1, 32) hView.wantsLayer = true hView.layer?.backgroundColor = color.cgColor hView.isHidden = true ocrLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") ocrSelectBox.borderWidth = 0 ocrSelectBox.contentView = ocrCheckBox_ ocrCheckBox_.setTarget(self, action: #selector(buttonClicked_OCRSelect)) languageView_.properties.isDisabled = true languageView_.reloadData() ocrPlanRadio_.setTarget(self, action: #selector(ocrPlanAction)) ocrPlanRadio_.properties.isDisabled = true ocrPlanRadio_.properties.checkboxType = .selected ocrPlanRadio_.reloadData() ocrPlanRadio2_.setTarget(self, action: #selector(ocrPlanAction)) ocrPlanRadio2_.properties.isDisabled = true ocrPlanRadio2_.reloadData() extractTextCheckBox_.properties.isDisabled = true extractTextCheckBox_.reloadData() bottomBox.borderWidth = 0 applyButton.properties = ComponentButtonProperty(type: .primary, size: .m, onlyIcon: false, buttonText: KMLocalizedString("Apply")) applyButton.setTarget(self, action: #selector(buttonClicked_ImageToPDF)) view.addSubview(topLine) topLine.km_add_top_constraint() topLine.km_add_height_constraint(constant: 1) topLine.km_add_left_constraint() topLine.km_add_right_constraint() self.localizedLanguage() self.configuUI() if let cnt = self.files?.count, cnt > 0 { self._updateActionButtonEnable(true) } else { self._updateActionButtonEnable(false) } } override func addNotifations() { super.addNotifations() NotificationCenter.default.addObserver(self, selector: #selector(batchFilesCountNotification(notification:)), name: NSNotification.Name("KMBatchFilesCountNotification"), object: nil) } override func updateUILanguage() { super.updateUILanguage() KMMainThreadExecute { self.titleLabel.stringValue = KMLocalizedString("Image to PDF") self.ocrLabel.stringValue = KMLocalizedString("Text Recognition Settings") } } override func updateUIThemeColor() { super.updateUIThemeColor() KMMainThreadExecute { self.topLine.layer?.backgroundColor = KMNColorTools.colorBorder_divider().cgColor let titleColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") self.titleLabel.textColor = titleColor self.headerBottomLine.properties = ComponentDividerProperty() self.ocrLabel.textColor = titleColor self.languageBox.borderColor = KMNColorTools.compField_colorBorderDis() self.bottomTopLine.properties = ComponentDividerProperty() self.updateViewColor() } } func localizedLanguage() { self.outputTypeLabel.stringValue = KMLocalizedString("Output") let languages = KMGOCRManager.languages() as NSArray let strings = languages.value(forKeyPath: KMGOCRLanguageStringKey) as? [String] var menuItemArr: [ComponentMenuitemProperty] = [] for language in strings ?? [] { let itemProperty: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false, itemSelected: false, isDisabled: false, keyEquivalent: nil, text: language) menuItemArr.append(itemProperty) } languageView_.updateMenuItemsArr(menuItemArr) languageView_.selectItemAtIndex(0) languageView_.properties.creatable = false languageView_.properties.text = menuItemArr.first?.text languageView_.reloadData() self.updateLanguageButton((KMGOCRManager.default().selectedLanguages?.value(forKeyPath: KMGOCRLanguageStringKey) as? [String])) self.OCRSelectedPlanChangeAction() } func configuUI() { self.view.wantsLayer = true newPDFBox.borderWidth = 0 newPDFBox.contentView = createNewPDFRadio_ createNewPDFRadio_.setTarget(self, action: #selector(buttonClicked_CreateNewPDF)) mergeAllBox.borderWidth = 0 mergeAllBox.contentView = mergeAllCheckBox_ appendBox.borderWidth = 0 appendBox.contentView = appendRadio_ appendRadio_.setTarget(self, action: #selector(buttonClicked_AppendOtherPDF)) languageBox.borderWidth = 1 languageBox.cornerRadius = ComponentLibrary.shared.getComponentValueFromKey("comp-field/radius") as? CGFloat ?? 4 languageBox.contentView = languageView_ ocrPlanBox.borderWidth = 0 ocrPlanBox.contentView?.addSubview(ocrPlanRadio_) ocrPlanRadio_.km_add_leading_constraint() ocrPlanRadio_.km_add_centerY_constraint() ocrPlanRadio_.km_add_height_constraint(equalTo: ocrPlanBox.contentView) ocrPlanRadio_.km_add_width_constraint(constant: ocrPlanRadio_.properties.propertyInfo.viewWidth + 10) ocrPlan2Box.borderWidth = 0 ocrPlan2Box.contentView?.addSubview(ocrPlanRadio2_) ocrPlanRadio2_.km_add_leading_constraint() ocrPlanRadio2_.km_add_centerY_constraint() ocrPlanRadio2_.km_add_height_constraint(equalTo: ocrPlan2Box.contentView) ocrPlanRadio2_.km_add_width_constraint(constant: ocrPlanRadio2_.properties.propertyInfo.viewWidth + 10) hLine.addSubview(vLine_) vLine_.frame = hLine.bounds vLine_.autoresizingMask = [.width, .height] extractTextBox.borderWidth = 0 extractTextBox.contentView = extractTextCheckBox_ } func updateViewColor() { self.view.layer?.backgroundColor = ComponentLibrary.shared.getComponentColorFromKey("colorBg-layout-middle").cgColor } func updateLanguageButton(_ languages: [String]?) { if languages?.count ?? 0 < 1 { self.languageView_.properties.text = " " + KMLocalizedString("Auto Detection") self.languageView_.reloadData() return } var languageName: String = "" 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.languageView_.properties.text = " " + languageName self.languageView_.reloadData() } func converArrType(arr: Array, keyString: String) -> [String] { let newArr = NSMutableArray() for item in arr { newArr.add(item.filePath) } return newArr as! [String] } func isConnectionAvailable() -> Bool { if Reachability.forInternetConnection().currentReachabilityStatus().rawValue == 0 { return false } return true } func beginImageToPDF() { if self.files?.count ?? 0 < 1 { return } let photoArray = converArrType(arr: self.files!, keyString: "") var path: String = "" var isMerge = false var isCreatNewPDF = false var isOCR = false if ocrCheckBox_.properties.checkboxType == .selected { isOCR = true } var isSaveAs = false if extractTextCheckBox_.properties.checkboxType == .selected { isSaveAs = true } let plan = UserDefaults.standard.integer(forKey: "KMOCRCurrentPlanKey") if isOCR && !self.isConnectionAvailable() && plan == 0 { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = KMLocalizedString("Connection Error", comment: "") alert.informativeText = KMLocalizedString("Please make sure your internet connection is available.", comment: "") alert.addButton(withTitle: KMLocalizedString("OK", comment: "")) if alert.responds(to: #selector(alert.beginSheetModal(for:completionHandler:))) { alert.beginSheetModal(for: self.view.window!, completionHandler: nil) } else { alert.runModal() } return } if createNewPDFRadio_.properties.checkboxType == .selected { if (self.choosePath.count < 1) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = String(format: KMLocalizedString("Output Folder cannot be empty.", comment: "")) alert.runModal() return } path = self.choosePath if mergeAllCheckBox_.properties.checkboxType == .selected { isMerge = true } isCreatNewPDF = true } else { let appenString = appendBackInput_.properties.text if appenString.isEmpty { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = String(format: KMLocalizedString("Select a File", comment: "")) alert.runModal() return } path = appenString isMerge = true isCreatNewPDF = false } let planDisabled = ocrPlanRadio_.properties.isDisabled ocrPlanRadio_.properties.isDisabled = true ocrPlanRadio_.reloadData() ocrPlanRadio2_.properties.isDisabled = true ocrPlanRadio2_.reloadData() self.method.password = self.password self.interfaceStatus = .Processing self.method.saveAsTestPath = self.choosePath self.method.exportPDFFile(fileArray: photoArray, savePath: path, isOCR: isOCR, isCreatPDF: isCreatNewPDF, isMerge: isMerge, isSaveAsText: isSaveAs) { [weak self] savePath, errorArr, errorOCRArray in self?.ocrPlanRadio_.properties.isDisabled = planDisabled self?.ocrPlanRadio_.reloadData() self?.ocrPlanRadio2_.properties.isDisabled = planDisabled self?.ocrPlanRadio2_.reloadData() self?.applyButton.properties.isDisabled = false self?.applyButton.properties.state = .normal self?.applyButton.reloadData() self?.interfaceStatus = .PrepareProcess if errorArr.count > 0 { let dict: [String: Any] = ["isMerge": false, "isSuccess": false] NotificationCenter.default.post(name: NSNotification.Name(rawValue: "KMBatchOperateImageToPDFSuccessNotification"), object: self, userInfo: dict) let alert = NSAlert() alert.messageText = KMLocalizedString("Conversion Failed", comment: "") alert.addButton(withTitle: KMLocalizedString("OK", comment: "")) alert.informativeText = "\(errorArr)" alert.alertStyle = .informational alert.runModal() } else { if errorOCRArray.count > 0 { var contextString = KMLocalizedString("Some problems occurred during the last operation:", comment: "") for filePath in errorOCRArray { contextString += "\n" + (filePath as AnyObject).lastPathComponent } let alert = NSAlert() alert.messageText = KMLocalizedString("Converted Successfully", comment: "") alert.addButton(withTitle: KMLocalizedString("OK", comment: "")) alert.informativeText = contextString alert.alertStyle = .informational let response = alert.runModal() if response == .OK { self?.viewFileAtFinder(fileName: savePath) } } else { self?.viewFileAtFinder(fileName: savePath) } } } } func viewFileAtFinder(fileName: String) { let dict = ["isMerge": true, "isSuccess": true] NotificationCenter.default.post(name: Notification.Name("KMBatchOperateImageToPDFSuccessNotification"), object: self, userInfo: dict) let workspace = NSWorkspace.shared let url = URL(fileURLWithPath: fileName) workspace.activateFileViewerSelecting([url]) } // MARK: - Actions @objc func ocrPlanAction(_ sender: ComponentRadio) { for radio in [ocrPlanRadio_, ocrPlanRadio2_] { if radio.isEqual(to: sender) { radio.properties.checkboxType = .selected radio.reloadData() KMGOCRManager.default().ocrType = .google KMDataManager.ud_set(0, forKey: "KMOCRCurrentPlanKey") } else { radio.properties.checkboxType = .normal radio.reloadData() KMGOCRManager.default().ocrType = .apple KMDataManager.ud_set(1, forKey: "KMOCRCurrentPlanKey") } } self.OCRSelectedPlanChangeAction() } @IBAction func buttonClicked_CreateNewPDF(_ sender: ComponentRadio) { if (sender.properties.checkboxType == .selected) { mergeAllCheckBox_.properties.isDisabled = false mergeAllCheckBox_.reloadData() appendRadio_.properties.checkboxType = .normal appendRadio_.reloadData() appendBackInput_.properties.isDisabled = true appendBackInput_.reloadData() appendBackButtonInput_.properties.isDisabled = true appendBackButtonInput_.reloadData() } } @IBAction func buttonClicked_AppendOtherPDF(_ sender: ComponentRadio) { if (sender.properties.checkboxType == .selected) { createNewPDFRadio_.properties.checkboxType = .normal createNewPDFRadio_.reloadData() mergeAllCheckBox_.properties.checkboxType = .normal mergeAllCheckBox_.properties.isDisabled = true mergeAllCheckBox_.reloadData() appendBackInput_.properties.isDisabled = false appendBackInput_.reloadData() appendBackButtonInput_.properties.isDisabled = false appendBackButtonInput_.reloadData() } } @IBAction func buttonClicked_OCRSelect(_ sender: ComponentCheckBox) { //MARK: 判断是否付费用户 if IAPProductsManager.default().isAvailableAllFunction() == false { KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) ocrCheckBox_.properties.checkboxType = .normal ocrCheckBox_.reloadData() return } if (sender.properties.checkboxType == .selected) { languageView_.properties.isDisabled = false languageView_.reloadData() ocrPlanRadio_.properties.isDisabled = false ocrPlanRadio_.reloadData() ocrPlanRadio2_.properties.isDisabled = false ocrPlanRadio2_.reloadData() extractTextCheckBox_.properties.isDisabled = false extractTextCheckBox_.reloadData() } else { languageView_.properties.isDisabled = true languageView_.reloadData() ocrPlanRadio_.properties.isDisabled = true ocrPlanRadio_.reloadData() ocrPlanRadio2_.properties.isDisabled = true ocrPlanRadio2_.reloadData() extractTextCheckBox_.properties.isDisabled = true extractTextCheckBox_.reloadData() } } @IBAction func buttonClicked_ImageToPDF(_ sender: ComponentButton) { //MARK: 判断是否付费用户,展示iap界面 if self.files?.count ?? 0 < 1 { return } if IAPProductsManager.default().isAvailableAllFunction() == false && self.files?.count ?? 0 > 1{ KMPurchaseCompareWindowController.sharedInstance().showWindow(nil) return } if sender.properties.state == .pressed { self.choosePath = "" var hasTask = false for i in 0..<(self.files?.count ?? 0) { let file = self.files?[i] file?.currentOperateInfo?.resetState() if file?.fileType == .Image { hasTask = true } } if !hasTask { NSSound.beep() return } var isOCR = false if ocrCheckBox_.properties.checkboxType == .selected { isOCR = true } var isSaveAs = false if extractTextCheckBox_.properties.checkboxType == .selected { isSaveAs = true } let plan = UserDefaults.standard.integer(forKey: "KMOCRCurrentPlanKey") if isOCR && !isConnectionAvailable() && plan == 0 { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = KMLocalizedString("Connection Error", comment: "") alert.informativeText = KMLocalizedString("Please make sure your internet connection is available.", comment: "") alert.addButton(withTitle: KMLocalizedString("OK", comment: "")) if let window = self.view.window { alert.beginSheetModal(for: window, completionHandler: nil) } else { alert.runModal() } return } if createNewPDFRadio_.properties.checkboxType != .selected { let appenString = appendBackInput_.properties.text if appenString.isEmpty { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = KMLocalizedString("Select a File", comment: "") alert.runModal() return } } let openPanel = NSOpenPanel() openPanel.canChooseFiles = false openPanel.canChooseDirectories = true openPanel.canCreateDirectories = true openPanel.beginSheetModal(for: self.view.window!) { (result) in if result == .OK { for fileURL in openPanel.urls { self.choosePath = fileURL.path self.beginImageToPDF() } } } } else { // Do something else } } } @IBAction func buttonItemClicked_AppendOtherPDF(_ sender: NSButton) { let isDisabled = appendBackButtonInput_.properties.isDisabled if isDisabled { return } let openPanel = NSOpenPanel() openPanel.allowedFileTypes = ["pdf"] openPanel.canChooseDirectories = false openPanel.allowsMultipleSelection = false openPanel.beginSheetModal(for: self.view.window!) { (result) in if result == .OK { guard let url = openPanel.url else { return } guard let document = PDFDocument(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 { KMBaseWindowController.checkPassword(url: url, type: .owner) { [weak self] success, resultPassword in if success { self?.password = resultPassword self?.appendBackInput_.properties.text = url.path self?.appendBackInput_.reloadData() } } } else { self.appendBackInput_.properties.text = url.path self.appendBackInput_.reloadData() } } } } // "Choose automatic language detection for better OCR results." //MARK: -Notification @objc func batchFilesCountNotification(notification: Notification) { let files: Array? = notification.object as? [KMBatchOperateFile] self.files? = files ?? [] let cnt = self.files?.count ?? 0 if cnt > 0 { self._updateActionButtonEnable(true) } else { self._updateActionButtonEnable(false) } } func OCRSelectedPlanChangeAction() { KMGOCRManager.default().selectedLanguages = NSMutableArray() self.updateLanguageButton(KMGOCRManager.default().selectedLanguages?.value(forKeyPath: KMGOCRLanguageStringKey) as? [String]) } } // MARK: - KMImageToPDFMethodDelegate extension KMBatchOperateImageToPDFViewController: KMImageToPDFMethodDelegate { func imageToPDFMethod(_ method: KMImageToPDFMethod, progress: Float) { } } // MARK: - ComponentSelectDelegate extension KMBatchOperateImageToPDFViewController: ComponentSelectDelegate { func componentSelectDidSelect(view: ComponentSelect?, menuItemProperty: ComponentMenuitemProperty?) { let idx = view?.indexOfSelect() ?? 0 let languages = KMGOCRManager.languages() as NSArray let lanuage = languages[idx] KMGOCRManager.default().selectedLanguages = [lanuage] } }