// // KMWatermarkManager.swift // PDF Reader Pro // // Created by tangchao on 2022/12/19. // import Cocoa enum KMWatermarkKey: String { case text = "WatermarTextKey" case textFontSize = "WatermarkOfTextFontSizeKey" case textFontName = "textFontName" case imagePath = "WatermarkOfImagePathKey" case rotate = "WatermarkOfRotationKey" case opacity = "WatermarkOfOpacityKey" case scale = "WatermarkOfScaleKey" case verticalMode = "WatermarkOfVerticalModeKey" case verticalSpace = "WatermarkOfVerticalSpaceKey" case horizontalMode = "WatermarkOfHorizontalModeKey" case horizontalSpace = "WatermarkOfHorizontalSpaceKey" case isFront = "WatermarkOfIsFrontKey" case red = "WatermarkOfRedKey" case green = "WatermarkOfGreenKey" case blue = "WatermarkOfBlueKey" case createDate = "WatermarkOfCreatTemplateDateKey" case pageRangeType = "WatermarkOfPageRangeTypeKey" case pageRangeString = "WatermarkOfPageStringKey" case tileVerticalSpace = "WatermarkTileVerticalSpaceKey" case tileHorizontalSpace = "WatermarkTileHorizontalSpaceKey" case isTile = "WatermarkOfIsTileKey" case lastAddData = "kAddLastWatermarkDataKey1" case id = "kWatermarkIDKey" } 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") static let defaultManager = KMWatermarkManager() var watermarks: Array = [] override init() { super.init() if (FileManager.default.fileExists(atPath: watermarkPlistPath!)) { let dataDict = NSDictionary(contentsOfFile: watermarkPlistPath!) var deleteKeys: Array = [] 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) /// 赋值tag model.tag = key let isFile: Bool = (watermarkDict.object(forKey: KMWatermarkKey.imagePath.rawValue) != nil) if (isFile) { if (model.image == nil) { deleteKeys.append(key) } else { self.watermarks.append(model) } } else { self.watermarks.append(model) } } /// 根据id进行排序(升序) self.watermarks.sort(){$0.watermarkID > $1.watermarkID} if (deleteKeys.count > 0) { var newDict: NSMutableDictionary = NSMutableDictionary(dictionary: dataDict!) for key in deleteKeys { newDict.removeObject(forKey: key) } newDict.write(toFile: watermarkPlistPath!, atomically: true) } } } func addWatermark(watermark: KMWatermarkModel) -> Bool { if (!FileManager.default.fileExists(atPath: watermarkFolderPath!)) { // let create = try?FileManager.default.createDirectory(atPath: watermarkFolderPath!, withIntermediateDirectories: false) let create: ()? = try?FileManager.default.createDirectory(atPath: watermarkFolderPath!, withIntermediateDirectories: true, attributes: nil) if (create == nil) { return false } } if (!FileManager.default.fileExists(atPath: watermarkPlistPath!)) { let create = try?FileManager.default.createFile(atPath: watermarkPlistPath!, contents: nil) if (create == nil) { return false } } let dict = NSDictionary(contentsOfFile: watermarkPlistPath!) var newDict:NSMutableDictionary! if (dict != nil) { newDict = NSMutableDictionary(dictionary: dict!) } else { newDict = NSMutableDictionary() } let watermarkDict = self.parseModel(model: watermark) if (watermarkDict.isEmpty) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("文件\(watermark.imagePath.lastPathComponent)已损坏", comment: "") alert.runModal() return false } let tag = tagString() newDict.addEntries(from: [tag : watermarkDict]) watermark.tag = tag 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) } } 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!)) { let create = try?FileManager.default.createFile(atPath: watermarkPlistPath!, contents: nil) if (create == nil) { return false } } 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.parseModel(model: watermark) if (watermarkDict.isEmpty) { let alert = NSAlert() alert.alertStyle = .critical alert.messageText = NSLocalizedString("文件\(watermark.imagePath.lastPathComponent)已损坏", comment: "") alert.runModal() return false } newDict.setObject(watermarkDict, forKey: flagModel.tag as NSCopying) let result = newDict.write(toFile: watermarkPlistPath!, atomically: true) if (result) { let index = self.watermarks.index(of: flagModel) self.watermarks[index!] = watermark } return result } func removeWatermark(watermark: KMWatermarkModel) -> Bool { if (watermark == nil) { return false } if (watermark.tag == nil) { return false } 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 (watermark.text == nil || watermark.text.isEmpty) { let filePath: String = watermark.imagePath try?FileManager.default.removeItem(atPath: filePath) } if (self.watermarks.contains(watermark)) { self.watermarks.removeObject(watermark) } } 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() } return result } func removeAllTextWatermarks() -> 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() } let count = self.watermarks.count-1 var deleteArray: Array = [] for i in 0 ... count { let model = self.watermarks[i] if (model.text != nil && !model.text.isEmpty) { newDictionary.removeObject(forKey: model.tag as Any) deleteArray.append(model) } } let result = newDictionary.write(toFile: watermarkPlistPath!, atomically: true) if (result) { for model in deleteArray { self.watermarks.removeObject(model) } } return result } func removeAllFileWatermarks() -> 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() } let count = self.watermarks.count-1 var deleteArray: Array = [] for i in 0 ... count { let model = self.watermarks[i] if (model.image != nil) { newDictionary.removeObject(forKey: model.tag as Any) deleteArray.append(model) } } let result = newDictionary.write(toFile: watermarkPlistPath!, atomically: true) if (result) { for model in deleteArray { self.watermarks.removeObject(model) } } return result } private func parseModel(model: KMWatermarkModel) -> Dictionary { let tag = tagString() let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yy-MM-dd HH:mm:ss" let timeString = dateFormatter.string(from: Date()) model.creatTemplateDate = timeString var dict: [String : Any] = [:] if (!model.text.isEmpty) { dict[KMWatermarkKey.text.rawValue] = model.text dict[KMWatermarkKey.textFontSize.rawValue] = model.getTextFontSize() dict[KMWatermarkKey.textFontName.rawValue] = model.getTextFontName() } else { if (!FileManager.default.fileExists(atPath: watermarkFolderPath!)) { try?FileManager.default.createDirectory(atPath: watermarkFolderPath!, withIntermediateDirectories: false) } let path = watermarkFolderPath?.stringByAppendingPathComponent("\(tag).png") let image = model.image let data = image?.tiffRepresentation let imageRep = NSBitmapImageRep(data: data!) imageRep?.size = image!.size var imageData: Data! let pathExtension = model.imagePath.components(separatedBy: ".").last if (pathExtension?.lowercased() == "png") { imageData = imageRep?.representation(using: NSBitmapImageRep.FileType.png, properties: [:]) } else { imageData = imageRep?.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [:]) } do { try imageData.write(to: URL(fileURLWithPath: path!)) dict[KMWatermarkKey.imagePath.rawValue] = path?.lastPathComponent } catch { KMPrint("Failed to write to disk.") return [:] } } var red: CGFloat = 0.0 var green: CGFloat = 0.0 var blue: CGFloat = 0.0 model.getTextColor().usingColorSpaceName(NSColorSpaceName.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: nil) dict[KMWatermarkKey.isFront.rawValue] = model.isFront dict[KMWatermarkKey.scale.rawValue] = model.scale dict[KMWatermarkKey.opacity.rawValue] = model.opacity dict[KMWatermarkKey.rotate.rawValue] = model.rotation dict[KMWatermarkKey.verticalMode.rawValue] = model.verticalMode dict[KMWatermarkKey.verticalSpace.rawValue] = model.verticalSpace dict[KMWatermarkKey.horizontalMode.rawValue] = model.horizontalMode dict[KMWatermarkKey.horizontalSpace.rawValue] = model.horizontalSpace dict[KMWatermarkKey.red.rawValue] = red dict[KMWatermarkKey.green.rawValue] = green dict[KMWatermarkKey.blue.rawValue] = blue dict[KMWatermarkKey.isTile.rawValue] = model.isTilePage dict[KMWatermarkKey.tileVerticalSpace.rawValue] = model.tileVerticalSpace dict[KMWatermarkKey.tileHorizontalSpace.rawValue] = model.tileHorizontalSpace dict[KMWatermarkKey.pageRangeType.rawValue] = model.pageRangeType.rawValue dict[KMWatermarkKey.pageRangeString.rawValue] = model.pagesString dict[KMWatermarkKey.createDate.rawValue] = model.creatTemplateDate dict[KMWatermarkKey.id.rawValue] = model.watermarkID return dict } private func parseDictionary(dict: NSDictionary) -> KMWatermarkModel { let model = KMWatermarkModel() let isText: Bool = (dict.object(forKey: KMWatermarkKey.text.rawValue) != nil) let isFile: Bool = (dict.object(forKey: KMWatermarkKey.imagePath.rawValue) != nil) if (isFile) { let path = watermarkFolderPath?.stringByAppendingPathComponent(dict.object(forKey: KMWatermarkKey.imagePath.rawValue) as! String) if (FileManager.default.fileExists(atPath: path!)) { model.image = NSImage(contentsOfFile: path!) model.imagePath = path ?? "" } else { model.image = nil } } else if (isText) { model.text = (dict.object(forKey: KMWatermarkKey.text.rawValue) as! String) let fontSize: CGFloat = dict.object(forKey: KMWatermarkKey.textFontSize.rawValue) as! CGFloat // let fontName: String = dict.object(forKey: KMWatermarkKey.textFontName.rawValue) as! String model.textFont = .font(name: "Helvetica", size: fontSize) } 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.verticalMode = (dict.object(forKey: KMWatermarkKey.verticalMode.rawValue) as? Int) ?? 0 model.verticalSpace = dict.object(forKey: KMWatermarkKey.verticalSpace.rawValue) as? CGFloat ?? 0 model.horizontalMode = (dict.object(forKey: KMWatermarkKey.horizontalMode.rawValue) as? Int) ?? 0 model.horizontalSpace = dict.object(forKey: KMWatermarkKey.horizontalSpace.rawValue) as? CGFloat ?? 0 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 = .color(red: red, green: green, blue: blue, alpha: 1.0) model.isFront = (dict.object(forKey: KMWatermarkKey.isFront.rawValue) as? Bool) ?? false model.pageRangeType = KMWatermarkeModelPageRangeType.init(rawValue: (dict.object(forKey: KMWatermarkKey.pageRangeType.rawValue) as? Int) ?? 0)! model.pagesString = (dict.object(forKey: KMWatermarkKey.pageRangeString.rawValue) as? String ?? "") model.isTilePage = (dict.object(forKey: KMWatermarkKey.isTile.rawValue) as? Bool) ?? false model.tileHorizontalSpace = (dict.object(forKey: KMWatermarkKey.tileHorizontalSpace.rawValue) as? CGFloat) ?? 0 model.tileVerticalSpace = (dict.object(forKey: KMWatermarkKey.tileVerticalSpace.rawValue) as? CGFloat) ?? 0 model.watermarkID = (dict.object(forKey: KMWatermarkKey.id.rawValue) as? String) ?? "" model.creatTemplateDate = (dict.object(forKey: KMWatermarkKey.createDate.rawValue) as? String) ?? "" return model } func fetchAvailableName() -> String { var availableIndex: Int = 0 let watermark = "Watermark" for model in self.watermarks { let watermarkID = model.watermarkID 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)" } /** Private Methods */ private func tagString() -> String { var result: String = "" let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyMMddHHmmss" result.append(dateFormatter.string(from: Date())) result = result.appendingFormat("%04d", arc4random()%10000) return result } }