// // KMAddBackgroundView.swift // PDF Reader Pro // // Created by lizhe on 2023/11/14. // import Cocoa enum KMBackgroundManagerType: Int { case add = 0 case edit case use } typealias KMAddBackgroundViewOperateCallBack = (_ background: KMBackgroundModel, _ countType: Int) -> () typealias KMAddBackgroundViewBatchAction = (_ view: KMAddBackgroundView, _ files: [KMFileAttribute]) -> Void typealias KMAddBackgroundViewCancelAction = (_ view: KMAddBackgroundView) -> Void class KMAddBackgroundView: KMBaseXibView, NSComboBoxDelegate { @IBOutlet weak var pdfView: KMWatermarkPDFView! @IBOutlet weak var previousButton: NSButton! @IBOutlet weak var nextButton: NSButton! @IBOutlet weak var currentPageIndexTextField: NSTextField! @IBOutlet weak var totalPageCountlabel: NSTextField! @IBOutlet weak var typeBox: NSBox! @IBOutlet weak var colorButton: NSButton! @IBOutlet weak var colorWell: NSColorWell! @IBOutlet weak var fileButton: NSButton! @IBOutlet weak var filePathLabel: NSTextField! @IBOutlet weak var browseButton: NSButton! @IBOutlet weak var ratioLabel: NSTextField! @IBOutlet weak var ratioTextField: NSTextField! @IBOutlet weak var ratioStepper: NSStepper! @IBOutlet weak var appearanceBox: NSBox! @IBOutlet weak var angleLabel: NSTextField! @IBOutlet weak var angleTextField: NSTextField! @IBOutlet weak var angleStepper: NSStepper! @IBOutlet weak var left45IndicateView: KMAngleIndicateView! @IBOutlet weak var horizontalIndicateView: KMAngleIndicateView! @IBOutlet weak var right45IndicateView: KMAngleIndicateView! @IBOutlet weak var alphaLabel: NSTextField! @IBOutlet weak var alphaSlider: NSSlider! @IBOutlet weak var alphaTextField: NSTextField! @IBOutlet weak var alphaStepper: NSStepper! @IBOutlet weak var postionView: KMPostionIndicateView! @IBOutlet weak var verticalGapLabel: NSTextField! @IBOutlet weak var verticalGapTextField: NSTextField! @IBOutlet weak var verticalStepper: NSStepper! @IBOutlet weak var horizontalGapLabel: NSTextField! @IBOutlet weak var horizontalGapTextField: NSTextField! @IBOutlet weak var horizontalStepper: NSStepper! @IBOutlet weak var pageRangeComboBox: NSComboBox! @IBOutlet weak var pageRangeLabel: NSTextField! @IBOutlet weak var saveToTemplateButton: NSButton! @IBOutlet weak var templateNameLabel: NSTextField! @IBOutlet weak var templateNameTextField: NSTextField! @IBOutlet weak var doneButton: NSButton! @IBOutlet weak var cancelButton: NSButton! @IBOutlet weak var batchButton: NSButton! var isHiddenBatchBtn: Bool = false private var workItem: DispatchWorkItem? var isAllowReloadDocument = true lazy var background: KMBackgroundModel = { var bg = KMBackgroundModel() bg.type = .color bg.color = .red bg.opacity = 1.0 bg.scale = 1.0 bg.verticalMode = 1 bg.horizontalMode = 1 bg.backgroundID = KMBackgroundManager.defaultManager.fetchAvailableName() self.initialID = bg.backgroundID bg.pagesString = "" bg.pageRangeType = .all return bg }() var originalBackground: KMBackgroundModel = KMBackgroundModel() var filePath: String = Bundle.main.path(forResource: "Quick Start Guide", ofType: "pdf") ?? "" var password: String = "" var type: KMBackgroundManagerType = .use var pdfDocument: CPDFDocument? { didSet { self._fileAttri = KMFileAttribute() self._fileAttri?.password = self.pdfDocument?.password ?? "" self._fileAttri?.filePath = self.pdfDocument?.documentURL.path ?? "" self.password = pdfDocument?.password ?? "" self.pdfView.document = pdfDocument self.reloadData() } } var backgroundType: KMBackgroundType = .color var initialID: String! var currentType: Int = 0 var cancelAction: KMAddBackgroundViewCancelAction? var batchAction: KMAddBackgroundViewCancelAction? var operateCallBack: KMAddBackgroundViewOperateCallBack? var onlyManagerTemplate: Bool = true private var _fileAttri: KMFileAttribute? // MARK: - Dealloc deinit { NotificationCenter.default.removeObserver(self) } // MARK: - Init Methods convenience init?(baseFile filePath: String, background backgroundObject: KMBackgroundModel, password: String, type: KMBackgroundManagerType, fileType countType: Int) { self.init() self.filePath = filePath self.password = password self.background = backgroundObject self.originalBackground = backgroundObject self.initialID = backgroundObject.backgroundID self.type = type self.pdfDocument = CPDFDocument(url: URL(fileURLWithPath: self.filePath)) if pdfDocument!.isLocked { pdfDocument!.unlock(withPassword: password) } if pdfDocument!.isLocked { return nil } } override func setup() { // pdfView.background = background // pdfView.document = pdfDocument pdfView.autoScales = true pdfView.setDisplay(.singlePage) // pdfView.documentView?.enclosingScrollView?.hasVerticalScroller = false // pdfView.documentView?.enclosingScrollView?.hasHorizontalScroller = false for i in 0..<3 { for j in 0..<3 { if i == Int(background.horizontalMode) && j == Int(background.verticalMode) { postionView.style = KMPositionIndicateViewStyle(rawValue: i + 3 * j)! } } } postionView.styleChangedCallBack = { [weak self] in guard let self = self else { return } self.background.horizontalMode = self.postionView.style.rawValue % 3 self.background.verticalMode = self.postionView.style.rawValue / 3 self.self.updatePDFView() if self.filePathLabel.stringValue.count > 0 { self.doneButton.isEnabled = true } } currentPageIndexTextField.stringValue = "1" // let numberFormatter = currentPageIndexTextField.formatter as! NumberFormatter // numberFormatter.maximum = NSNumber(value: pdfDocument.pageCount) let countFormatter = TextFieldFormatter.init() countFormatter.allowedCharacterSet = "-" self.angleTextField.formatter = countFormatter angleTextField.delegate = self let formatter = TextFieldFormatter.init() formatter.allowedCharacterSet = "-." self.verticalGapTextField.formatter = formatter self.verticalGapTextField.delegate = self let formatter2 = TextFieldFormatter.init() formatter2.allowedCharacterSet = "-." self.horizontalGapTextField.formatter = formatter2 self.horizontalGapTextField.delegate = self let formatter3 = TextFieldFormatter.init() formatter3.allowedCharacterSet = "%" self.alphaTextField.formatter = formatter3 alphaTextField.delegate = self left45IndicateView.style = .left45 left45IndicateView.touchCallBack = { [weak self] in guard let self = self else { return } self.background.rotation = -45 self.angleStepper.doubleValue = -45 self.angleTextField.stringValue = "\(-45)" self.checkAngle() if self.filePathLabel.stringValue.count > 0 { self.doneButton.isEnabled = true } self.updatePDFView() } horizontalIndicateView.style = .horizontal horizontalIndicateView.touchCallBack = { [weak self] in guard let self = self else { return } self.background.rotation = 0 self.angleStepper.doubleValue = 0 self.angleTextField.stringValue = "\(0)" self.checkAngle() if self.filePathLabel.stringValue.count > 0 { self.doneButton.isEnabled = true } self.updatePDFView() } right45IndicateView.style = .right45 right45IndicateView.touchCallBack = { [weak self] in guard let self = self else { return } self.background.rotation = 45 self.angleStepper.doubleValue = 45 self.angleTextField.stringValue = "\(45)" self.checkAngle() if self.filePathLabel.stringValue.count > 0 { self.doneButton.isEnabled = true } self.updatePDFView() } checkAngle() typeBox.titleFont = NSFont.systemFont(ofSize: 13) colorWell.color = background.color ?? NSColor.red templateNameTextField.stringValue = background.backgroundID appearanceBox.titleFont = NSFont.systemFont(ofSize: 13) saveToTemplateButton.isEnabled = onlyManagerTemplate // if type == .use { // saveToTemplateButton.isHidden = true // saveToTemplateButton.state = .off // } else { // saveToTemplateButton.isHidden = false // saveToTemplateButton.state = .on // } 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 colorWell.target = self colorWell.action = #selector(colorWellDidChange) } override func addNotification() { NotificationCenter.default.addObserver(self, selector: #selector(pageChangeNotification), name: NSNotification.Name.CPDFViewPageChanged, object: self.pdfView) } override func updateLanguage() { typeBox.title = NSLocalizedString("Source", comment: "") self.templateNameLabel.stringValue = NSLocalizedString("Name:", comment: "") batchButton.title = NSLocalizedString("Batch", comment: ""); cancelButton.title = NSLocalizedString("Cancel", comment: ""); colorButton.title = NSLocalizedString("Color", comment: "") fileButton.title = NSLocalizedString("File", comment: "") browseButton.title = NSLocalizedString("Choose...", comment: "") ratioLabel.stringValue = "\(NSLocalizedString("Ratio", comment: "")):" appearanceBox.title = NSLocalizedString("Appearance", comment: "") angleLabel.stringValue = "\(NSLocalizedString("Rotation", comment: "")):" alphaLabel.stringValue = "\(NSLocalizedString("Opacity", comment: "")):" pageRangeLabel.stringValue = "\(NSLocalizedString("Page Range", comment: "")):" horizontalGapLabel.stringValue = "X:" verticalGapLabel.stringValue = "Y:" templateNameLabel.stringValue = NSLocalizedString("Label", comment: "") saveToTemplateButton.title = NSLocalizedString("Add to Template", comment: "") if (self.type == .add) { self.doneButton.title = NSLocalizedString("Apply", comment: ""); self.batchButton.isHidden = true } else if (self.type == .edit) { self.doneButton.title = NSLocalizedString("Apply", comment: ""); self.batchButton.isHidden = true } else if (self.type == .use) { self.doneButton.title = NSLocalizedString("Save & Apply", comment: ""); } } private func checkAngle() { left45IndicateView.isSelcted = false horizontalIndicateView.isSelcted = false right45IndicateView.isSelcted = false if background.rotation == 45 { right45IndicateView.isSelcted = true } else if background.rotation == 0 { horizontalIndicateView.isSelcted = true } else if background.rotation == -45 { left45IndicateView.isSelcted = true } } override func reloadData() { guard let pdfDocument = pdfDocument else { return } totalPageCountlabel.stringValue = "/ \(pdfDocument.pageCount)" templateNameTextField.stringValue = background.backgroundID colorWell.color = background.color ?? NSColor.red filePathLabel.stringValue = background.imagePath filePathLabel.placeholderString = NSLocalizedString("Select a File", comment: "") angleStepper.doubleValue = Double(background.rotation) angleTextField.stringValue = "\(angleStepper.intValue)" alphaSlider.doubleValue = background.opacity alphaStepper.doubleValue = background.opacity let opacity = round(background.opacity * 100) / 100 alphaTextField.stringValue = "\(Int(opacity * 100))%" ratioStepper.doubleValue = background.scale ratioTextField.stringValue = "\(Int(background.scale * 100))%" if currentType == 0 { changeTypeBoxState(true) } else { changeTypeBoxState(false) } pageRangeComboBox.delegate = nil switch background.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 = background.pagesString window?.makeFirstResponder(pageRangeComboBox) } pageRangeComboBox.delegate = self verticalStepper.doubleValue = background.verticalSpace verticalGapTextField.stringValue = "\(verticalStepper.doubleValue)" horizontalStepper.doubleValue = background.horizontalSpace horizontalGapTextField.stringValue = "\(horizontalStepper.doubleValue)" batchButton.isHidden = isHiddenBatchBtn if !isHiddenBatchBtn { self.batchButton.isHidden = type != .use } } private func changeTypeBoxState(_ isColor: Bool) { if isColor { currentType = 0 colorButton.state = .on colorWell.isEnabled = true fileButton.state = .off browseButton.isEnabled = false ratioTextField.isEnabled = false ratioStepper.isEnabled = false background.color = colorWell.color background.type = .color background.scale = 1 doneButton.isEnabled = true } else { currentType = 1 colorButton.state = .off colorWell.isEnabled = false fileButton.state = .on browseButton.isEnabled = true ratioTextField.isEnabled = true ratioStepper.isEnabled = true background.color = NSColor.white background.type = .file background.scale = ratioStepper.doubleValue doneButton.isEnabled = filePathLabel.stringValue.count > 0 } self.updatePDFView() } func updatePDFView() { // pdfView.needsDisplay = true // pdfView.layoutDocumentView() // pdfView.setNeedsDisplayForVisiblePages() // // Save to temporary path // let documentPath = NSTemporaryDirectory() // let tempPath = (documentPath as NSString).appendingPathComponent((path as NSString).lastPathComponent) // try? FileManager.default.removeItem(atPath: tempPath) // // let result = document.write(to: URL(fileURLWithPath: tempPath)) // if result { // if FileManager.default.fileExists(atPath: path) { // try? FileManager.default.removeItem(atPath: path) // } // try? FileManager.default.moveItem(atPath: tempPath, toPath: path) // } else { // try? FileManager.default.removeItem(atPath: tempPath) // } // 如果前一次调用还在执行,则取消它 workItem?.cancel() // 创建一个新的 DispatchWorkItem let newWorkItem = DispatchWorkItem { // 在这里执行你的方法的实际逻辑 self.reloadDocument() } // 将新的 DispatchWorkItem 分配给实例变量 workItem = newWorkItem // 在队列中执行 DispatchWorkItem DispatchQueue.main.async(execute: newWorkItem) } func reloadDocument() { if !self.isAllowReloadDocument { return } self.isAllowReloadDocument = false let document = CPDFDocument(url: self.pdfDocument?.documentURL) guard let document = document else { return } document.unlock(withPassword: self.pdfDocument?.password) let tBackground: CPDFBackground = document.background() tBackground.opacity = background.opacity tBackground.scale = background.scale tBackground.rotation = CGFloat(background.rotation) tBackground.horizontalAlignment = UInt(background.horizontalMode) tBackground.verticalAlignment = UInt(background.verticalMode) tBackground.xOffset = background.horizontalSpace tBackground.yOffset = background.verticalSpace if let color = background.color { tBackground.color = color tBackground.type = .color } if background.imagePath.count != 0 { if let data = background.image { tBackground.setImage(data) } else { if let image = NSImage(contentsOfFile: background.imagePath) { tBackground.setImage(image) } } tBackground.type = .image } if background.pagesString.count != 0 { tBackground.pageString = background.pagesString } else { let pageString = "0-\(document.pageCount - 1)" tBackground.pageString = pageString } tBackground.update() self.pdfView.document = document DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { self.isAllowReloadDocument = true } } // Other methods... @objc func controlTextDidEndEditing(_ notification: Notification) { guard let textField = notification.object as? NSTextField else { return } switch textField { case ratioTextField: let formatter = textField.formatter as? NumberFormatter if let floatValue = formatter?.number(from: textField.stringValue)?.floatValue { ratioStepper.doubleValue = Double(floatValue) background.scale = Double(floatValue) self.updatePDFView() } case angleTextField: if let integerValue = Int(textField.stringValue) { background.rotation = CGFloat(integerValue) angleStepper.doubleValue = Double(background.rotation) checkAngle() self.updatePDFView() } case alphaTextField: let floatValue = textField.stringValue.replacingOccurrences(of: "%", with: "").stringToCGFloat() * 0.01 alphaSlider.doubleValue = Double(floatValue) alphaStepper.doubleValue = Double(floatValue) background.opacity = Double(floatValue) self.updatePDFView() case pageRangeComboBox: if pageRangeComboBox.indexOfSelectedItem == -1 { if !checkPageRangeValidate(pageRangeComboBox.stringValue) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = "\(pdfDocument!.documentURL.lastPathComponent) \(NSLocalizedString("Invalid page range or the page number is out of range. Please try again.", comment: ""))" alert.runModal() window?.makeFirstResponder(pageRangeComboBox) return } else { background.pagesString = pageRangeComboBox.stringValue self.updatePDFView() } } case verticalGapTextField: if let integerValue = Int(verticalGapTextField.stringValue) { background.verticalSpace = CGFloat(integerValue) verticalStepper.doubleValue = background.verticalSpace self.updatePDFView() } case horizontalGapTextField: if let integerValue = Int(horizontalGapTextField.stringValue) { background.horizontalSpace = CGFloat(integerValue) horizontalStepper.doubleValue = background.horizontalSpace self.updatePDFView() } case currentPageIndexTextField: if let pageIndex = Int(currentPageIndexTextField.stringValue), let page = pdfDocument!.page(at: UInt(pageIndex - 1)) { pdfView.go(to: page) } default: break } if filePathLabel.stringValue.count > 0 { doneButton.isEnabled = true } } @objc func comboBoxSelectionDidChange(_ notification: Notification) { guard notification.object as? NSComboBox == pageRangeComboBox else { return } pageRangeComboBox.isEditable = false switch pageRangeComboBox.indexOfSelectedItem { case 0: background.pageRangeType = .all case 1: background.pageRangeType = .odd case 2: background.pageRangeType = .even default: background.pageRangeType = .other pageRangeComboBox.stringValue = "" pageRangeComboBox.isEditable = true window?.makeFirstResponder(pageRangeComboBox) } if filePathLabel.stringValue.count > 0 { doneButton.isEnabled = true } } 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?.filePath = pdfDocument!.documentURL.path fileAttribute?.bAllPage = false fileAttribute?.pagesString = pageRangeComboBox.stringValue var pageRange: KMPageRange = .all let pageRangeType: KMWatermarkeModelPageRangeType = background.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 return fileAttribute!.fetchSelectPages().count != 0 } func saveAsPDF(with background: KMBackgroundModel, to path: String, autoOpen: Bool) { self.window?.makeFirstResponder(nil) DispatchQueue.global(qos: .default).async { [unowned self] in var filePath = self.pdfDocument!.documentURL?.path let password = self.password if filePath == nil { let writeSuccess = self.pdfDocument!.write(to: URL(fileURLWithPath: kNewDocumentTempSavePath(NSLocalizedString("Untitled", comment: "")))) if writeSuccess { self.pdfDocument = CPDFDocument(url: URL(fileURLWithPath: kNewDocumentTempSavePath(NSLocalizedString("Untitled", comment: ""))))! filePath = self.pdfDocument!.documentURL?.path } } let document = CPDFDocument(url: URL(fileURLWithPath: filePath!))! document.unlock(withPassword: password) let tBackground: CPDFBackground = document.background() tBackground.opacity = background.opacity tBackground.scale = background.scale tBackground.rotation = CGFloat(background.rotation) tBackground.horizontalAlignment = UInt(background.horizontalMode) tBackground.verticalAlignment = UInt(background.verticalMode) tBackground.xOffset = background.horizontalSpace tBackground.yOffset = background.verticalSpace if let color = background.color { tBackground.color = color tBackground.type = .color } else if background.imagePath.count != 0 { let image = NSImage(contentsOfFile: background.imagePath)! tBackground.setImage(image) tBackground.type = .image } if background.pagesString.count != 0 { tBackground.pageString = background.pagesString } else { let pageString = "0-\(document.pageCount - 1)" tBackground.pageString = pageString } tBackground.update() // Save to temporary path let documentPath = NSTemporaryDirectory() let tempPath = (documentPath as NSString).appendingPathComponent((path as NSString).lastPathComponent) try? FileManager.default.removeItem(atPath: tempPath) let result = document.write(to: URL(fileURLWithPath: tempPath)) if result { if FileManager.default.fileExists(atPath: path) { try? FileManager.default.removeItem(atPath: path) } try? FileManager.default.moveItem(atPath: tempPath, toPath: path) } else { try? FileManager.default.removeItem(atPath: tempPath) } if result { DispatchQueue.main.async { let needSave = self.saveToTemplateButton.state == .on if needSave { if self.checkPageRangeValidate(self.pageRangeComboBox.stringValue) && self.pageRangeComboBox.indexOfSelectedItem == -1 { self.background.pagesString = self.pageRangeComboBox.stringValue } KMBackgroundManager.defaultManager.addTemplate(model: self.background) NotificationCenter.default.post(name: NSNotification.Name("KMBatchOperateWatermarksNotification"), object: self) } self.cancelAction?(self) if autoOpen { NSDocumentController.shared.openDocument(withContentsOf: URL(fileURLWithPath: path), display: true) { _, _, _ in } } else { NSWorkspace.shared.selectFile(path, inFileViewerRootedAtPath: "") } } } } } static func saveAsPDFRemoveAllBackground(PDFDocument: CPDFDocument, password: String?, toPath path: String, completionHandler handler: ((Int) -> Void)?) { DispatchQueue.global(qos: .default).async { guard let filePath = PDFDocument.documentURL?.path else { return } let document = CPDFDocument(url: URL(fileURLWithPath: filePath)) if let password = password { document?.unlock(withPassword: password) } let tBackground: CPDFBackground = document!.background() tBackground.clear() // Save to a temporary path let documentPath = NSTemporaryDirectory() let tempPath = (documentPath as NSString).appendingPathComponent((path as NSString).lastPathComponent) if FileManager.default.fileExists(atPath: tempPath) { try? FileManager.default.removeItem(atPath: tempPath) } if let result = document?.write(to: URL(fileURLWithPath: tempPath)) { if FileManager.default.fileExists(atPath: path) { try? FileManager.default.removeItem(atPath: path) } try? FileManager.default.moveItem(atPath: tempPath, toPath: path) DispatchQueue.main.async { handler?(1) } } else { try? FileManager.default.removeItem(atPath: tempPath) DispatchQueue.main.async { handler?(0) } } } } func kNewDocumentTempSavePath(_ fileName: String) -> String { let searchPath = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last let append1 = searchPath?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!) let append2 = append1!.stringByAppendingPathComponent(String(format: "%@", fileName)) return append2 } func isDamageImage(_ image: NSImage, imagePath path: String) -> Bool { let addImageAnnotation = (NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last! as NSString).appendingPathComponent(Bundle.main.bundleIdentifier!).stringByAppendingPathComponent("addImageAnnotation") 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 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(tagString() + ".png") return ((try? imageData?.write(to: URL(fileURLWithPath: rPath), options: .atomic)) == nil) } func tagString() -> String { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyMMddHHmmss" return String(format: "%@%04d", dateFormatter.string(from: Date()), arc4random() % 10000) } // ... (remaining methods) @objc func pageChangeNotification(notification: NSNotification) { currentPageIndexTextField.stringValue = "\(pdfView.currentPage().pageIndex() + 1)" } } extension KMAddBackgroundView { @IBAction func cancelButtonAction(_ sender: Any) { guard let callBack = cancelAction else { return } callBack(self) } @IBAction func buttonClicked_SwitchBackgroundType(_ sender: Any) { changeTypeBoxState(sender as? NSObject == colorButton) } // @IBAction func colorWellChanged(_ sender: NSColorWell) { // background.color = sender.color // self.updatePDFView() // } @objc func colorWellDidChange(_ sender: NSColorWell) { if let color = sender.color.usingColorSpaceName(NSColorSpaceName.calibratedRGB) { background.color = color self.updatePDFView() } } @IBAction func radioStepperAction(_ sender: NSStepper) { ratioTextField.stringValue = "\(Int(sender.doubleValue * 100))%" background.scale = sender.doubleValue self.updatePDFView() if filePathLabel.stringValue.count > 0 { doneButton.isEnabled = true } } @IBAction func angleStepperAction(_ sender: NSStepper) { angleTextField.stringValue = "\(sender.doubleValue)" background.rotation = CGFloat(Int(sender.doubleValue)) checkAngle() self.updatePDFView() if filePathLabel.stringValue.count > 0 { doneButton.isEnabled = true } } @IBAction func alphaSliderAction(_ sender: NSSlider) { background.opacity = sender.doubleValue alphaStepper.doubleValue = sender.doubleValue alphaTextField.stringValue = "\(Int(sender.doubleValue * 100))%" if filePathLabel.stringValue.count > 0 { doneButton.isEnabled = true } self.updatePDFView() } @IBAction func verticalStepperAction(_ sender: NSStepper) { verticalGapTextField.stringValue = "\(sender.doubleValue)" background.verticalSpace = sender.doubleValue self.updatePDFView() if filePathLabel.stringValue.count > 0 { doneButton.isEnabled = true } } @IBAction func horizentalStepperAction(_ sender: NSStepper) { horizontalGapTextField.stringValue = "\(sender.doubleValue)" background.horizontalSpace = sender.doubleValue self.updatePDFView() if filePathLabel.stringValue.count > 0 { doneButton.isEnabled = true } } @IBAction func alphaSteperAction(_ sender: NSStepper) { alphaTextField.stringValue = "\(Int(sender.doubleValue * 100))%" background.opacity = sender.doubleValue alphaSlider.doubleValue = sender.doubleValue self.updatePDFView() if filePathLabel.stringValue.count > 0 { doneButton.isEnabled = true } } @IBAction func goPrevious(_ sender: Any) { if pdfView.canGoToPreviousPage() { pdfView.goToPreviousPage(nil) } // let index = pdfDocument!.index(for: pdfView.currentPage()) // currentPageIndexTextField.stringValue = "\(index + 1)" } @IBAction func goNext(_ sender: Any) { if pdfView.canGoToNextPage() { pdfView.goToNextPage(nil) } // let index = pdfDocument!.index(for: pdfView.currentPage()) // currentPageIndexTextField.stringValue = "\(index + 1)" } @IBAction func buttonClicked_BrowserFile(_ sender: Any) { let openPanel = NSOpenPanel() openPanel.canChooseDirectories = false openPanel.canChooseFiles = true openPanel.allowsMultipleSelection = false openPanel.allowedFileTypes = ["jpg", "cur", "bmp", "jpeg", "gif", "png", "tiff", "tif", "ico", "icns", "tga", "psd", "eps", "hdr", "jp2", "jpc", "pict", "sgi", "pdf"] openPanel.beginSheetModal(for: window!) { (result) in if result == .OK { guard let url = openPanel.url else { return } let filePath: NSString = url.path as NSString if filePath.pathExtension.lowercased() == "pdf" { let pdf = CPDFDocument(url: url) if pdf?.isEncrypted == true { return } } if let image = NSImage(contentsOfFile: url.path), !self.isDamageImage(image, imagePath: url.path) { self.filePathLabel.stringValue = url.path self.doneButton.isEnabled = true self.background.imagePath = url.path self.background.image = image self.background.backgroundID = url.path.lastPathComponent.deletingPathExtension self.templateNameTextField.stringValue = url.path.lastPathComponent.deletingPathExtension self.self.updatePDFView() } } } } // ... (remaining IBActions) @IBAction func buttonClicked_Batch(_ sender: Any) { if background.type == .color { background.imagePath = "" } else { background.color = nil if background.image == nil { return } } if templateNameTextField.stringValue.count < 1 { background.backgroundID = initialID } else { background.backgroundID = templateNameTextField.stringValue } let needSave = saveToTemplateButton.state == .on if needSave { KMBackgroundManager.defaultManager.addTemplate(model: background) } operateCallBack?(background, currentType) } @IBAction func buttonClicked_Done(_ sender: Any) { guard let pdfDocument = pdfDocument else { return } if background.type == .color { background.imagePath = "" } else { background.color = nil if background.image == nil { return } } if templateNameTextField.stringValue.isEmpty { background.backgroundID = initialID } else { background.backgroundID = templateNameTextField.stringValue } // Avoid showing the page range alert twice if checkPageRangeValidate(pageRangeComboBox.stringValue) { background.pagesString = pageRangeComboBox.stringValue self.updatePDFView() window?.makeFirstResponder(self) } let needSave = saveToTemplateButton.state == .on var pages = [Int]() switch pageRangeComboBox.indexOfSelectedItem { case 0: pages = Array(0..