// // KMNPopOperationWindowController.swift // PDF Reader Pro // // Created by 丁林圭 on 2024/12/12. // import Cocoa import KMComponentLibrary @objc public enum OperationType: Int, CaseIterable{ case crop = 0 case ocr case operationNone } typealias OperaCropCallback = () -> () typealias KMNPopOperationWindowControllerOCRAction = () -> () class KMNPopOperationViewController: KMNBaseViewController { @IBOutlet weak var contentBox: NSBox! @IBOutlet weak var operationBox: NSBox! @IBOutlet weak var operationWidthConstraint: NSLayoutConstraint! @IBOutlet var cropView: NSView! @IBOutlet var closeButton: ComponentButton! @IBOutlet var printButton: ComponentButton! @IBOutlet var extractSelect: ComponentCSelector! @IBOutlet var resetButton: ComponentButton! @IBOutlet var addButton: ComponentButton! @IBOutlet var ocrView: NSView! @IBOutlet var cancelButton: ComponentButton! @IBOutlet var ocrButton: ComponentButton! @IBOutlet weak var cancelWidthConstraint: NSLayoutConstraint! @IBOutlet weak var ocrWidthConstraint: NSLayoutConstraint! private var extractGroupView: ComponentGroup? static let shared: KMNPopOperationViewController = { let windowC = KMNPopOperationViewController(nibName: "KMNPopOperationViewController", bundle: nil) return windowC }() var cropCurrentCallback: OperaCropCallback? var updatePDFViewCallback: UpdatePDFViewCallback? var OCRAction: KMNPopOperationWindowControllerOCRAction? weak var listView:CPDFListView? public var popType:OperationType = .operationNone { didSet { switch popType { case .ocr : ocrView.layoutSubtreeIfNeeded() operationWidthConstraint.constant = ocrView.bounds.width self.view.display() //需刷新约束才会有值,不然会变化 operationBox.contentView = ocrView break case .crop: cropView.layoutSubtreeIfNeeded() operationWidthConstraint.constant = cropView.bounds.width self.view.display() //需刷新约束才会有值,不然会变化 operationBox.contentView = cropView break case .operationNone: break } } } override func viewDidLoad() { super.viewDidLoad() } override func initContentView() { super.initContentView() extractSelect.properties = ComponentCSelectorProperty(iconImage:NSImage(named: "KMNImageNameListViewCropExport")) extractSelect.setTarget(self, action: #selector(extractButtonClicked(_ :))) closeButton.properties = ComponentButtonProperty(type: .text_gray, size: .s, state: .normal, onlyIcon: true, icon:NSImage(named: "KMNImageNameListViewCropClose"), keepPressState: false) closeButton.setTarget(self, action: #selector(closeButtonClicked(_ :))) printButton.properties = ComponentButtonProperty(type: .text_gray, size: .s, state: .normal, onlyIcon: true, icon:NSImage(named: "KMNImageNameListViewCropPrint"), keepPressState: false) printButton.setTarget(self, action: #selector(printButtonClicked(_ :))) addButton.properties = ComponentButtonProperty(type: .text_gray, size: .s, state: .normal, onlyIcon: true, icon:NSImage(named: "KMNImageNameListViewCropAdd"),keepPressState: false) addButton.setTarget(self, action: #selector(addButtonClicked(_ :))) resetButton.properties = ComponentButtonProperty(type: .text_gray, size: .s, state: .normal, onlyIcon: true, icon:NSImage(named: "KMNImageNameListViewCropRest"), keepPressState: false) resetButton.setTarget(self, action: #selector(restButtonClicked(_ :))) } override func updateUIThemeColor() { super.updateUIThemeColor() contentBox.fillColor = ComponentLibrary.shared.getComponentColorFromKey("colorBg/popup") contentBox.borderColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/3-default") } override func updateUILanguage() { super.updateUILanguage() cancelButton.properties = ComponentButtonProperty(type: .default_tertiary, size: .s, state: .normal, buttonText: KMLocalizedString("Cancel")) cancelButton.setTarget(self, action: #selector(cancelButtonClicked(_ :))) ocrButton.properties = ComponentButtonProperty(type: .primary, size: .s, state: .normal, buttonText: KMLocalizedString("OCR")) ocrButton.setTarget(self, action: #selector(ocrButtonClicked(_ :))) ocrWidthConstraint.constant = ocrButton.properties.propertyInfo.viewWidth cancelWidthConstraint.constant = cancelButton.properties.propertyInfo.viewWidth } func removeGroupView() { if extractGroupView != nil { extractGroupView?.removeFromSuperview() } extractSelect.properties.state = .normal extractSelect.reloadData() } //MARK: - Action @objc func cancelButtonClicked(_ sender: NSView) { listView?.selectionRect = NSZeroRect listView?.selectionPageIndex = UInt(NSNotFound) updatePDFViewCallback?() } @objc func ocrButtonClicked(_ sender: NSView) { OCRAction?() } @objc func addButtonClicked(_ sender: NSView) { let rect = NSIntegralRect(listView?.currentSelectionRect() ?? CGRect.zero) let orgPage : CPDFPage = listView?.currentSelectionPage() ?? CPDFPage() if let page : CPDFPage = orgPage.copy() as? CPDFPage { page.setBounds(rect, for: .cropBox) let image = page.thumbnail(of: rect.size) ?? NSImage() let data = image.tiffRepresentation let imageItem = NSPasteboardItem() imageItem.setData(data ?? Data(), forType: .tiff) let pboard = NSPasteboard.general pboard.clearContents() pboard.writeObjects([imageItem]) } } @objc func printButtonClicked(_ sender: NSView) { let rect = listView?.currentSelectionRect() ?? CGRect.zero let page = listView?.currentPage() if page != nil { let copyPage : CPDFPage = page!.copy() as! CPDFPage copyPage.setBounds(rect, for: .cropBox) let image : NSImage = copyPage.thumbnail(of:(copyPage.bounds(for: .cropBox)).size) KMPrintWindowController.printImage(image: image) } } @objc func restButtonClicked(_ sender: NSView) { cropCurrentCallback?() } @objc func extractButtonClicked(_ sender: NSView) { if extractGroupView?.superview != nil { removeGroupView() } else { var viewHeight: CGFloat = 8 var menuItemArr: [ComponentMenuitemProperty] = [] for i in ["jpg", "png", "pdf"] { let properties_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false, itemSelected: false, isDisabled: false, keyEquivalent: nil, text: KMLocalizedString(i)) menuItemArr.append(properties_Menuitem) viewHeight += 36 } if extractGroupView == nil { extractGroupView = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle()) } extractGroupView?.groupDelegate = self extractGroupView?.frame = CGRectMake(310, 0, 72, viewHeight) extractGroupView?.updateGroupInfo(menuItemArr) let point = CGPoint(x: sender.frame.origin.x + sender.frame.size.width/2, y: CGRectGetMinY(sender.frame) - viewHeight) extractGroupView?.showWithPoint(point, relativeTo: sender) extractSelect.properties.state = .pressed extractSelect.reloadData() } } @objc func closeButtonClicked(_ sender: NSView) { listView?.selectionRect = NSZeroRect listView?.selectionPageIndex = UInt(NSNotFound) updatePDFViewCallback?() } } extension KMNPopOperationViewController: ComponentGroupDelegate { func componentGroupDidDismiss(group: ComponentGroup?) { removeGroupView() extractSelect.properties.state = .normal extractSelect.reloadData() } func componentGroupDidSelect(group: ComponentGroup?, menuItemProperty: ComponentMenuitemProperty?) { if group == extractGroupView { let rect = NSIntegralRect(listView?.currentSelectionRect() ?? CGRect.zero) let orgPage : CPDFPage = listView?.currentSelectionPage() ?? CPDFPage() if let page : CPDFPage = orgPage.copy() as? CPDFPage { page.setBounds(rect, for: .cropBox) let image = page.thumbnail(of: rect.size) ?? NSImage() let data = image.tiffRepresentation guard let data = data else { return } let imageRep : NSBitmapImageRep = NSBitmapImageRep(data: data) ?? NSBitmapImageRep() imageRep.size = rect.size let savePanel = NSSavePanel() if let selItem = menuItemProperty { let index = group?.menuItemArr.firstIndex(of: selItem) if index == 0 { savePanel.allowedFileTypes = ["jpg"] let imageData : Data = imageRep.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [:])! savePanel.beginSheetModal(for: listView?.window ?? NSWindow()) { response in if (response != .OK) { return } if NSData(data: imageData).write(to: savePanel.url!, atomically: true) { NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: ""); } } } else if index == 1 { savePanel.allowedFileTypes = ["png"] let imageData : Data = imageRep.representation(using: NSBitmapImageRep.FileType.png, properties: [:])! savePanel.beginSheetModal(for: listView?.window ?? NSWindow()) { response in if (response != .OK) { return } if NSData(data: imageData).write(to: savePanel.url!, atomically: true) { NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: ""); } } } else if index == 2 { savePanel.allowedFileTypes = ["pdf"] let pdfdocument = CPDFDocument() let signatureImagePath = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first?.stringByAppendingPathComponent("signatureImage.png") let imageData : Data = imageRep.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [:])! if NSData(data: imageData).write(to: URL(fileURLWithPath: signatureImagePath!), atomically: true) { pdfdocument?.insertPage(image.size, withImage: signatureImagePath, at: 0) savePanel.beginSheetModal(for: listView?.window ?? NSWindow()) { response in if (response != .OK) { return } if pdfdocument!.write(to: savePanel.url!) { NSWorkspace.shared.selectFile(savePanel.url?.path, inFileViewerRootedAtPath: ""); } } } } } } } } }