// // KMWatermarkView.swift // PDF Reader Pro // // Created by lizhe on 2023/11/14. // import Cocoa enum KMWatermarkManagerType { case add case edit case use } typealias KMWatermarkViewOperateCallBack = (_ watermark: KMWatermarkModel, _ countType: Int) -> () typealias KMWatermarkViewCancelAction = (_ view: KMWatermarkView) -> Void class KMWatermarkView: KMBaseXibView, NSTextFieldDelegate, NSComboBoxDelegate, NSTextViewDelegate, CPDFViewDelegate { //顶部box @IBOutlet var typeBox: NSBox! @IBOutlet var txtButton: NSButton! @IBOutlet var fileButton: NSButton! @IBOutlet var filePathLabel: NSTextField! @IBOutlet var browsebutton: NSButton! @IBOutlet var ratioLabel: NSTextField! @IBOutlet var ratioTextField: NSTextField! @IBOutlet var ratioStepper: NSStepper! @IBOutlet var fontLabel: NSTextField! @IBOutlet var fontComboBox: NSComboBox! @IBOutlet var fontSizeLabel: NSTextField! @IBOutlet var fontSizeCombobox: NSComboBox! @IBOutlet var colorLabel: NSTextField! @IBOutlet var colorWell: NSColorWell! @IBOutlet var watermarkStringTextView: NSTextView! var maskView: KMBookletMaskView? //底部box @IBOutlet var appearanceBox: NSBox! @IBOutlet var angleLabel: NSTextField! @IBOutlet var angleTextF: NSTextField! @IBOutlet var angleStepper: NSStepper! @IBOutlet var left45IndicateView: KMAngleIndicateView! @IBOutlet var horizontalIndicateView: KMAngleIndicateView! @IBOutlet var right45IndicateView: KMAngleIndicateView! @IBOutlet var alphaLabel: NSTextField! @IBOutlet var alphaSlider: NSSlider! @IBOutlet var alphaTextField: NSTextField! @IBOutlet var alphaStepper: NSStepper! @IBOutlet var watermarkPositionLabel: NSTextField! @IBOutlet var OnPageButton: NSButton! @IBOutlet var backPageButton: NSButton! @IBOutlet var positionView: KMPostionIndicateView! @IBOutlet var horizentalGapLabel: NSTextField! @IBOutlet var verticalGapLabel: NSTextField! @IBOutlet var horizentalGapTextField: NSTextField! @IBOutlet var verticalFapTextField: NSTextField! @IBOutlet var horizentalGapStepper: NSStepper! @IBOutlet var verticalGapStepper: NSStepper! @IBOutlet var pageRangeLabel: NSTextField! @IBOutlet var pageRangeComboBox: NSComboBox! //保存到模版按钮 @IBOutlet var saveToTemplateButton: NSButton! @IBOutlet var templateNameLabel: NSTextField! @IBOutlet var templateNameTextField: NSTextField! @IBOutlet var isTileWater: NSButton! @IBOutlet var spacingHorTextField: NSTextField! @IBOutlet var spacingHorStepper: NSStepper! @IBOutlet var horizentalIconButton: NSButton! @IBOutlet var verticalIconButton: NSButton! @IBOutlet var spacingVerTextField: NSTextField! @IBOutlet var spacingStepper: NSStepper! //底部按钮 @IBOutlet var batchButton: NSButton! @IBOutlet var cancelButton: NSButton! @IBOutlet var applyButton: NSButton! //左侧 @IBOutlet var previewPageButton: NSButton! @IBOutlet var nextPageButton: NSButton! @IBOutlet var currentPageIndexTextF: NSTextField! @IBOutlet var totalPageCountLabel: NSTextField! @IBOutlet var pdfView: KMWatermarkPDFView! var fontModified: Bool = false var currentType: Int = 0 var filePath: String = Bundle.main.path(forResource: "Quick Start Guide", ofType: "pdf") ?? "" var password: String = "" var originalWatermark: KMWatermarkModel = KMWatermarkModel() var watermark: KMWatermarkModel = KMWatermarkModel() var type: KMWatermarkManagerType = .use { didSet { if type == .edit { } else { watermark.watermarkID = KMWatermarkManager.defaultManager.fetchAvailableName() } self.templateNameTextField.stringValue = self.watermark.watermarkID } } var pdfDocument: CPDFDocument? { didSet { self._fileAttri = KMFileAttribute() self._fileAttri?.password = self.pdfDocument?.password ?? "" self._fileAttri?.filePath = self.pdfDocument?.documentURL?.path ?? "" self.password = pdfDocument?.password ?? "" DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { self.pdfView.watermark = self.watermark self.pdfView.document = self.pdfDocument self.pdfView.autoScales = true self.pdfView.documentView().enclosingScrollView?.scrollerStyle = .overlay self.pdfView.documentView().enclosingScrollView?.hasVerticalScroller = false self.pdfView.documentView().enclosingScrollView?.hasHorizontalScroller = false } // self.reloadData() } } var onlyManagerTemplate: Bool = true var isHiddenBatchBtn: Bool = false private var _fileAttri: KMFileAttribute? var cancelAction: KMWatermarkViewCancelAction? var operateCallBack: KMWatermarkViewOperateCallBack? convenience init(baseFile filePath: String, watermark: KMWatermarkModel, password: String, type: KMWatermarkManagerType, fileType countType: Int) { self.init() self.filePath = filePath self.password = password self.originalWatermark = watermark.copy() as! KMWatermarkModel self.watermark = watermark.copy() as! KMWatermarkModel self.type = type self.pdfDocument = CPDFDocument(url: URL(fileURLWithPath: self.filePath)) self.currentType = countType if pdfDocument?.isLocked ?? false { pdfDocument?.unlock(withPassword: password) } } override func setup() { pdfView.setDisplay(.singlePage) // if (pdfView.documentView() != nil) { // pdfView.setDisplay(.singlePage) // pdfView.documentView().enclosingScrollView?.scrollerStyle = .overlay // pdfView.documentView().enclosingScrollView?.hasVerticalScroller = false // pdfView.documentView().enclosingScrollView?.hasHorizontalScroller = false // } for i in 0..<3 { for j in 0..<3 { if i == Int(watermark.horizontalMode) && j == Int(watermark.verticalMode) { positionView.style = KMPositionIndicateViewStyle(rawValue: i + 3 * j)! } } } positionView.styleChangedCallBack = { [weak self] in guard let self = self else { return } self.watermark.horizontalMode = self.positionView.style.rawValue % 3 self.watermark.verticalMode = self.positionView.style.rawValue / 3 self.updatePDFView() } currentPageIndexTextF.stringValue = "1" // let numberFormatter = currentPageIndexTextF.formatter as! NumberFormatter // numberFormatter.maximum = NSNumber(value: pdfDocument!.pageCount) pdfView.delegate = self let formatter = TextFieldFormatter.init() formatter.allowedCharacterSet = "-" self.angleTextF.formatter = formatter angleTextF.delegate = self let formatter2 = TextFieldFormatter.init() formatter2.allowedCharacterSet = "%" self.alphaTextField.formatter = formatter2 alphaTextField.delegate = self let formatter3 = TextFieldFormatter.init() formatter3.allowedCharacterSet = ".-" self.horizentalGapTextField.formatter = formatter3 horizentalGapTextField.delegate = self let formatter4 = TextFieldFormatter.init() formatter4.allowedCharacterSet = ".-" self.verticalFapTextField.formatter = formatter4 verticalFapTextField.delegate = self let formatter5 = TextFieldFormatter.init() formatter5.allowedCharacterSet = "" self.spacingHorTextField.formatter = formatter5 spacingHorTextField.delegate = self let formatter6 = TextFieldFormatter.init() formatter6.allowedCharacterSet = "" self.spacingVerTextField.formatter = formatter6 spacingVerTextField.delegate = self left45IndicateView.style = .left45 left45IndicateView.touchCallBack = { [weak self] in guard let self = self else { return } self.watermark.rotation = -45 self.angleStepper.doubleValue = self.watermark.rotation self.angleTextF.stringValue = "\(self.angleStepper.intValue)" self.checkAngle() self.updatePDFView() } horizontalIndicateView.style = .horizontal horizontalIndicateView.touchCallBack = { [weak self] in guard let self = self else { return } self.watermark.rotation = 0 self.angleStepper.doubleValue = 0 self.angleTextF.stringValue = "\(0)" self.checkAngle() self.updatePDFView() } right45IndicateView.style = .right45 right45IndicateView.touchCallBack = { [weak self] in guard let self = self else { return } self.watermark.rotation = 45 self.angleStepper.doubleValue = self.watermark.rotation self.angleTextF.stringValue = "\(self.angleStepper.intValue)" self.checkAngle() self.updatePDFView() } saveToTemplateButton.isEnabled = onlyManagerTemplate // if type == .use { // saveToTemplateButton.isHidden = true // saveToTemplateButton.state = .off // } else { // saveToTemplateButton.isHidden = false // saveToTemplateButton.state = .on // } if type == .add { applyButton.title = NSLocalizedString("Apply", comment: "") batchButton.isHidden = true } else if type == .edit { applyButton.title = NSLocalizedString("Apply", comment: "") batchButton.isHidden = true } else if type == .use { applyButton.title = NSLocalizedString("Save & Apply", comment: "") } filePathLabel.stringValue = "" filePathLabel.placeholderString = NSLocalizedString("Select a File", comment: "") fontSizeCombobox.removeAllItems() fontSizeCombobox.addItems(withObjectValues: ["9","10","11","12","13","14","18","24","36","48","64","72","96","144","288"]) fontSizeCombobox.formatter = TextFieldFormatter() watermarkStringTextView.delegate = self pageRangeComboBox.removeAllItems() pageRangeComboBox.addItems(withObjectValues: [ NSLocalizedString("All Pages", comment: ""), NSLocalizedString("Odd Pages Only", comment: ""), NSLocalizedString("Even Pages Only", comment: ""), NSLocalizedString("e.g. 1,3-5,10", comment: "") ]) pageRangeComboBox.placeholderString = NSLocalizedString("e.g. 1,3-5,10", comment: "") pageRangeComboBox.delegate = nil pageRangeComboBox.selectItem(at: 0) pageRangeComboBox.isEditable = false pageRangeComboBox.delegate = self fontSizeCombobox.wantsLayer = true pageRangeComboBox.wantsLayer = true fontSizeCombobox.layer?.cornerRadius = 3.0 pageRangeComboBox.layer?.cornerRadius = 3.0 self.verticalFapTextField.delegate = self self.horizentalGapTextField.delegate = self self.spacingHorTextField.delegate = self self.spacingVerTextField.delegate = self } override func updateLanguage() { typeBox.title = NSLocalizedString("Source", comment: "") typeBox.titleFont = NSFont.systemFont(ofSize: 13) txtButton.title = NSLocalizedString("Text", comment: "") fileButton.title = NSLocalizedString("File", comment: "") browsebutton.title = NSLocalizedString("Choose...", comment: "") ratioLabel.stringValue = "\(NSLocalizedString("Ratio", comment: "")):" fontLabel.stringValue = NSLocalizedString("Font", comment: "") horizentalIconButton.toolTip = NSLocalizedString("Horizontal Distance", comment: "") verticalIconButton.toolTip = NSLocalizedString("Vertical Distance", comment: "") fontSizeLabel.stringValue = "\(NSLocalizedString("Font Size", comment: "")):" colorLabel.stringValue = "\(NSLocalizedString("Color", comment: "")):" templateNameTextField.stringValue = watermark.watermarkID ?? "" appearanceBox.title = NSLocalizedString("Appearance", comment: "") appearanceBox.titleFont = NSFont.systemFont(ofSize: 13) angleLabel.stringValue = "\(NSLocalizedString("Rotation", comment: "")):" alphaLabel.stringValue = "\(NSLocalizedString("Opacity", comment: "")):" watermarkPositionLabel.stringValue = "\(NSLocalizedString("Position", comment: "")):" OnPageButton.title = NSLocalizedString("Appear on top of page", comment: "") backPageButton.title = NSLocalizedString("Appear behind page", comment: "") pageRangeLabel.stringValue = "\(NSLocalizedString("Page Range", comment: "")):" isTileWater.title = NSLocalizedString("Tile", comment: "") OnPageButton.toolTip = NSLocalizedString("Appear on top of page", comment: "") backPageButton.toolTip = NSLocalizedString("Appear behind page", comment: "") pageRangeLabel.toolTip = "\(NSLocalizedString("Page Range", comment: "")):" horizentalGapLabel.stringValue = "X:" verticalGapLabel.stringValue = "Y:" saveToTemplateButton.title = NSLocalizedString("Add to Template", comment: "") templateNameLabel.stringValue = NSLocalizedString("Name:", comment: "") batchButton.title = NSLocalizedString("Batch", comment: "") cancelButton.title = NSLocalizedString("Cancel", comment: "") } override func reloadData() { guard let pdfDocument = pdfDocument else { return } let opacity = round(watermark.opacity * 100) / 100 watermarkStringTextView.string = watermark.text colorWell.color = watermark.getTextColor() totalPageCountLabel.stringValue = "/ \(pdfDocument.pageCount)" fontSizeCombobox.stringValue = "\(Int(watermark.getTextFontSize()))" angleStepper.doubleValue = Double(watermark.rotation) angleTextF.stringValue = "\(angleStepper.intValue)" OnPageButton.state = watermark.isFront ? .on : .off backPageButton.state = watermark.isFront ? .off : .on alphaSlider.doubleValue = watermark.opacity alphaStepper.doubleValue = watermark.opacity alphaTextField.stringValue = "\(Int(opacity * 100))%" ratioStepper.doubleValue = watermark.scale ratioTextField.stringValue = "\(Int(opacity * 100))%" fontComboBox.stringValue = "\(watermark.getTextFontSize() )" filePathLabel.stringValue = watermark.imagePath batchButton.isHidden = isHiddenBatchBtn if !isHiddenBatchBtn { self.batchButton.isHidden = type != .use } if currentType == 0 { changeTypeBoxState(isTextWatermark: true) } else { changeTypeBoxState(isTextWatermark: false) } switch watermark.pageRangeType { case .all: pageRangeComboBox.isEditable = false pageRangeComboBox.selectItem(at: 0) case .odd: pageRangeComboBox.isEditable = false pageRangeComboBox.selectItem(at: 1) case .even: pageRangeComboBox.isEditable = false pageRangeComboBox.selectItem(at: 2) case .other: pageRangeComboBox.isEditable = true pageRangeComboBox.selectItem(at: 3) pageRangeComboBox.stringValue = watermark.pagesString } for i in 0..<3 { for j in 0..<3 { if i == Int(watermark.horizontalMode) && j == Int(watermark.verticalMode) { self.positionView.style = KMPositionIndicateViewStyle(rawValue: i + 3 * j)! } } } verticalGapStepper.doubleValue = Double(watermark.verticalSpace) verticalFapTextField.stringValue = "\(verticalGapStepper.doubleValue)" horizentalGapStepper.doubleValue = Double(watermark.horizontalSpace) horizentalGapTextField.stringValue = "\(horizentalGapStepper.doubleValue)" spacingHorTextField.stringValue = "\(watermark.tileHorizontalSpace)" spacingVerTextField.stringValue = "\(watermark.tileVerticalSpace)" spacingHorStepper.doubleValue = Double(watermark.tileHorizontalSpace) spacingStepper.doubleValue = Double(watermark.tileVerticalSpace) if watermark.isTilePage { isTileWater.state = .on spacingHorTextField.isEnabled = true spacingHorStepper.isEnabled = true spacingVerTextField.isEnabled = true spacingStepper.isEnabled = true } else { isTileWater.state = .off spacingHorTextField.isEnabled = false spacingHorStepper.isEnabled = false spacingVerTextField.isEnabled = false spacingStepper.isEnabled = false } pageRangeComboxAction(Any.self) checkAngle() } override func addNotification() { NotificationCenter.default.addObserver(self, selector: #selector(pageChangeNotification), name: NSNotification.Name.CPDFViewPageChanged, object: self.pdfView) } func updatePDFView() { // pdfView.needsDisplay = true km_synchronized(self) { self.pdfView.setNeedsDisplayForVisiblePages() } } func checkAngle() { left45IndicateView.isSelcted = false horizontalIndicateView.isSelcted = false right45IndicateView.isSelcted = false switch watermark.rotation { case -45: left45IndicateView.isSelcted = true case 0: horizontalIndicateView.isSelcted = true case 45: right45IndicateView.isSelcted = true default: break } } func changeTypeBoxState(isTextWatermark: Bool) { if isTextWatermark { txtButton.state = .on watermarkStringTextView.isEditable = true watermarkStringTextView.isSelectable = true fontSizeCombobox.isEnabled = true colorWell.isEnabled = true fileButton.state = .off browsebutton.isEnabled = false ratioTextField.isEnabled = false ratioStepper.isEnabled = false watermark.text = watermarkStringTextView.string watermarkStringTextView.string = watermarkStringTextView.string watermark.image = nil if watermarkStringTextView.string.isEmpty == false { applyButton.isEnabled = true batchButton.isEnabled = true } else { applyButton.isEnabled = false batchButton.isEnabled = false } } else { txtButton.state = .off watermarkStringTextView.isEditable = false watermarkStringTextView.isSelectable = false fontSizeCombobox.isEnabled = false colorWell.isEnabled = false fileButton.state = .on browsebutton.isEnabled = true ratioTextField.isEnabled = true ratioStepper.isEnabled = true watermark.text = "" if let _image = NSImage(contentsOfFile: watermark.imagePath ) { watermark.image = _image } if filePathLabel.stringValue.isEmpty == false { applyButton.isEnabled = true batchButton.isEnabled = true } else { applyButton.isEnabled = false batchButton.isEnabled = false } } updatePDFView() } func checkPageRangeValidate(_ pageRangeString: String) -> Bool { var fileAttribute = self._fileAttri if fileAttribute == nil { fileAttribute = KMFileAttribute() fileAttribute?.password = self.pdfDocument?.password ?? "" fileAttribute?.filePath = self.pdfDocument?.documentURL.path ?? "" self._fileAttri = fileAttribute } fileAttribute?.bAllPage = false fileAttribute?.pagesString = self.pageRangeComboBox.stringValue var pageRange: KMPageRange = .all let pageRangeType: KMWatermarkeModelPageRangeType = watermark.pageRangeType if pageRangeType == .all { pageRange = .all } else if pageRangeType == .even { pageRange = .even } else if pageRangeType == .odd { pageRange = .odd } else if pageRangeType == .other { pageRange = .custom } fileAttribute?.pagesType = pageRange if let cnt = fileAttribute?.fetchSelectPages().count, cnt == 0 { return false } return true } @objc func controlTextDidEndEditing(_ obj: Notification) { if obj.object as? NSComboBox == self.fontSizeCombobox { var textSize = CGFloat(Int(self.fontSizeCombobox.stringValue) ?? 0) if textSize == 0 { textSize = 48 if self.watermark.isTilePage { textSize = 18 } } self.watermark.textFont = KMWatermarkAdjectiveText.font(name: "Helvetica", size: textSize) self.fontSizeCombobox.stringValue = "\(Int(textSize))" self.updatePDFView() } else if obj.object as? NSTextField == self.ratioTextField { let formatter = self.ratioTextField.formatter as? NumberFormatter _ = formatter?.number(from: self.ratioTextField.stringValue)?.floatValue ?? 0 self.ratioStepper.doubleValue = Double(self.watermark.scale) self.updatePDFView() } else if obj.object as? NSTextField == self.angleTextF { self.watermark.rotation = CGFloat(Int(self.angleTextF.stringValue) ?? 0) self.angleStepper.doubleValue = self.watermark.rotation self.checkAngle() self.updatePDFView() } else if obj.object as? NSTextField == self.alphaTextField { let floatValue = self.alphaTextField.stringValue.replacingOccurrences(of: "%", with: "").stringToCGFloat() * 0.01 self.alphaSlider.doubleValue = Double(floatValue) self.alphaStepper.doubleValue = Double(floatValue) self.watermark.opacity = Double(floatValue) self.updatePDFView() } else if obj.object as? NSComboBox == self.pageRangeComboBox { if self.pageRangeComboBox.indexOfSelectedItem == -1 { if !self.checkPageRangeValidate(self.pageRangeComboBox.stringValue) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "\(String(describing: self.pdfDocument?.documentURL.lastPathComponent)) \(NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: ""))" alert.runModal() self.window?.makeFirstResponder(self.pageRangeComboBox) return } else { self.watermark.pagesString = self.pageRangeComboBox.stringValue self.updatePDFView() } } } else if obj.object as? NSTextField == self.verticalFapTextField { self.watermark.verticalSpace = CGFloat(Int(self.verticalFapTextField.stringValue) ?? 0) self.verticalGapStepper.doubleValue = Double(self.watermark.verticalSpace) self.updatePDFView() } else if obj.object as? NSTextField == self.horizentalGapTextField { self.watermark.horizontalSpace = CGFloat(Int(self.horizentalGapTextField.stringValue) ?? 0) self.horizentalGapStepper.doubleValue = Double(self.watermark.horizontalSpace) self.updatePDFView() } else if obj.object as? NSTextField == self.currentPageIndexTextF { self.pdfView.go(toPageIndex: (Int(self.currentPageIndexTextF.stringValue) ?? 0 - 1), animated: false) } else if obj.object as? NSTextField == self.spacingHorTextField { self.watermark.tileHorizontalSpace = CGFloat(Int(self.spacingHorTextField.stringValue) ?? 0) self.spacingHorStepper.doubleValue = Double(self.watermark.tileHorizontalSpace) self.updatePDFView() } else if obj.object as? NSTextField == self.spacingVerTextField { self.watermark.tileVerticalSpace = CGFloat(Int(self.spacingVerTextField.stringValue) ?? 0) self.spacingStepper.doubleValue = Double(self.watermark.tileVerticalSpace) self.updatePDFView() } } @objc func comboBoxSelectionDidChange(_ notification: Notification) { if notification.object as? NSComboBox == self.pageRangeComboBox { self.pageRangeComboBox.isEditable = false if self.pageRangeComboBox.indexOfSelectedItem == 0 { self.watermark.pageRangeType = .all } else if self.pageRangeComboBox.indexOfSelectedItem == 1 { self.watermark.pageRangeType = .odd } else if self.pageRangeComboBox.indexOfSelectedItem == 2 { self.watermark.pageRangeType = .even } else { self.watermark.pageRangeType = .other self.pageRangeComboBox.stringValue = "" self.pageRangeComboBox.isEditable = true self.window?.makeFirstResponder(self.pageRangeComboBox) } } } @objc func textDidChange(_ notification: Notification) { if notification.object as? NSTextView == self.watermarkStringTextView { self.watermark.text = self.watermarkStringTextView.string self.applyButton.isEnabled = !self.watermark.text.isEmpty self.batchButton.isEnabled = !self.watermark.text.isEmpty self.updatePDFView() } } func isDamageImage(_ image: NSImage?, imagePath path: String) -> Bool { let addImageAnnotation = (NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last! as NSString).appendingPathComponent(Bundle.main.bundleIdentifier!) if !FileManager.default.fileExists(atPath: addImageAnnotation) { try? FileManager.default.createDirectory(atPath: addImageAnnotation, withIntermediateDirectories: false, attributes: nil) } let data = image?.tiffRepresentation let imageRep = NSBitmapImageRep(data: data!) imageRep?.size = image?.size ?? NSSize.zero var imageData: Data? if path.lowercased() == "png" { imageData = imageRep?.representation(using: .png, properties: [:]) } else { imageData = imageRep?.representation(using: .jpeg, properties: [:]) } let rPath = (addImageAnnotation as NSString).appendingPathComponent("waterAnnotation.png") if ((try? imageData?.write(to: URL(fileURLWithPath: rPath), options: .atomic)) == nil) { return true } else { return false } } func tagString() -> String { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyMMddHHmmss" return "\(dateFormatter.string(from: Date()))\(arc4random() % 10000)" } // MARK: - Action // NSNotification @objc func pageChangeNotification(_ notification: Notification) { currentPageIndexTextF.stringValue = "\(pdfView.currentPage().pageIndex() + 1)" } // 开始转圈,隐藏转圈提示 func showWaitting() { if maskView == nil { maskView = KMBookletMaskView(frame: NSRect(x: 0, y: 0, width: window?.frame.size.width ?? 0, height: window?.frame.size.height ?? 0)) } window?.contentView?.addSubview(maskView!) } func hideWaitting() { maskView?.removeFromSuperview() } override func mouseDown(with event: NSEvent) { super.mouseDown(with: event) window?.makeFirstResponder(nil) } } extension KMWatermarkView { @IBAction func buttonClicked_SwitchTextWatermark(_ sender: Any) { currentType = 0 changeTypeBoxState(isTextWatermark: true) } @IBAction func buttonClicked_SwitchFileWaterMark(_ sender: Any) { currentType = 1 changeTypeBoxState(isTextWatermark: false) } @IBAction func buttonClicked_BrowseFile(_ sender: Any) { let openPanel = NSOpenPanel() openPanel.canChooseDirectories = false openPanel.canChooseFiles = true openPanel.allowsMultipleSelection = false openPanel.allowedFileTypes = ["jpg", "jpeg", "png", "pdf"] openPanel.beginSheetModal(for: window!) { (result) in if result == NSApplication.ModalResponse.OK { guard let url = openPanel.url else { return } let filePath = url.path if filePath.extension.lowercased() == ".pdf" { let pdf = CPDFDocument(url: url) guard !pdf!.isEncrypted else { return } self.showWaitting() let convert = KMPDFConvert() convert.convertType = .png convert.filePath = url.path convert.pages = [1] convert.outputFolderPath = (NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last! as NSString).appendingPathComponent(Bundle.main.bundleIdentifier!) convert.outputFileName = "pdfConvertPng" KMPDFConvertManager.defaultManager.convert(convert: convert, completion: { (finished, error) in self.hideWaitting() if finished { let outputFilePath = convert.outputFilePath if FileManager.default.fileExists(atPath: outputFilePath) { let fimagePath = (try? FileManager.default.subpaths(atPath: outputFilePath))?.first let pdfPath = convert.outputFilePath + "/" + fimagePath! var newPath = (convert.outputFolderPath as NSString).appendingPathComponent(self.tagString()) newPath = (newPath as NSString).appendingPathComponent(((url.path as NSString).lastPathComponent as NSString).deletingPathExtension + ".png") do { try FileManager.default.copyItem(atPath: pdfPath, toPath: newPath) try FileManager.default.removeItem(atPath: convert.outputFilePath) } catch { print(error.localizedDescription) } let image = NSImage(contentsOfFile: pdfPath) if self.isDamageImage(image, imagePath: pdfPath) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "The file \"\(url.lastPathComponent)\" could not be opened." alert.informativeText = "It may be damaged or use a file format that PDF Reader Pro doesn’t recognize." alert.addButton(withTitle: "Cancel") alert.beginSheetModal(for: NSApp.mainWindow!) { (response) in if response == NSApplication.ModalResponse.alertFirstButtonReturn { // Cancel button clicked } } return } self.filePathLabel.stringValue = url.path self.watermark.imagePath = pdfPath self.watermark.image = NSImage(contentsOfFile: pdfPath) self.watermark.text = "" self.templateNameTextField.stringValue = self.watermark.watermarkID self.applyButton.isEnabled = true self.batchButton.isEnabled = true self.pdfView.setNeedsDisplay(NSRect.zero) } } }) } else { let image = NSImage(contentsOfFile: url.path) if self.isDamageImage(image, imagePath: url.path) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "The file \"\(url.lastPathComponent)\" could not be opened." alert.informativeText = "It may be damaged or use a file format that PDF Reader Pro doesn’t recognize." alert.addButton(withTitle: "Cancel") alert.beginSheetModal(for: NSApp.mainWindow!) { (response) in if response == NSApplication.ModalResponse.alertFirstButtonReturn { // Cancel button clicked } } return } self.filePathLabel.stringValue = url.path self.watermark.imagePath = url.path self.watermark.image = NSImage(contentsOfFile: url.path) self.watermark.text = "" self.templateNameTextField.stringValue = self.watermark.watermarkID self.applyButton.isEnabled = true self.batchButton.isEnabled = true self.pdfView.setNeedsDisplay(NSRect.zero) } } } } @IBAction func buttonClicked_Batch(_ sender: Any) { let needSave = saveToTemplateButton.state == .on if needSave { if templateNameTextField.stringValue.isEmpty { self.watermark.watermarkID = templateNameTextField.stringValue } else { self.watermark.watermarkID = KMWatermarkManager.defaultManager.fetchAvailableName() } let result = KMWatermarkManager.defaultManager.addWatermark(watermark: self.watermark) if !result { return } } if let operateCallBack = self.operateCallBack { operateCallBack(self.watermark, currentType) } // self.cancelAction?(self) } @IBAction func buttonClicked_Cancel(_ sender: Any) { self.pdfView.watermark = nil self.pdfView.background = nil self.pdfView.headerFooter = nil self.cancelAction?(self) } @IBAction func buttonClicked_Done(_ sender: Any) { guard let pdfDocument = pdfDocument else { return } if self.watermark.imagePath.count == 0 { if self.watermark.text.isEmpty { return } } if checkPageRangeValidate(pageRangeComboBox.stringValue) { watermark.pagesString = pageRangeComboBox.stringValue self.updatePDFView() window?.makeFirstResponder(self) } let needSave = saveToTemplateButton.state == .on var pages = [Int]() switch pageRangeComboBox.indexOfSelectedItem { case 0: pages = Array(0.. ()) { DispatchQueue.main.async { let wm = KMWatermarkView() wm.pdfView = KMWatermarkPDFView() wm.pdfView.document = document wm.password = document.password ?? "" wm.addWatermark(model: model, toPath: toPath, completion: completion) } } func addWatermark(model: KMWatermarkModel, toPath: String, completion: @escaping (_ result: Bool) -> ()) { DispatchQueue.global().async { let waterDocument = CPDFDocument(url: self.pdfView.document.documentURL) guard let waterDocumentT = waterDocument else { return } if self.password.isEmpty == false { waterDocumentT.unlock(withPassword: self.password) } var property: CPDFWatermark! var scale: CGFloat = model.scale if model.image != nil { property = CPDFWatermark(document: waterDocument, type: .image) property.image = model.image } else { property = CPDFWatermark(document: waterDocument, type: .text) property.text = model.text property.textColor = model.getTextColor() scale = model.getTextFontSize() / 24.0 } property.scale = scale property.rotation = -model.rotation property.opacity = model.opacity property.tx = model.horizontalSpace property.ty = model.verticalSpace property.isFront = model.isFront var pageString: String = "" if (model.pageRangeType == .all) { for i in 0.. = self.preView.document.watermarks() // for watermark in watermarks { // let model = KMWatermarkModel() // model.scale = watermark.scale // model.rotation = -watermark.rotation // model.opacity = watermark.opacity // model.verticalSpace = watermark.tx // model.horizontalSpace = watermark.ty // model.pagesString = watermark.pageString //// model.textColor = watermark.textColor // model.isFront = watermark.isFront // model.isTilePage = watermark.isTilePage // model.tileVerticalSpace = watermark.verticalSpacing // model.tileHorizontalSpace = watermark.horizontalSpacing // // if (watermark.type == .text) { // model.text = watermark.text //// model.textFont // model.scale = watermark.scale * 24 // } else if (watermark.type == .image) { // model.image = watermark.image // } // // if (watermark.verticalPosition == .top) { // model.verticalMode = 0 // } else if (watermark.verticalPosition == .center) { // model.verticalMode = 1 // } else if (watermark.verticalPosition == .bottom) { // model.verticalMode = 2 // } // // if (watermark.horizontalPosition == .left) { // model.horizontalMode = 0 // } else if (watermark.horizontalPosition == .center) { // model.horizontalMode = 1 // } else if (watermark.horizontalPosition == .right) { // model.horizontalMode = 2 // } // // model.watermark = watermark // self.watermarkArray.append(model) // } // } } func deleteWatermarks(toPath: String, completion: @escaping (_ result: Bool) -> ()) -> () { if (self.pdfView.document.watermarks().count <= 0) { completion(false) } DispatchQueue.global().async { let array: Array = self.pdfView.document.watermarks() for model in array { self.pdfView.document.removeWatermark(model) } /// 保存到临时路径 let documentPath = NSTemporaryDirectory() let tempPath: String = "\(documentPath)/\(toPath.lastPathComponent)" if (FileManager.default.fileExists(atPath: tempPath)) { try?FileManager.default.removeItem(atPath: tempPath) } let result = self.pdfView.document.write(to: URL(fileURLWithPath: tempPath)) if (result) { if (FileManager.default.fileExists(atPath: toPath)) { try?FileManager.default.removeItem(atPath: toPath) } try?FileManager.default.moveItem(atPath: tempPath, toPath: toPath) } else { try?FileManager.default.removeItem(atPath: tempPath) } DispatchQueue.main.async { completion(result) } } } }