KMNPopOperationWindowController.swift 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. //
  2. // KMNPopOperationWindowController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by 丁林圭 on 2024/12/12.
  6. //
  7. import Cocoa
  8. import KMComponentLibrary
  9. @objc public enum OperationType: Int, CaseIterable{
  10. case crop = 0
  11. case ocr
  12. case operationNone
  13. }
  14. typealias OperaCropCallback = () -> ()
  15. typealias KMNPopOperationWindowControllerOCRAction = () -> ()
  16. class KMNPopOperationWindowController: KMNBaseWindowController {
  17. @IBOutlet weak var contentBox: NSBox!
  18. @IBOutlet weak var operationBox: NSBox!
  19. @IBOutlet weak var operationWidthConstraint: NSLayoutConstraint!
  20. @IBOutlet var cropView: NSView!
  21. @IBOutlet var closeButton: ComponentButton!
  22. @IBOutlet var printButton: ComponentButton!
  23. @IBOutlet var extractSelect: ComponentCSelector!
  24. @IBOutlet var resetButton: ComponentButton!
  25. @IBOutlet var addButton: ComponentButton!
  26. @IBOutlet var ocrView: NSView!
  27. @IBOutlet var cancelButton: ComponentButton!
  28. @IBOutlet var ocrButton: ComponentButton!
  29. @IBOutlet weak var cancelWidthConstraint: NSLayoutConstraint!
  30. @IBOutlet weak var ocrWidthConstraint: NSLayoutConstraint!
  31. private var extractGroupView: ComponentGroup?
  32. static let shared: KMNPopOperationWindowController = {
  33. let windowC = KMNPopOperationWindowController(windowNibName: "KMNPopOperationWindowController")
  34. return windowC
  35. }()
  36. var cropCurrentCallback: OperaCropCallback?
  37. var updatePDFViewCallback: UpdatePDFViewCallback?
  38. var OCRAction: KMNPopOperationWindowControllerOCRAction?
  39. weak var listView:CPDFListView?
  40. public var popType:OperationType = .operationNone {
  41. didSet {
  42. switch popType {
  43. case .ocr :
  44. ocrView.layoutSubtreeIfNeeded()
  45. operationWidthConstraint.constant = ocrView.bounds.width
  46. self.window?.display() //需刷新约束才会有值,不然会变化
  47. operationBox.contentView = ocrView
  48. break
  49. case .crop:
  50. cropView.layoutSubtreeIfNeeded()
  51. operationWidthConstraint.constant = cropView.bounds.width
  52. self.window?.display() //需刷新约束才会有值,不然会变化
  53. operationBox.contentView = cropView
  54. break
  55. case .operationNone:
  56. break
  57. }
  58. }
  59. }
  60. override func windowDidLoad() {
  61. super.windowDidLoad()
  62. }
  63. override func initContentView() {
  64. super.initContentView()
  65. extractSelect.properties = ComponentCSelectorProperty(iconImage:NSImage(named: "KMNImageNameListViewCropExport"))
  66. extractSelect.setTarget(self, action: #selector(extractButtonClicked(_ :)))
  67. closeButton.properties = ComponentButtonProperty(type: .text_gray,
  68. size: .s,
  69. state: .normal,
  70. onlyIcon: true,
  71. icon:NSImage(named: "KMNImageNameListViewCropClose"),
  72. keepPressState: false)
  73. closeButton.setTarget(self, action: #selector(closeButtonClicked(_ :)))
  74. printButton.properties = ComponentButtonProperty(type: .text_gray,
  75. size: .s,
  76. state: .normal,
  77. onlyIcon: true,
  78. icon:NSImage(named: "KMNImageNameListViewCropPrint"),
  79. keepPressState: false)
  80. printButton.setTarget(self, action: #selector(printButtonClicked(_ :)))
  81. addButton.properties = ComponentButtonProperty(type: .text_gray,
  82. size: .s,
  83. state: .normal,
  84. onlyIcon: true,
  85. icon:NSImage(named: "KMNImageNameListViewCropAdd"),keepPressState: false)
  86. addButton.setTarget(self, action: #selector(addButtonClicked(_ :)))
  87. resetButton.properties = ComponentButtonProperty(type: .text_gray,
  88. size: .s,
  89. state: .normal,
  90. onlyIcon: true,
  91. icon:NSImage(named: "KMNImageNameListViewCropRest"),
  92. keepPressState: false)
  93. resetButton.setTarget(self, action: #selector(restButtonClicked(_ :)))
  94. }
  95. override func updateUIThemeColor() {
  96. super.updateUIThemeColor()
  97. contentBox.fillColor = ComponentLibrary.shared.getComponentColorFromKey("colorBg/popup")
  98. contentBox.borderColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/3-default")
  99. }
  100. override func updateUILanguage() {
  101. super.updateUILanguage()
  102. cancelButton.properties = ComponentButtonProperty(type: .default_tertiary,
  103. size: .s,
  104. state: .normal,
  105. buttonText: KMLocalizedString("Cancel"))
  106. cancelButton.setTarget(self, action: #selector(cancelButtonClicked(_ :)))
  107. ocrButton.properties = ComponentButtonProperty(type: .primary,
  108. size: .s,
  109. state: .normal,
  110. buttonText: KMLocalizedString("OCR"))
  111. ocrButton.setTarget(self, action: #selector(ocrButtonClicked(_ :)))
  112. ocrWidthConstraint.constant = ocrButton.properties.propertyInfo.viewWidth
  113. cancelWidthConstraint.constant = cancelButton.properties.propertyInfo.viewWidth
  114. }
  115. func removeGroupView() {
  116. if extractGroupView != nil {
  117. extractGroupView?.removeFromSuperview()
  118. }
  119. extractSelect.properties.state = .normal
  120. extractSelect.reloadData()
  121. }
  122. //MARK: - Public
  123. public func updateFrame(listView:CPDFListView?,page:CPDFPage?) {
  124. let windowFram = listView?.window?.frame ?? CGRectZero
  125. let pageRect = listView?.currentSelectionRect() ?? NSRect.zero
  126. if page != nil {
  127. let positioningRect = listView?.convert(pageRect, from: page!) ?? NSRect.zero
  128. if (CGRectIntersectsRect(positioningRect, listView?.frame ?? CGRectZero)) {
  129. let view: NSView? = nil
  130. let position = listView?.convert(positioningRect, to: view) ?? NSRect.zero
  131. var positionNew = position.origin
  132. positionNew.x += windowFram.origin.x + position.width
  133. positionNew.y += windowFram.origin.y
  134. var positionRect = self.window?.frame ?? CGRectZero
  135. positionRect.origin.x = positionNew.x - positionRect.width
  136. positionRect.origin.y = positionNew.y - popOffSet - positionRect.height
  137. var listViewWindRect = listView?.convert(listView?.frame ?? CGRect.zero, to: view) ?? CGRect.zero
  138. listViewWindRect.origin.x += windowFram.origin.x
  139. listViewWindRect.origin.y += windowFram.origin.y
  140. if CGRectGetMinY(positionRect) < CGRectGetMinY(listViewWindRect) {
  141. positionRect.origin.y = positionNew.y + popOffSet + position.height
  142. }
  143. if CGRectGetMinX(positionRect) < CGRectGetMinX(listViewWindRect) {
  144. positionRect.origin.x = CGRectGetMinX(listViewWindRect)
  145. }
  146. if CGRectGetMaxX(positionRect) > CGRectGetMaxX(listViewWindRect) {
  147. positionRect.origin.x = CGRectGetMaxX(listViewWindRect) - positionRect.width
  148. }
  149. self.window?.setFrame(positionRect, display: true)
  150. updateUILanguage()
  151. }
  152. }
  153. }
  154. public func closeWindow(listView:CPDFListView?) {
  155. if self.window?.isVisible == true {
  156. listView?.window?.removeChildWindow(self.window ?? NSWindow())
  157. self.window?.close()
  158. }
  159. }
  160. //MARK: - Action
  161. @objc func cancelButtonClicked(_ sender: NSView) {
  162. listView?.selectionRect = NSZeroRect
  163. listView?.selectionPageIndex = UInt(NSNotFound)
  164. updatePDFViewCallback?()
  165. }
  166. @objc func ocrButtonClicked(_ sender: NSView) {
  167. OCRAction?()
  168. }
  169. @objc func addButtonClicked(_ sender: NSView) {
  170. let rect = NSIntegralRect(listView?.currentSelectionRect() ?? CGRect.zero)
  171. let orgPage : CPDFPage = listView?.currentSelectionPage() ?? CPDFPage()
  172. if let page : CPDFPage = orgPage.copy() as? CPDFPage {
  173. page.setBounds(rect, for: .cropBox)
  174. let image = page.thumbnail(of: rect.size) ?? NSImage()
  175. let data = image.tiffRepresentation
  176. let imageItem = NSPasteboardItem()
  177. imageItem.setData(data ?? Data(), forType: .tiff)
  178. let pboard = NSPasteboard.general
  179. pboard.clearContents()
  180. pboard.writeObjects([imageItem])
  181. }
  182. }
  183. @objc func printButtonClicked(_ sender: NSView) {
  184. let rect = listView?.currentSelectionRect() ?? CGRect.zero
  185. let page = listView?.currentPage()
  186. if page != nil {
  187. let copyPage : CPDFPage = page!.copy() as! CPDFPage
  188. copyPage.setBounds(rect, for: .cropBox)
  189. let image : NSImage = copyPage.thumbnail(of:(copyPage.bounds(for: .cropBox)).size)
  190. KMPrintWindowController.printImage(image: image)
  191. }
  192. }
  193. @objc func restButtonClicked(_ sender: NSView) {
  194. cropCurrentCallback?()
  195. }
  196. @objc func extractButtonClicked(_ sender: NSView) {
  197. if extractGroupView?.superview != nil {
  198. removeGroupView()
  199. } else {
  200. var viewHeight: CGFloat = 8
  201. var menuItemArr: [ComponentMenuitemProperty] = []
  202. for i in ["jpg", "png", "pdf"] {
  203. let properties_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false,
  204. itemSelected: false,
  205. isDisabled: false,
  206. keyEquivalent: nil,
  207. text: KMLocalizedString(i))
  208. menuItemArr.append(properties_Menuitem)
  209. viewHeight += 36
  210. }
  211. if extractGroupView == nil {
  212. extractGroupView = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle())
  213. }
  214. extractGroupView?.groupDelegate = self
  215. extractGroupView?.frame = CGRectMake(310, 0, 72, viewHeight)
  216. extractGroupView?.updateGroupInfo(menuItemArr)
  217. let point = CGPoint(x: sender.frame.origin.x + sender.frame.size.width/2, y: CGRectGetMinY(sender.frame) - viewHeight)
  218. extractGroupView?.showWithPoint(point, relativeTo: self.window?.contentView)
  219. extractSelect.properties.state = .pressed
  220. extractSelect.reloadData()
  221. }
  222. }
  223. @objc func closeButtonClicked(_ sender: NSView) {
  224. listView?.selectionRect = NSZeroRect
  225. listView?.selectionPageIndex = UInt(NSNotFound)
  226. updatePDFViewCallback?()
  227. }
  228. }
  229. extension KMNPopOperationWindowController: ComponentGroupDelegate {
  230. func componentGroupDidDismiss(group: ComponentGroup?) {
  231. removeGroupView()
  232. extractSelect.properties.state = .normal
  233. extractSelect.reloadData()
  234. }
  235. func componentGroupDidSelect(group: ComponentGroup?, menuItemProperty: ComponentMenuitemProperty?) {
  236. if group == extractGroupView {
  237. let rect = NSIntegralRect(listView?.currentSelectionRect() ?? CGRect.zero)
  238. let orgPage : CPDFPage = listView?.currentSelectionPage() ?? CPDFPage()
  239. if let page : CPDFPage = orgPage.copy() as? CPDFPage {
  240. page.setBounds(rect, for: .cropBox)
  241. let image = page.thumbnail(of: rect.size) ?? NSImage()
  242. let data = image.tiffRepresentation
  243. guard let data = data else { return }
  244. let imageRep : NSBitmapImageRep = NSBitmapImageRep(data: data) ?? NSBitmapImageRep()
  245. imageRep.size = rect.size
  246. let savePanel = NSSavePanel()
  247. if let selItem = menuItemProperty {
  248. let index = group?.menuItemArr.firstIndex(of: selItem)
  249. if index == 0 {
  250. savePanel.allowedFileTypes = ["jpg"]
  251. let imageData : Data = imageRep.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [:])!
  252. savePanel.beginSheetModal(for: listView?.window ?? NSWindow()) { response in
  253. if (response != .OK) {
  254. return
  255. }
  256. if NSData(data: imageData).write(to: savePanel.url!, atomically: true) {
  257. NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: "");
  258. }
  259. }
  260. } else if index == 1 {
  261. savePanel.allowedFileTypes = ["png"]
  262. let imageData : Data = imageRep.representation(using: NSBitmapImageRep.FileType.png, properties: [:])!
  263. savePanel.beginSheetModal(for: listView?.window ?? NSWindow()) { response in
  264. if (response != .OK) {
  265. return
  266. }
  267. if NSData(data: imageData).write(to: savePanel.url!, atomically: true) {
  268. NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: "");
  269. }
  270. }
  271. } else if index == 2 {
  272. savePanel.allowedFileTypes = ["pdf"]
  273. let pdfdocument = CPDFDocument()
  274. let signatureImagePath = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first?.stringByAppendingPathComponent("signatureImage.png")
  275. let imageData : Data = imageRep.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [:])!
  276. if NSData(data: imageData).write(to: URL(fileURLWithPath: signatureImagePath!), atomically: true) {
  277. pdfdocument?.insertPage(image.size, withImage: signatureImagePath, at: 0)
  278. savePanel.beginSheetModal(for: listView?.window ?? NSWindow()) { response in
  279. if (response != .OK) {
  280. return
  281. }
  282. if pdfdocument!.write(to: savePanel.url!) {
  283. NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: "");
  284. }
  285. }
  286. }
  287. }
  288. }
  289. }
  290. }
  291. }
  292. }