KMBatchImageToPDFView.swift 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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. }
  163. extension KMBatchImageToPDFView: ComponentSelectDelegate {
  164. func componentSelectDidSelect(view: ComponentSelect?, menuItemProperty: ComponentMenuitemProperty?) {
  165. if (view == languageSelectButton) {
  166. var languages: [String] = KMOCRManager.manager.getLanguages(type: model.ocrType)
  167. let position = languages.firstIndex(of: model.language) ?? 0
  168. self.selectIndex = position + 1
  169. let values: [String: String] = KMGOCRManager.languages()[position] as? [String : String] ?? [:]
  170. let key = values[KMGOCRLanguageCodeKey]
  171. model.language = key ?? ""
  172. if let unwrappedKey = key, let intValue = Int(unwrappedKey) {
  173. model.languageType = COCRLanguage(rawValue: intValue) ?? .english
  174. } else {
  175. print("转换失败")
  176. }
  177. }
  178. }
  179. }
  180. //MARK: Action
  181. extension KMBatchImageToPDFView {
  182. @objc func saveButtonClicked(_ sender: ComponentButton) {
  183. self.model.selectFilePath = self.selectFileInputButton.properties.text
  184. guard let callBack = self.batchExport else { return }
  185. callBack(self, model)
  186. }
  187. func addFilesButtonAction() {
  188. let openPanel = NSOpenPanel()
  189. openPanel.allowedFileTypes = ["pdf"]
  190. openPanel.canChooseDirectories = false
  191. openPanel.allowsMultipleSelection = false
  192. openPanel.beginSheetModal(for: self.window!) { (result) in
  193. if result == .OK {
  194. guard let url = openPanel.url else { return }
  195. guard let document = CPDFDocument(url: url) else {
  196. let alert = NSAlert()
  197. alert.alertStyle = .critical
  198. alert.messageText = KMLocalizedString("An error occurred while opening this document. The file is damaged and could not be repaired.", comment: "")
  199. alert.runModal()
  200. return
  201. }
  202. if !document.allowsCopying || !document.allowsPrinting {
  203. let alert = NSAlert()
  204. alert.alertStyle = .critical
  205. alert.messageText = KMLocalizedString("This is a secured document. Editing is not permitted.", comment: "")
  206. alert.runModal()
  207. return
  208. }
  209. if document.isLocked {
  210. KMBaseWindowController.checkPassword(url: url, type: .owner) { [weak self] success, resultPassword in
  211. if success {
  212. self?.password = resultPassword
  213. self?.selectFileInputButton.properties.text = url.path
  214. self?.selectFileInputButton.reloadData()
  215. }
  216. }
  217. } else {
  218. self.selectFileInputButton.properties.text = url.path
  219. self.selectFileInputButton.reloadData()
  220. }
  221. }
  222. }
  223. }
  224. func newPDFDocumentButtonAction() {
  225. self.model.isNewPDF = !self.model.isNewPDF
  226. self.model.isAppendToExistingFile = !self.model.isNewPDF
  227. self.reloadData()
  228. }
  229. func mergeAllButtonAction() {
  230. self.model.isMergeAll = !self.model.isMergeAll
  231. self.reloadData()
  232. }
  233. func appendToFileButtonAction() {
  234. self.model.isAppendToExistingFile = !self.model.isAppendToExistingFile
  235. self.model.isNewPDF = !self.model.isAppendToExistingFile
  236. self.reloadData()
  237. }
  238. func OCRButtonAction() {
  239. self.model.isOCR = !self.model.isOCR
  240. self.reloadData()
  241. }
  242. func OCRPlan1ButtonAction() {
  243. self.model.ocrType = .google
  244. self.reloadData()
  245. }
  246. func OCRPlan2ButtonAction() {
  247. self.model.ocrType = .apple
  248. self.reloadData()
  249. }
  250. func extractTextButtonAction() {
  251. self.model.isExtractText = !self.model.isExtractText
  252. self.reloadData()
  253. }
  254. }