KMBatchImageToPDFView.swift 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. //
  2. // KMBatchImageToPDFView.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by lizhe on 2025/1/15.
  6. //
  7. import Cocoa
  8. import KMComponentLibrary
  9. class KMBatchImageToPDFView: KMBatchSettingItemView {
  10. @IBOutlet weak var titleLabel: NSTextField!
  11. @IBOutlet weak var titleContentView: NSView!
  12. @IBOutlet weak var subTitleLabel: NSTextField!
  13. @IBOutlet weak var newPDFDocumentButton: ComponentRadio!
  14. @IBOutlet weak var mergeAllButton: ComponentCheckBox!
  15. @IBOutlet weak var appendToFileButton: ComponentRadio!
  16. @IBOutlet weak var selectFileInputButton: ComponentInput!
  17. @IBOutlet weak var selectFileInputAddonButton: ComponentInputAddon!
  18. @IBOutlet weak var textRecognitionSettingLabel: NSTextField!
  19. @IBOutlet weak var recognizeTextButton: ComponentCheckBox!
  20. @IBOutlet weak var languageSelectButton: ComponentSelect!
  21. @IBOutlet weak var lineView: ComponentDivider!
  22. @IBOutlet weak var OCRPlan1Button: ComponentRadio!
  23. @IBOutlet weak var OCRPlan1ButtonWidthConstraint: NSLayoutConstraint!
  24. @IBOutlet weak var OCRPlan2Button: ComponentRadio!
  25. @IBOutlet weak var OCRPlan2ButtonWidthConstraint: NSLayoutConstraint!
  26. @IBOutlet weak var extractTextButton: ComponentCheckBox!
  27. @IBOutlet weak var applyButton: ComponentButton!
  28. var model: KMBatchImageToPDFModel = KMBatchImageToPDFModel()
  29. var selectIndex = 0
  30. var password: String = ""
  31. override func draw(_ dirtyRect: NSRect) {
  32. super.draw(dirtyRect)
  33. // Drawing code here.
  34. }
  35. override func updateUILanguage() {
  36. self.subTitleLabel.stringValue = KMLocalizedString("Output")
  37. self.newPDFDocumentButton.properties.text = KMLocalizedString("New PDF Document")
  38. self.newPDFDocumentButton.reloadData()
  39. self.mergeAllButton.properties.text = KMLocalizedString("Merge All")
  40. self.mergeAllButton.reloadData()
  41. self.appendToFileButton.properties.text = KMLocalizedString("Append to Existing File")
  42. self.appendToFileButton.reloadData()
  43. self.textRecognitionSettingLabel.stringValue = KMLocalizedString("Text Recognition Settings")
  44. self.recognizeTextButton.properties.text = KMLocalizedString("Recognize text if needed")
  45. self.recognizeTextButton.reloadData()
  46. self.OCRPlan1Button.properties.text = KMLocalizedString("OCR Plan 1 (Online)")
  47. 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.")
  48. self.OCRPlan1Button.reloadData()
  49. self.OCRPlan1ButtonWidthConstraint.constant = self.OCRPlan1Button.properties.propertyInfo.viewWidth
  50. self.OCRPlan2Button.properties.text = KMLocalizedString("OCR Plan 2 (Offline)")
  51. 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.")
  52. self.OCRPlan2Button.reloadData()
  53. self.OCRPlan2ButtonWidthConstraint.constant = self.OCRPlan2Button.properties.propertyInfo.viewWidth
  54. self.extractTextButton.properties.text = KMLocalizedString("Extract Text (.txt)")
  55. self.extractTextButton.reloadData()
  56. self.applyButton.properties.buttonText = KMLocalizedString("Apply")
  57. }
  58. override func updateUIThemeColor() {
  59. self.titleContentView.border(ComponentLibrary.shared.getComponentColorFromKey("colorBorder/divider"), 0.5, 0)
  60. titleLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-medium")
  61. titleLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2")
  62. subTitleLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium")
  63. subTitleLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2")
  64. textRecognitionSettingLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium")
  65. textRecognitionSettingLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2")
  66. }
  67. override func setup() {
  68. self.newPDFDocumentButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, checkboxType: .normal)
  69. self.newPDFDocumentButton.setTarget(self, action: #selector(newPDFDocumentButtonAction))
  70. self.mergeAllButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false,checkboxType: .normal)
  71. self.mergeAllButton.setTarget(self, action: #selector(mergeAllButtonAction))
  72. self.appendToFileButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, checkboxType: .normal)
  73. self.appendToFileButton.setTarget(self, action: #selector(appendToFileButtonAction))
  74. self.recognizeTextButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, checkboxType: .normal)
  75. self.recognizeTextButton.setTarget(self, action: #selector(OCRButtonAction))
  76. let inputWithAddonProperty = ComponentInputProperty(size: .s,
  77. state: .normal,
  78. isError: false,
  79. showPrefix: false,
  80. showSuffix: false,
  81. showClear: false,
  82. isDisabled: true,
  83. placeholder: KMLocalizedString("Select File..."),
  84. text: "",
  85. creatable: false)
  86. selectFileInputButton.properties = inputWithAddonProperty
  87. selectFileInputButton.properties.propertyInfo.cornerRadius_topRight = 0
  88. selectFileInputButton.properties.propertyInfo.cornerRadius_bottomRight = 0
  89. selectFileInputButton.properties.isDisabled = true
  90. selectFileInputButton.reloadData()
  91. selectFileInputAddonButton.properties = ComponentInputAddonProperty(size: .s,
  92. state: .normal,
  93. addOnBefore: false,
  94. onlyRead: false,
  95. addonType: .imageWithColor,
  96. iconImage: NSImage(named: "KMFolderIcon"))
  97. selectFileInputAddonButton.properties.isDisabled = true
  98. selectFileInputAddonButton.reloadData()
  99. selectFileInputAddonButton.setTarget(self, action: #selector(addFilesButtonAction))
  100. self.languageSelectButton.properties = ComponentSelectProperties(size: .s, state: .normal, isDisabled: false, isError: false, leftIcon: false, placeholder: nil, errorText: nil, creatable: false, text: KMLocalizedString("", comment: ""))
  101. self.languageSelectButton.delegate = self
  102. self.OCRPlan1Button.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: true, text: KMLocalizedString("OCR Plan 1 (Online)"), checkboxType: .normal)
  103. OCRPlan1Button.setTarget(self, action: #selector(OCRPlan1ButtonAction))
  104. self.OCRPlan1Button.reloadData()
  105. self.OCRPlan1ButtonWidthConstraint.constant = self.OCRPlan1Button.properties.propertyInfo.viewWidth
  106. self.OCRPlan2Button.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: true, text: KMLocalizedString("OCR Plan 2 (Offline)"), checkboxType: .normal)
  107. OCRPlan2Button.setTarget(self, action: #selector(OCRPlan2ButtonAction))
  108. self.OCRPlan2Button.reloadData()
  109. self.OCRPlan2ButtonWidthConstraint.constant = self.OCRPlan2Button.properties.propertyInfo.viewWidth
  110. self.extractTextButton.properties = ComponentCheckBoxProperty(size: .s, state: .normal, isDisabled: false, showhelp: false, checkboxType: .normal)
  111. extractTextButton.setTarget(self, action: #selector(extractTextButtonAction))
  112. applyButton.properties = ComponentButtonProperty(type: .primary, size: .m, showRightIcon: true, keepPressState: false)
  113. applyButton.setTarget(self, action: #selector(saveButtonClicked(_:)))
  114. self.lineView.properties = ComponentDividerProperty()
  115. super.setup()
  116. }
  117. override func reloadData() {
  118. self.updateLanguages()
  119. self.newPDFDocumentButton.properties.checkboxType = self.model.isNewPDF ? .selected : .normal
  120. self.newPDFDocumentButton.reloadData()
  121. self.mergeAllButton.properties.isDisabled = !self.model.isNewPDF
  122. self.mergeAllButton.reloadData()
  123. self.appendToFileButton.properties.checkboxType = self.model.isAppendToExistingFile ? .selected : .normal
  124. self.appendToFileButton.reloadData()
  125. self.selectFileInputButton.properties.isDisabled = !self.model.isAppendToExistingFile
  126. self.selectFileInputButton.reloadData()
  127. self.selectFileInputAddonButton.properties.isDisabled = !self.model.isAppendToExistingFile
  128. self.selectFileInputAddonButton.reloadData()
  129. self.languageSelectButton.properties.isDisabled = !self.model.isOCR
  130. self.languageSelectButton.reloadData()
  131. if self.model.ocrType == .google {
  132. self.OCRPlan1Button.properties.checkboxType = .selected
  133. self.OCRPlan2Button.properties.checkboxType = .normal
  134. } else if self.model.ocrType == .apple {
  135. self.OCRPlan1Button.properties.checkboxType = .normal
  136. self.OCRPlan2Button.properties.checkboxType = .selected
  137. }
  138. self.OCRPlan1Button.properties.isDisabled = !self.model.isOCR
  139. self.OCRPlan1Button.reloadData()
  140. self.OCRPlan2Button.properties.isDisabled = !self.model.isOCR
  141. self.OCRPlan2Button.reloadData()
  142. self.extractTextButton.properties.isDisabled = !self.model.isOCR
  143. self.extractTextButton.reloadData()
  144. languageSelectButton.selectItemAtIndex(self.selectIndex)
  145. }
  146. func updateLanguages() {
  147. var menuItemArr: [ComponentMenuitemProperty] = []
  148. var languages: [String] = KMOCRManager.manager.getLanguages(type: model.ocrType)
  149. languages.insert(KMLocalizedString("Auto Detection"), at: 0)
  150. for language in languages {
  151. let itemProperty: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false,
  152. itemSelected: false,
  153. isDisabled: false,
  154. keyEquivalent: nil,
  155. text: language, identifier: "1")
  156. menuItemArr.append(itemProperty)
  157. }
  158. languageSelectButton.updateMenuItemsArr(menuItemArr)
  159. let position = languages.firstIndex(of: model.language) ?? 0
  160. self.selectIndex = position
  161. }
  162. override func bacthProcessingNotification() {
  163. self.newPDFDocumentButton.properties.isDisabled = self.isDisable
  164. self.newPDFDocumentButton.reloadData()
  165. self.mergeAllButton.properties.isDisabled = self.isDisable
  166. self.mergeAllButton.reloadData()
  167. self.appendToFileButton.properties.isDisabled = self.isDisable
  168. self.appendToFileButton.reloadData()
  169. self.selectFileInputButton.properties.isDisabled = self.isDisable
  170. self.selectFileInputButton.reloadData()
  171. self.selectFileInputAddonButton.properties.isDisabled = self.isDisable
  172. self.selectFileInputAddonButton.reloadData()
  173. self.recognizeTextButton.properties.isDisabled = self.isDisable
  174. self.recognizeTextButton.reloadData()
  175. self.languageSelectButton.properties.isDisabled = self.isDisable
  176. self.languageSelectButton.reloadData()
  177. self.OCRPlan1Button.properties.isDisabled = self.isDisable
  178. self.OCRPlan1Button.reloadData()
  179. self.OCRPlan2Button.properties.isDisabled = self.isDisable
  180. self.OCRPlan2Button.reloadData()
  181. self.applyButton.properties.isDisabled = self.isDisable
  182. self.applyButton.reloadData()
  183. self.extractTextButton.properties.isDisabled = self.isDisable
  184. self.extractTextButton.reloadData()
  185. }
  186. }
  187. extension KMBatchImageToPDFView: ComponentSelectDelegate {
  188. func componentSelectDidSelect(view: ComponentSelect?, menuItemProperty: ComponentMenuitemProperty?) {
  189. if (view == languageSelectButton) {
  190. var languages: [String] = KMOCRManager.manager.getLanguages(type: model.ocrType)
  191. let position = languages.firstIndex(of: menuItemProperty?.text ?? "") ?? 0
  192. self.selectIndex = position + 1
  193. let values: [String: String] = KMGOCRManager.languages()[position] as? [String : String] ?? [:]
  194. let key = values[KMGOCRLanguageCodeKey]
  195. model.language = key ?? ""
  196. if let unwrappedKey = key, let intValue = Int(unwrappedKey) {
  197. model.languageType = COCRLanguage(rawValue: intValue) ?? .english
  198. } else {
  199. print("转换失败")
  200. }
  201. }
  202. }
  203. }
  204. //MARK: Action
  205. extension KMBatchImageToPDFView {
  206. @objc func saveButtonClicked(_ sender: ComponentButton) {
  207. self.model.selectFilePath = self.selectFileInputButton.properties.text
  208. guard let callBack = self.batchExport else { return }
  209. callBack(self, model)
  210. }
  211. func addFilesButtonAction() {
  212. let openPanel = NSOpenPanel()
  213. openPanel.allowedFileTypes = ["pdf"]
  214. openPanel.canChooseDirectories = false
  215. openPanel.allowsMultipleSelection = false
  216. openPanel.beginSheetModal(for: self.window!) { (result) in
  217. if result == .OK {
  218. guard let url = openPanel.url else { return }
  219. guard let document = CPDFDocument(url: url) else {
  220. let alert = NSAlert()
  221. alert.alertStyle = .critical
  222. alert.messageText = KMLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "")
  223. alert.runModal()
  224. return
  225. }
  226. if !document.allowsCopying || !document.allowsPrinting {
  227. let alert = NSAlert()
  228. alert.alertStyle = .critical
  229. alert.messageText = KMLocalizedString("This is a secured document. Editing is not permitted.", comment: "")
  230. alert.runModal()
  231. return
  232. }
  233. if document.isLocked {
  234. NSWindowController.checkPassword(url: url, type: .owner) { [weak self] success, resultPassword in
  235. if success {
  236. self?.password = resultPassword
  237. self?.selectFileInputButton.properties.text = url.path
  238. self?.selectFileInputButton.reloadData()
  239. }
  240. }
  241. } else {
  242. self.selectFileInputButton.properties.text = url.path
  243. self.selectFileInputButton.reloadData()
  244. }
  245. }
  246. }
  247. }
  248. func newPDFDocumentButtonAction() {
  249. self.model.isNewPDF = !self.model.isNewPDF
  250. self.model.isAppendToExistingFile = !self.model.isNewPDF
  251. self.reloadData()
  252. }
  253. func mergeAllButtonAction() {
  254. self.model.isMergeAll = !self.model.isMergeAll
  255. self.reloadData()
  256. }
  257. func appendToFileButtonAction() {
  258. self.model.isAppendToExistingFile = !self.model.isAppendToExistingFile
  259. self.model.isNewPDF = !self.model.isAppendToExistingFile
  260. self.reloadData()
  261. }
  262. func OCRButtonAction() {
  263. self.model.isOCR = !self.model.isOCR
  264. self.reloadData()
  265. }
  266. func OCRPlan1ButtonAction() {
  267. self.model.ocrType = .google
  268. self.reloadData()
  269. }
  270. func OCRPlan2ButtonAction() {
  271. self.model.ocrType = .apple
  272. self.reloadData()
  273. }
  274. func extractTextButtonAction() {
  275. self.model.isExtractText = !self.model.isExtractText
  276. self.reloadData()
  277. }
  278. }