// // KMWatermarkManager.swift // PDF Reader Pro // // Created by tangchao on 2022/12/19. // import Cocoa let KMWaterMarkDatasUpdateNotiName = NSNotification.Name("KMWaterMarkDatasUpdateNotiName") enum KMWatermarkKey: String { case watermarkType = "watermarkTypeKey" case text = "WatermarTextKey" case textFontSize = "WatermarkOfTextFontSizeKey" case textfontStyle = "WatermarkOfTextFontStyleKey" case textFontName = "textFontName" case textColor = "WatermarkTextColorKey" case red = "WatermarkOfRedKey" case green = "WatermarkOfGreenKey" case blue = "WatermarkOfBlueKey" case imagePath = "WatermarkOfImagePathKey" case rotate = "WatermarkOfRotationKey" case opacity = "WatermarkOfOpacityKey" case isScale = "WatermarkOfIsScaleKey" case scale = "WatermarkOfScaleKey" case verticalMode = "WatermarkOfVerticalModeKey" case verticalSpace = "WatermarkOfVerticalSpaceKey" case horizontalMode = "WatermarkOfHorizontalModeKey" case horizontalSpace = "WatermarkOfHorizontalSpaceKey" case isFront = "WatermarkOfIsFrontKey" case createDate = "WatermarkOfCreatTemplateDateKey" case pageRangeType = "WatermarkOfPageRangeTypeKey" case pageRangeString = "WatermarkOfPageStringKey" case tileVerticalSpace = "WatermarkTileVerticalSpaceKey" case tileHorizontalSpace = "WatermarkTileHorizontalSpaceKey" case isTile = "WatermarkOfIsTileKey" case lastAddData = "kAddLastWatermarkDataKey1" case id = "kWatermarkIDKey" case tag = "kWatermarkTagKey" case watermarkName = "watermarkNameKey" } class KMWatermarkManager: NSObject { let watermarkFolderPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!).stringByAppendingPathComponent("watermark") let watermarkPlistPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!).stringByAppendingPathComponent("watermark").stringByAppendingPathComponent("watermark.plist") let watermarkImageFolder = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!).stringByAppendingPathComponent("watermark").stringByAppendingPathComponent("image") static let defaultManager = KMWatermarkManager() var watermarks: Array = [] var defaultWatermarkData = KMWatermarkModel.defaultWDData() override init() { super.init() #if DEBUG print("watermarkPlistPath=\(watermarkPlistPath ?? "")") #endif if (!FileManager.default.fileExists(atPath: watermarkFolderPath!)) { try?FileManager.default.createDirectory(atPath: watermarkFolderPath!, withIntermediateDirectories: true, attributes: nil) } if (!FileManager.default.fileExists(atPath: watermarkImageFolder!)) { let create: ()? = try?FileManager.default.createDirectory(atPath: watermarkImageFolder!, withIntermediateDirectories: false) } if (FileManager.default.fileExists(atPath: watermarkPlistPath!)) { let dataDict = NSDictionary(contentsOfFile: watermarkPlistPath!) for keyIndex in 0 ..< (dataDict?.allKeys.count ?? 0) { let key: String = dataDict?.allKeys[keyIndex] as! String let watermarkDict: NSDictionary = dataDict?.object(forKey: key) as! NSDictionary let model = parseDictionary(dict: watermarkDict) watermarks.append(model) } watermarks.sort(){$0.tag > $1.tag} } } //MARK: - 增删改查 func addWatermark(watermark: KMWatermarkModel) -> Bool { if (!FileManager.default.fileExists(atPath: watermarkFolderPath!)) { let create: ()? = try?FileManager.default.createDirectory(atPath: watermarkFolderPath!, withIntermediateDirectories: true, attributes: nil) if (create == nil) { return false } } if (!FileManager.default.fileExists(atPath: watermarkPlistPath!)) { FileManager.default.createFile(atPath: watermarkPlistPath!, contents: nil) } let dict = NSDictionary(contentsOfFile: watermarkPlistPath!) var newDict:NSMutableDictionary! if (dict != nil) { newDict = NSMutableDictionary(dictionary: dict!) } else { newDict = NSMutableDictionary() } let watermarkDict = self.parseWaterMark(model: watermark) if (watermarkDict.isEmpty) { return false } let key: String = watermark.tag if newDict.object(forKey: key) != nil { newDict.setObject(watermarkDict, forKey: key as NSCopying) } else { newDict.addEntries(from: [key : watermarkDict]) } let result = newDict.write(toFile: watermarkPlistPath!, atomically: true) if (result) { if (self.watermarks.count < 1) { self.watermarks.append(watermark) } else { self.watermarks.insert(watermark, at: 0) } watermark.updatePreviewImage() } NotificationCenter.default.post(name: KMWaterMarkDatasUpdateNotiName, object: nil) return result } func updateWatermark(watermark: KMWatermarkModel) -> Bool { if (!FileManager.default.fileExists(atPath: watermarkFolderPath!)) { let create: ()? = try?FileManager.default.createDirectory(atPath: watermarkFolderPath!, withIntermediateDirectories: false) if (create == nil) { return false } } if (!FileManager.default.fileExists(atPath: watermarkPlistPath!)) { FileManager.default.createFile(atPath: watermarkPlistPath!, contents: nil) } var flagModel: KMWatermarkModel! for model in self.watermarks { if (model.tag == watermark.tag) { flagModel = model break } } if (flagModel == nil) { return false } let dict = NSDictionary(contentsOfFile: watermarkPlistPath!) var newDict:NSMutableDictionary! if (dict != nil) { newDict = NSMutableDictionary(dictionary: dict!) } else { newDict = NSMutableDictionary() } let watermarkDict = self.parseWaterMark(model: watermark) if (watermarkDict.isEmpty) { return false } newDict.setObject(watermarkDict, forKey: flagModel.tag as NSCopying) let result = newDict.write(toFile: watermarkPlistPath!, atomically: true) if (result) { if let index = self.watermarks.firstIndex(of: flagModel) { self.watermarks[index] = watermark } watermark.updatePreviewImage() } NotificationCenter.default.post(name: KMWaterMarkDatasUpdateNotiName, object: nil) return result } func removeWatermark(watermark: KMWatermarkModel) -> Bool { if (!FileManager.default.fileExists(atPath: watermarkPlistPath!)) { return false } let key: String = watermark.tag let dictionary = NSDictionary(contentsOfFile: watermarkPlistPath!) var newDictionary: NSMutableDictionary! if (dictionary != nil) { newDictionary = NSMutableDictionary(dictionary: dictionary!) } else { newDictionary = NSMutableDictionary() } newDictionary.removeObject(forKey: key) let result = newDictionary.write(toFile: watermarkPlistPath!, atomically: true) if (result) { if let filePath: String = watermark.imagePath { try?FileManager.default.removeItem(atPath: filePath) } if (self.watermarks.contains(watermark)) { self.watermarks.removeObject(watermark) } } NotificationCenter.default.post(name: KMWaterMarkDatasUpdateNotiName, object: nil) return result } func removeAllWatermark() -> Bool { if (!FileManager.default.fileExists(atPath: watermarkPlistPath!)) { return false } let dictionary = NSDictionary(contentsOfFile: watermarkPlistPath!) var newDictionary: NSMutableDictionary! if (dictionary != nil) { newDictionary = NSMutableDictionary(dictionary: dictionary!) } else { newDictionary = NSMutableDictionary() } newDictionary.removeAllObjects() let result = newDictionary.write(toFile: watermarkPlistPath!, atomically: true) if (result) { self.watermarks.removeAll() } NotificationCenter.default.post(name: KMWaterMarkDatasUpdateNotiName, object: nil) return result } //MARK: - private func setDictToWatermarK(dict: NSDictionary, _ model: KMWatermarkModel) { model.watermarkType = .text if let typeIndex = dict.object(forKey: KMWatermarkKey.watermarkType.rawValue) as? AnyObject { if let rawValue = typeIndex as? Int { model.watermarkType = CPDFWatermarkType(rawValue: rawValue) ?? .text } else if let rawValue = typeIndex as? String, let rawIndex = Int(rawValue) { model.watermarkType = CPDFWatermarkType(rawValue: rawIndex) ?? .text } } model.text = (dict.object(forKey: KMWatermarkKey.text.rawValue) as? String) model.fontName = (dict.object(forKey: KMWatermarkKey.textFontName.rawValue) as? String) ?? "" model.fontStyle = (dict.object(forKey: KMWatermarkKey.textfontStyle.rawValue) as? String) ?? "" model.fontSize = (dict.object(forKey: KMWatermarkKey.textFontSize.rawValue) as? CGFloat) ?? 12 if let pathValue = dict.object(forKey: KMWatermarkKey.imagePath.rawValue) { let path = watermarkFolderPath?.stringByAppendingPathComponent(pathValue as! String) if (FileManager.default.fileExists(atPath: path!)) { model.imagePath = path ?? "" } } model.isScale = (dict.object(forKey: KMWatermarkKey.isScale.rawValue) as? Bool) ?? false model.scale = (dict.object(forKey: KMWatermarkKey.scale.rawValue) as? CGFloat) ?? 1 model.rotation = dict.object(forKey: KMWatermarkKey.rotate.rawValue) as? CGFloat ?? 0 model.opacity = (dict.object(forKey: KMWatermarkKey.opacity.rawValue) as? CGFloat) ?? 1 model.verticalPosition = (dict.object(forKey: KMWatermarkKey.verticalMode.rawValue) as? CPDFWatermarkVerticalPosition) ?? .center model.ty = dict.object(forKey: KMWatermarkKey.verticalSpace.rawValue) as? CGFloat ?? 0 model.horizontalPosition = (dict.object(forKey: KMWatermarkKey.horizontalMode.rawValue) as? CPDFWatermarkHorizontalPosition) ?? .center model.tx = dict.object(forKey: KMWatermarkKey.horizontalSpace.rawValue) as? CGFloat ?? 0 if let textColorKey = dict.object(forKey: KMWatermarkKey.textColor.rawValue) as? String { model.textColor = NSColor.km_init(hex: textColorKey) } else { let red: CGFloat = dict.object(forKey: KMWatermarkKey.red.rawValue) as? CGFloat ?? 0 let green: CGFloat = dict.object(forKey: KMWatermarkKey.green.rawValue) as? CGFloat ?? 0 let blue: CGFloat = dict.object(forKey: KMWatermarkKey.blue.rawValue) as? CGFloat ?? 0 model.textColor = NSColor(red: red, green: green, blue: blue, alpha: 1.0) } model.isFront = (dict.object(forKey: KMWatermarkKey.isFront.rawValue) as? Bool) ?? false model.isTilePage = (dict.object(forKey: KMWatermarkKey.isTile.rawValue) as? Bool) ?? false model.horizontalSpacing = (dict.object(forKey: KMWatermarkKey.tileHorizontalSpace.rawValue) as? CGFloat) ?? 0 model.verticalSpacing = (dict.object(forKey: KMWatermarkKey.tileVerticalSpace.rawValue) as? CGFloat) ?? 0 model.tag = (dict.object(forKey: KMWatermarkKey.tag.rawValue) as? String) ?? "" model.watermarkName = (dict.object(forKey: KMWatermarkKey.watermarkName.rawValue) as? String) ?? "" NotificationCenter.default.post(name: KMWaterMarkDatasUpdateNotiName, object: nil) } //MARK: - Parse func parseWaterMark(model: KMWatermarkModel) -> Dictionary { var dict: [String : Any] = [:] if model.watermarkType == .text { dict[KMWatermarkKey.watermarkType.rawValue] = NSNumber(value: 0) } else if model.watermarkType == .image { dict[KMWatermarkKey.watermarkType.rawValue] = NSNumber(value: 1) } if let text = model.text { dict[KMWatermarkKey.text.rawValue] = text } dict[KMWatermarkKey.textFontName.rawValue] = model.fontName dict[KMWatermarkKey.textfontStyle.rawValue] = model.fontStyle dict[KMWatermarkKey.textFontSize.rawValue] = model.fontSize if let imagePath = model.imagePath { dict[KMWatermarkKey.imagePath.rawValue] = imagePath } dict[KMWatermarkKey.isFront.rawValue] = model.isFront dict[KMWatermarkKey.isScale.rawValue] = model.isScale dict[KMWatermarkKey.scale.rawValue] = model.scale dict[KMWatermarkKey.opacity.rawValue] = model.opacity dict[KMWatermarkKey.rotate.rawValue] = model.rotation dict[KMWatermarkKey.verticalMode.rawValue] = model.verticalPosition.rawValue dict[KMWatermarkKey.verticalSpace.rawValue] = model.ty dict[KMWatermarkKey.horizontalMode.rawValue] = model.horizontalPosition.rawValue dict[KMWatermarkKey.horizontalSpace.rawValue] = model.tx dict[KMWatermarkKey.textColor.rawValue] = model.textColor.toHex() dict[KMWatermarkKey.isTile.rawValue] = model.isTilePage dict[KMWatermarkKey.tileVerticalSpace.rawValue] = model.verticalSpacing dict[KMWatermarkKey.tileHorizontalSpace.rawValue] = model.horizontalSpacing dict[KMWatermarkKey.tag.rawValue] = model.tag dict[KMWatermarkKey.watermarkName.rawValue] = model.watermarkName return dict } private func parseDictionary(dict: NSDictionary) -> KMWatermarkModel { let model = KMWatermarkModel() if let type = dict.object(forKey: KMWatermarkKey.watermarkType.rawValue) { if let data = type as? Int { model.watermarkType = CPDFWatermarkType(rawValue: data) ?? .text } else if let data = type as? String, let value = Int(data), value < 2 { model.watermarkType = CPDFWatermarkType(rawValue: value) ?? .text } else { model.watermarkType = .text } } else { model.watermarkType = .text } model.text = (dict.object(forKey: KMWatermarkKey.text.rawValue) as? String) model.fontName = (dict.object(forKey: KMWatermarkKey.textFontName.rawValue) as? String) ?? "" model.fontStyle = (dict.object(forKey: KMWatermarkKey.textfontStyle.rawValue) as? String) ?? "" model.fontSize = (dict.object(forKey: KMWatermarkKey.textFontSize.rawValue) as? CGFloat) ?? 12 if let pathValue = dict.object(forKey: KMWatermarkKey.imagePath.rawValue) { model.imagePath = pathValue as? String } model.isScale = (dict.object(forKey: KMWatermarkKey.isScale.rawValue) as? Bool) ?? false model.scale = (dict.object(forKey: KMWatermarkKey.scale.rawValue) as? CGFloat) ?? 1 model.rotation = dict.object(forKey: KMWatermarkKey.rotate.rawValue) as? CGFloat ?? 0 model.opacity = (dict.object(forKey: KMWatermarkKey.opacity.rawValue) as? CGFloat) ?? 1 model.verticalPosition = (dict.object(forKey: KMWatermarkKey.verticalMode.rawValue) as? CPDFWatermarkVerticalPosition) ?? .center model.ty = dict.object(forKey: KMWatermarkKey.verticalSpace.rawValue) as? CGFloat ?? 0 model.horizontalPosition = (dict.object(forKey: KMWatermarkKey.horizontalMode.rawValue) as? CPDFWatermarkHorizontalPosition) ?? .center model.tx = dict.object(forKey: KMWatermarkKey.horizontalSpace.rawValue) as? CGFloat ?? 0 if let textColorKey = dict.object(forKey: KMWatermarkKey.textColor.rawValue) as? String { model.textColor = NSColor.km_init(hex: textColorKey) } else { let red: CGFloat = dict.object(forKey: KMWatermarkKey.red.rawValue) as? CGFloat ?? 0 let green: CGFloat = dict.object(forKey: KMWatermarkKey.green.rawValue) as? CGFloat ?? 0 let blue: CGFloat = dict.object(forKey: KMWatermarkKey.blue.rawValue) as? CGFloat ?? 0 model.textColor = NSColor(red: red, green: green, blue: blue, alpha: 1.0) } model.isFront = (dict.object(forKey: KMWatermarkKey.isFront.rawValue) as? Bool) ?? false model.isTilePage = (dict.object(forKey: KMWatermarkKey.isTile.rawValue) as? Bool) ?? false model.horizontalSpacing = (dict.object(forKey: KMWatermarkKey.tileHorizontalSpace.rawValue) as? CGFloat) ?? 0 model.verticalSpacing = (dict.object(forKey: KMWatermarkKey.tileVerticalSpace.rawValue) as? CGFloat) ?? 0 model.tag = (dict.object(forKey: KMWatermarkKey.tag.rawValue) as? String) ?? "" model.watermarkName = (dict.object(forKey: KMWatermarkKey.watermarkName.rawValue) as? String) ?? "" return model } // 水平位置枚举 enum HorizontalPosition { case left case center case right } // 垂直位置枚举 enum VerticalPosition { case top case center case bottom } //MARK: - Getter func drawImageAtpageRect(rect: NSRect, data: KMWatermarkModel) -> NSImage? { var size = CGSize(width: 177*3, height: 252*3) let text: String = data.text ?? "" var color = data.textColor var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0 color.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: nil) color = NSColor.init(calibratedRed: red, green: green, blue: blue, alpha: data.opacity) var returnImage: NSImage? if data.watermarkType == .image { guard let image = data.image() else { return returnImage } if data.isTilePage { returnImage = NSImage.createTileImageWithImage(imageToDraw: image, imageSize: size, rotationAngle: data.rotation * -1, horizontalPosition: data.horizontalPosition, verticalPosition: data.verticalPosition, alpha: data.opacity, sizeRatio: data.scale, horizontalSpacing: data.tx, verticalSpacing: data.ty) } else { returnImage = NSImage.createImageWithImage(imageToDraw: image, imageSize: size, rotationAngle: data.rotation * -1, horizontalPosition: data.horizontalPosition, verticalPosition: data.verticalPosition, alpha: data.opacity, sizeRatio: data.isScale ? data.scale : -1, horizontalSpacing: data.tx, verticalSpacing: data.ty) } } else if text.count > 0 { if data.isTilePage { returnImage = NSImage.createImageWithTileText(text: text, fontSize: data.fontSize, textColor: color, imageSize: size, rotationAngle: data.rotation * -1, verticalSpacing: data.verticalSpacing, horizontalSpacing: data.horizontalSpacing) } else { returnImage = NSImage.createImageWithText(text: text, fontSize: data.fontSize, textColor: color, imageSize: size, rotationAngle: data.rotation * -1, horizontalPosition: data.horizontalPosition, verticalPosition: data.verticalPosition, horizontalSpacing: data.tx, verticalSpacing: data.ty) } } return returnImage } class func getFontSize() -> [String] { return ["6","8","10","12","14", "16","18","20","22","24", "26","28","30","32","34", "36","40","48","64","80", "96","112"] } func fetchAvailableName() -> String { var availableIndex: Int = 0 let watermark = "Watermark" for model in self.watermarks { let watermarkID = model.tag if (watermarkID.hasPrefix(watermark)) { let indexString: String = (watermarkID.components(separatedBy: watermark).last ?? "0") let index: Int = Int(indexString) ?? 0 if (index >= availableIndex) { availableIndex = index + 1 } } } return "\(watermark)\(availableIndex)" } //MARK: - Compare class func compareIsChangedModel(_ model: KMWatermarkModel, withDict dict: NSDictionary) -> Bool { if let value = dict["fontName"] { if model.fontName != (value as! String) { return true } } if let value = dict.object(forKey: KMWatermarkKey.text.rawValue) { if model.text != (value as! String) { return true } } if let value = dict.object(forKey: KMWatermarkKey.textFontName.rawValue) { if model.fontName != (value as! String) { return true } } if let value = dict.object(forKey: KMWatermarkKey.textfontStyle.rawValue) { if model.fontStyle != (value as! String) { return true } } if let value = dict.object(forKey: KMWatermarkKey.textFontSize.rawValue) { if model.fontSize != (value as! CGFloat) { return true } } if let value = dict.object(forKey: KMWatermarkKey.imagePath.rawValue) { if model.imagePath != (value as! String) { return true } } if let value = dict.object(forKey: KMWatermarkKey.isScale.rawValue) { if model.isScale != (value as! Bool) { return true } } if let value = dict.object(forKey: KMWatermarkKey.scale.rawValue) { if model.scale != (value as! CGFloat) { return true } } if let value = dict.object(forKey: KMWatermarkKey.rotate.rawValue) { if model.rotation != (value as! CGFloat) { return true } } if let value = dict.object(forKey: KMWatermarkKey.opacity.rawValue) { if model.opacity != (value as! CGFloat) { return true } } if let value = dict.object(forKey: KMWatermarkKey.verticalMode.rawValue) { if model.verticalPosition.rawValue != (value as! Int) { return true } } if let value = dict.object(forKey: KMWatermarkKey.verticalSpace.rawValue) { if model.ty != (value as! CGFloat) { return true } } if let value = dict.object(forKey: KMWatermarkKey.horizontalMode.rawValue) { if model.horizontalPosition.rawValue != (value as! Int) { return true } } if let value = dict.object(forKey: KMWatermarkKey.horizontalSpace.rawValue) { if model.tx != (value as! CGFloat) { return true } } if let value = dict.object(forKey: KMWatermarkKey.textColor.rawValue) { var modelColorText = model.textColor.colorToHexString() if modelColorText.count > 7 { modelColorText = modelColorText.substring(to: 7) } if var valueString = value as? String { if valueString.count > 7 { valueString = valueString.substring(to: 7) } if valueString != modelColorText { return true } } } if let value = dict.object(forKey: KMWatermarkKey.isFront.rawValue) { if model.isFront != (value as! Bool) { return true } } if let value = dict.object(forKey: KMWatermarkKey.isTile.rawValue) { if model.isTilePage != (value as! Bool) { return true } } if let value = dict.object(forKey: KMWatermarkKey.tileHorizontalSpace.rawValue) { if model.horizontalSpacing != (value as! CGFloat) { return true } } if let value = dict.object(forKey: KMWatermarkKey.tileVerticalSpace.rawValue) { if model.verticalSpacing != (value as! CGFloat) { return true } } return false } }