KMNPopOperationWindowController.swift 16 KB

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