// // KMEditImagePropertyViewController.swift // PDF Master // // Created by lxy on 2022/12/28. // import Cocoa class KMEditImagePropertyViewController: NSViewController { @IBOutlet weak var titleLabel: NSTextField! @IBOutlet weak var editImageView: NSImageView! @IBOutlet weak var opacityTitleLabel: NSTextField! @IBOutlet weak var opacitySlider: NSSlider! @IBOutlet weak var opacityPopUpButton: KMComboBox! @IBOutlet weak var alignTitleLabel: NSTextField! @IBOutlet weak var cutButton: NSButton! @IBOutlet weak var replaceButton: NSButton! @IBOutlet weak var exportButton: NSButton! @IBOutlet weak var headerBox: NSBox! @IBOutlet weak var cancelCutButton: NSButton! @IBOutlet weak var cutRightConstraint: NSLayoutConstraint! @IBOutlet weak var headerBoxHeight: NSLayoutConstraint! @IBOutlet weak var imageBox: NSBox! @IBOutlet weak var imageBoxHeight: NSLayoutConstraint! @IBOutlet weak var opacityBoxHeight: NSLayoutConstraint! @IBOutlet weak var opacityBox: NSBox! @IBOutlet weak var buttonBoxHeight: NSLayoutConstraint! @IBOutlet weak var buttonBox: NSBox! @IBOutlet weak var areasLeftButton: NSButton! @IBOutlet weak var areasVerticalCenterButton: NSButton! @IBOutlet weak var areasHorzontalButton: NSButton! @IBOutlet weak var areasVerticalButton: NSButton! @IBOutlet weak var areasBotoomButton: NSButton! @IBOutlet weak var areasHorizontalCenterButton: NSButton! @IBOutlet weak var areasTopButton: NSButton! @IBOutlet weak var areasRightButton: NSButton! let items = ["10","20","50","80","100"] var imagesAreas : [CPDFEditImageArea] = [] var listView : CPDFListView! override func viewDidLoad() { super.viewDidLoad() self.updateButtonState(hidden: true) self.editImageView.wantsLayer = true self.editImageView.layer?.backgroundColor = NSColor.white.cgColor self.opacityPopUpButton.removeAllItems() for i in 0 ... items.count-1 { self.opacityPopUpButton.addItem(withObjectValue: "\(items[i])%") } self.opacityPopUpButton.selectItem(at:items.count-1) self.titleLabel.stringValue = NSLocalizedString("Image", comment: "") self.opacityTitleLabel.stringValue = NSLocalizedString("Opacity", comment: "") self.cutButton.title = NSLocalizedString("Crop", comment: "") self.cancelCutButton.title = NSLocalizedString("Cancel", comment: "") self.replaceButton.title = NSLocalizedString("Replace", comment: "") self.exportButton.title = NSLocalizedString("Extract", comment: "") self.alignTitleLabel.stringValue = NSLocalizedString("Align", comment: "") self.updateButtonState(hidden: true) self.reloadData() } func reloadData() { self.formAearsAlignIcon() imagesAreas = [] if self.listView.editingAreas()?.count ?? 0 < 1 { return } let areas = self.listView.editingAreas() for i in 0 ... areas!.count-1 { if areas![i] is CPDFEditImageArea { imagesAreas.append(areas![i] as! CPDFEditImageArea) } } if imagesAreas.count == 1 && imagesAreas.count == areas!.count{ //单个图片 self.listView.selectImageAreas = imagesAreas.first self.headerBox.isHidden = false self.headerBoxHeight.constant = 170 self.imageBox.isHidden = false self.imageBoxHeight.constant = 90 self.opacityBox.isHidden = false self.opacityBoxHeight.constant = 48 self.buttonBox.isHidden = false self.cutButton.isHidden = false self.cancelCutButton.isHidden = false self.replaceButton.isHidden = false self.buttonBoxHeight.constant = 100 self.editImageView.image = self.listView.selectImageAreas.thumbnailImage self.opacitySlider.objectValue = self.listView.opacity(for: imagesAreas.first) self.opacityPopUpButton.stringValue = "\(Int(self.listView.opacity(for: imagesAreas.first)*100))%" } else if imagesAreas.count > 1 && imagesAreas.count == areas!.count { //多选图片 self.headerBox.isHidden = false self.headerBoxHeight.constant = 80 self.imageBox.isHidden = true self.imageBoxHeight.constant = 0 self.opacityBox.isHidden = false self.opacityBoxHeight.constant = 48 self.buttonBox.isHidden = false self.cutButton.isHidden = true self.cancelCutButton.isHidden = true self.replaceButton.isHidden = true self.buttonBoxHeight.constant = 52 var opacity = self.listView.opacity(for: imagesAreas.first) for area in imagesAreas { let newOpacity = self.listView.opacity(for: area) if (opacity < newOpacity) { opacity = newOpacity } } self.opacitySlider.objectValue = opacity self.opacityPopUpButton.stringValue = "\(Int(opacity)*100))%" } else if imagesAreas.count > 0 && imagesAreas.count != areas!.count { //多选图片跟文字 self.headerBox.isHidden = true self.headerBoxHeight.constant = 0 self.imageBox.isHidden = true self.imageBoxHeight.constant = 0 self.opacityBox.isHidden = true self.opacityBoxHeight.constant = 0 self.buttonBox.isHidden = true self.buttonBoxHeight.constant = 0 } } //MARK: action @IBAction func selectOpacityAction(_ sender: KMComboBox) { let value = sender.indexOfItem(withObjectValue: sender.stringValue) if self.listView.editingAreas()?.count ?? 0 < 1 { return } self.updateImageAreasOpacity(opacity: Float("\(items[value])")!/100.0) self.opacitySlider.objectValue = Float("\(items[value])")!/100.0 } @IBAction func updateopacitySlider(_ sender: NSSlider) { let value = sender.floatValue if self.listView.editingAreas()?.count ?? 0 < 1 { return } self.updateImageAreasOpacity(opacity:value) self.opacityPopUpButton.stringValue = "\(Int(value*100))%" } @IBAction func rightRotationImageAction(_ sender: Any) { if self.listView.editingAreas()?.count ?? 0 < 1 { return } let areas = self.listView.editingAreas() if areas!.count == 1 && (areas!.first is CPDFEditImageArea) { let imageArea = areas!.first as! CPDFEditImageArea self.listView.rotate(with: imageArea, rotate: 90) self.listView.selectImageAreas = imageArea self.editImageView.image = self.listView.selectImageAreas.thumbnailImage } else if areas!.count > 1 { for imagesArea in imagesAreas { self.listView.rotate(with: imagesArea, rotate: 90) } } } @IBAction func leftRotationImageAction(_ sender: Any) { if self.listView.editingAreas()?.count ?? 0 < 1 { return } let areas = self.listView.editingAreas() if areas!.count == 1 && (areas!.first is CPDFEditImageArea) { self.listView.rotate(with: self.listView.selectImageAreas, rotate: -90) if self.listView.editingAreas()!.count == 1 && (self.listView.editingAreas()!.first is CPDFEditImageArea) { self.listView.selectImageAreas = self.listView.editingAreas()!.first as! CPDFEditImageArea } self.editImageView.image = self.listView.selectImageAreas.thumbnailImage } else { for imagesArea in imagesAreas { self.listView.rotate(with: imagesArea, rotate: -90) } } } @IBAction func cutImageAction(_ sender: Any) { if self.listView.selectImageAreas == nil { return } if self.listView.cropAreas != nil && self.listView.selectImageAreas != nil{ self.listView.cropEditImageArea(self.listView.selectImageAreas, withBounds: self.listView.cropAreas.cropRect) } else if self.listView.selectImageAreas != nil { self.listView.isEditImage = true self.listView.enterCrop(with: self.listView.selectImageAreas) self.updateButtonState(hidden: false) } } @IBAction func cancelCutImageAction(_ sender: Any) { if self.listView.selectImageAreas == nil { return } self.listView.exitCrop(with: self.listView.selectImageAreas) self.listView.cropAreas = nil self.listView.isEditImage = false self.updateButtonState(hidden: true) } @IBAction func replaceImageAction(_ sender: NSButton) { if self.listView.selectImageAreas == nil { return } let panel = NSOpenPanel() panel.allowsMultipleSelection = false panel.allowedFileTypes = ["png","jpg"] panel.beginSheetModal(for: NSApp.mainWindow!) { response in if response == .OK { let openPath = panel.url?.path // let s = self.listView.extractImage(with: self.selectImageAreas, toImagePath: openPath!) let s = self.listView.replace(self.listView.selectImageAreas, imagePath: openPath!) if s { } } } } @available(macOS 13.0, *) @IBAction func exportImageAction(_ sender: Any) { if self.listView.selectImageAreas == nil { return } if imagesAreas.count == 1 { let panel = NSSavePanel() panel.nameFieldStringValue = "\(NSLocalizedString("Untitled", comment: "")).png" let button = NSButton.init(checkboxWithTitle: NSLocalizedString("Open the document after saving", comment: ""), target: nil, action: nil) button.state = .on panel.accessoryView = button panel.isExtensionHidden = true let response = panel.runModal() if response == .OK { let url = panel.url let result = self.listView.extractImage(with: self.listView.selectImageAreas, toImagePath: url!.path) if result { if button.state == .on { /// 开启文档 NSWorkspace.shared.openFile(url!.path) } else { } } } } else if imagesAreas.count > 1 { let panel = NSOpenPanel() panel.canChooseFiles = false panel.canChooseDirectories = true panel.canCreateDirectories = true panel.allowsMultipleSelection = false panel.beginSheetModal(for: NSApp.mainWindow!) { response in if response == .OK { let outputURL = panel.url let s = self.listView.document.documentURL.lastPathComponent let folderPath = self.listView.document.documentURL.deletingPathExtension().lastPathComponent + "_extract" var filePath = outputURL?.path.stringByAppendingPathComponent(folderPath) var i = 1 let testFilePath = filePath while FileManager.default.fileExists(atPath: filePath!) { filePath = testFilePath! + "\(i)" i = i + 1 } try? FileManager.default.createDirectory(atPath: filePath!, withIntermediateDirectories: false, attributes: nil) var saveURLs : [URL] = [] for j in 0 ... self.imagesAreas.count-1 { let documentFileName = self.listView.document.documentURL.deletingPathExtension().lastPathComponent var outPath = filePath! outPath = outPath.stringByAppendingPathComponent(documentFileName) outPath = outPath + "page \(j+1)" outPath = outPath.stringByAppendingPathExtension("png") let result = self.listView.extractImage(with: self.imagesAreas[j], toImagePath: outPath) if result { saveURLs.append(URL(fileURLWithPath: outPath)) } } NSWorkspace.shared.activateFileViewerSelecting(saveURLs) } } } } override func mouseDown(with event: NSEvent) { } //MARK: 对齐 @IBAction func areasAlignStyleAction(_ sender: NSButton) { self.formAearsAlignMangent(stype: CPDFActiveAreasAlignType.init(rawValue: sender.tag) ?? .Left) } func updateButtonState(hidden:Bool) { if hidden { self.cancelCutButton.isHidden = true self.cutRightConstraint.constant = 10 self.cutButton.title = NSLocalizedString("cut", comment: "") self.replaceButton.isEnabled = true self.exportButton.isEnabled = true } else { self.cancelCutButton.isHidden = false self.cutRightConstraint.constant = 80 self.cutButton.title = NSLocalizedString("sure cut", comment: "") self.replaceButton.isEnabled = false self.exportButton.isEnabled = false } } func updateImageAreasOpacity (opacity:Float) { for area in imagesAreas { self.listView.setOpacityEditArea(area, opacity: CGFloat(opacity)) } if self.listView.editingAreas()!.count == 1 && (self.listView.editingAreas()!.first is CPDFEditImageArea) { self.listView.selectImageAreas = self.listView.editingAreas()!.first as! CPDFEditImageArea self.editImageView.image = self.listView.selectImageAreas.thumbnailImage self.opacitySlider.objectValue = self.listView.opacity(for: self.listView.selectImageAreas) } } func formAearsAlignIcon() { let norIcons : [String] = ["KMImageNameEditPDFImage20","KMImageNameEditPDFImage21","KMImageNameEditPDFImage45","KMImageNameEditPDFImage46", "KMImageNameEditPDFImage47","KMImageNameEditPDFImage48","KMImageNameEditPDFImage49","KMImageNameEditPDFImage50"] let selectIcons : [String] = ["KMImageNameEditPDFImage20_1","KMImageNameEditPDFImage21_1","KMImageNameEditPDFImage45_1","KMImageNameEditPDFImage46_1", "KMImageNameEditPDFImage47_1","KMImageNameEditPDFImage48_1","KMImageNameEditPDFImage49_1","KMImageNameEditPDFImage50_1"] let areasButtons : [NSButton] = [self.areasVerticalButton,self.areasHorzontalButton,self.areasLeftButton,self.areasVerticalCenterButton, self.areasRightButton,self.areasTopButton,self.areasHorizontalCenterButton,self.areasBotoomButton] if self.listView.editingAreas()?.count ?? 0 < 2 { for i in 0 ... areasButtons.count-1 { areasButtons[i].image = NSImage(named: norIcons[i]) } } else if self.listView.editingAreas()?.count ?? 0 == 2 { for i in 0 ... areasButtons.count-1 { if i == 0 || i == 1 { areasButtons[i].image = NSImage(named: norIcons[i]) } else { areasButtons[i].image = NSImage(named: selectIcons[i]) } } } else if self.listView.editingAreas()?.count ?? 0 > 2 { for i in 0 ... areasButtons.count-1 { areasButtons[i].image = NSImage(named: selectIcons[i]) } } } private func formAearsAlignMangent(stype:CPDFActiveAreasAlignType) { if self.listView.editingAreas().count < 2 { return } var zeroRect = NSRect.null var highestRect = NSZeroRect var widthestRect = NSZeroRect let fristArea : CPDFEditArea = self.listView.editingAreas().first as! CPDFEditArea var leftestRect = fristArea.bounds var rightestRect = fristArea.bounds var topestRect = fristArea.bounds var bottomestRect = fristArea.bounds var leftestArea : CPDFEditArea = fristArea var rightestArea : CPDFEditArea = fristArea var topestArea : CPDFEditArea = fristArea var bottomestArea : CPDFEditArea = fristArea var totalWidth = 0.0 var totalHeight = 0.0 for i in 0 ... self.listView.editingAreas().count-1 { let area : CPDFEditArea = self.listView.editingAreas()[i] as! CPDFEditArea zeroRect = zeroRect.union(area.bounds) totalWidth = totalWidth + area.bounds.width totalHeight = totalHeight + area.bounds.height if area.bounds.height > highestRect.height { highestRect = area.bounds } if area.bounds.width > widthestRect.width { widthestRect = area.bounds } if leftestRect.minX > area.bounds.minX { leftestRect = area.bounds leftestArea = area } if area.bounds.maxX > rightestRect.maxX { rightestRect = area.bounds rightestArea = area } if area.bounds.maxY > topestRect.maxY { topestRect = area.bounds topestArea = area } if bottomestRect.minY > area.bounds.minY { bottomestRect = area.bounds bottomestArea = area } } if stype == .Left { var newBoundsArray : [String] = [] for i in 0 ... self.listView.editingAreas().count-1 { let areas = self.listView.editingAreas()[i] as! CPDFEditArea var bounds = areas.bounds bounds.origin.x = zeroRect.origin.x newBoundsArray.append(NSStringFromRect(bounds)) } self.changeAreasAlign(areas: self.listView.editingAreas(), newBounds: newBoundsArray) } else if stype == .Right { var newBounds : [String] = [] for i in 0 ... self.listView.editingAreas().count-1 { let areas = self.listView.editingAreas()[i] as! CPDFEditArea var bounds = areas.bounds bounds.origin.x = zeroRect.maxX - bounds.size.width newBounds.append(NSStringFromRect(bounds)) } self.changeAreasAlign(areas: self.listView.editingAreas(), newBounds: newBounds) } else if stype == .Top { var newBounds : [String] = [] for i in 0 ... self.listView.editingAreas().count-1 { let areas = self.listView.editingAreas()[i] as! CPDFEditArea var bounds = areas.bounds bounds.origin.y = zeroRect.maxY - bounds.size.height newBounds.append(NSStringFromRect(bounds)) } self.changeAreasAlign(areas: self.listView.editingAreas(), newBounds: newBounds) } else if stype == .Bottom { var newBounds : [String] = [] for i in 0 ... self.listView.editingAreas().count-1 { let areas = self.listView.editingAreas()[i] as! CPDFEditArea var bounds = areas.bounds bounds.origin.y = zeroRect.minY newBounds.append(NSStringFromRect(bounds)) } self.changeAreasAlign(areas: self.listView.editingAreas(), newBounds: newBounds) } else if stype == .Horizontally { var newBounds : [String] = [] for i in 0 ... self.listView.editingAreas().count-1 { let areas = self.listView.editingAreas()[i] as! CPDFEditArea var bounds = areas.bounds bounds.origin.y = highestRect.midY - bounds.height/2 newBounds.append(NSStringFromRect(bounds)) } self.changeAreasAlign(areas: self.listView.editingAreas(), newBounds: newBounds) } else if stype == .Vertical { var newBounds : [String] = [] for i in 0 ... self.listView.editingAreas().count-1 { let areas = self.listView.editingAreas()[i] as! CPDFEditArea var bounds = areas.bounds bounds.origin.x = widthestRect.midX - bounds.width/2 newBounds.append(NSStringFromRect(bounds)) } self.changeAreasAlign(areas: self.listView.editingAreas(), newBounds: newBounds) } else if stype == .DisHorizontally { let middleGap = zeroRect.width - leftestRect.width - rightestRect.width let otherAreasTotalWidth = totalWidth - leftestRect.width - rightestRect.width let gap = (middleGap - otherAreasTotalWidth)/CGFloat(self.listView.editingAreas().count - 1) var areasCopyArray : [CPDFEditArea] = self.listView.editingAreas() as! [CPDFEditArea] areasCopyArray.sorted(by: { obj1, obj2 in let area1 = obj1 let area2 = obj2 if area1.bounds.origin.x < area2.bounds.origin.x { return true } else { return false } }) if let index = areasCopyArray.firstIndex(of: leftestArea) { areasCopyArray.remove(at: index) } if let index = areasCopyArray.firstIndex(of: rightestArea) { areasCopyArray.remove(at: index) } var newBounds : [String] = [] var leftStartX = leftestRect.maxX + gap for i in 0 ... areasCopyArray.count-1 { let areas = areasCopyArray[i] var bounds = areas.bounds bounds.origin.x = leftStartX newBounds.append(NSStringFromRect(bounds)) leftStartX = leftStartX + bounds.width + gap } self.changeAreasAlign(areas: areasCopyArray, newBounds: newBounds) } else if stype == .DisVertical { let middleGap = zeroRect.height - topestRect.height - bottomestRect.height let otherAreasTotalHeight = totalHeight - topestRect.height - bottomestRect.height let gap = (middleGap - otherAreasTotalHeight)/CGFloat(self.listView.editingAreas().count - 1) var areasCopyArray : [CPDFEditArea] = self.listView.editingAreas() as! [CPDFEditArea] areasCopyArray.sorted(by: { obj1, obj2 in let area1 = obj1 let area2 = obj2 if area1.bounds.origin.x < area2.bounds.origin.x { return true } else { return false } }) if let index = areasCopyArray.firstIndex(of: topestArea) { areasCopyArray.remove(at: index) } if let index = areasCopyArray.firstIndex(of: bottomestArea) { areasCopyArray.remove(at: index) } var newBounds : [String] = [] var bottomStartY = bottomestRect.maxY + gap for i in 0 ... areasCopyArray.count-1 { let areas = areasCopyArray[i] var bounds = areas.bounds bounds.origin.y = bottomStartY newBounds.append(NSStringFromRect(bounds)) bottomStartY = bottomStartY + bounds.height + gap } self.changeAreasAlign(areas: areasCopyArray, newBounds: newBounds) } } private func changeAreasAlign(areas:[Any],newBounds:[String]) { var oldBounds : [String] = [] for i in 0 ... areas.count-1 { let area : CPDFEditArea = areas[i] as! CPDFEditArea oldBounds.append(NSStringFromRect(area.bounds)) self.listView.setBoundsEditArea(area, withBounds: NSRectFromString(newBounds[i])) } self.listView.setNeedsDisplayForVisiblePages() } }