import Foundation let kHeaderFooterFolderPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!).stringByAppendingPathComponent("headerFooter") let kHeaderFooterPlistPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!).stringByAppendingPathComponent("headerFooter").stringByAppendingPathComponent("headerFooter2025.plist") class KMHeaderFooterManager: NSObject { static let defaultManager = KMHeaderFooterManager() var headFooterObjects: [KMHeaderFooterModel] = [] var defaultHeaderFooter: KMHeaderFooterModel = KMHeaderFooterModel() override init() { super.init() #if DEBUG print("kHeaderFooterPlistPath = \(kHeaderFooterPlistPath ?? "")") #endif if (FileManager.default.fileExists(atPath: kHeaderFooterPlistPath!)) { let dataDict = NSDictionary(contentsOfFile: kHeaderFooterPlistPath!) if (dataDict == nil) { return } for keyIndex in 0 ..< (dataDict?.allKeys.count)! { let key: String = dataDict?.allKeys[keyIndex] as! String let backgroundDict: NSDictionary = dataDict?.object(forKey: key) as! NSDictionary let model = parseDictionary(dict: backgroundDict) model.tag = key self.headFooterObjects.append(model) self.defaultHeaderFooter.name = self.fetchHeaderFooterAvailableName() } } } //MARK: - 增删改查 func addHeaderFooter(_ obj: KMHeaderFooterModel) -> Bool { if (!FileManager.default.fileExists(atPath: kHeaderFooterFolderPath!)) { let create: ()? = try?FileManager.default.createDirectory(atPath: kHeaderFooterFolderPath!, withIntermediateDirectories: false) if (create == nil) { return false } } if (!FileManager.default.fileExists(atPath: kHeaderFooterPlistPath!)) { let create = try?FileManager.default.createFile(atPath: kHeaderFooterPlistPath!, contents: nil) if (create == nil) { return false } } let dict = NSDictionary(contentsOfFile: kHeaderFooterPlistPath!) var newDict:NSMutableDictionary! if (dict != nil) { newDict = NSMutableDictionary(dictionary: dict!) } else { newDict = NSMutableDictionary() } let backgroundDict = self.parseModel(model: obj) if (backgroundDict.isEmpty) { let alert = NSAlert() alert.alertStyle = .critical // alert.messageText = NSLocalizedString("文件\(obj.imagePath?.lastPathComponent)已损坏", comment: "") alert.runModal() return false } let tag = obj.tag newDict.addEntries(from: [tag : backgroundDict]) let result = newDict.write(toFile: kHeaderFooterPlistPath!, atomically: true) if (result) { if (self.headFooterObjects.count < 1) { self.headFooterObjects.append(obj) } else { self.headFooterObjects.insert(obj, at: 0) } } return result } func removeHeaderFooter(_ obj: KMHeaderFooterModel) -> Bool { if (obj.tag.isEmpty) { return false } if (!FileManager.default.fileExists(atPath: kHeaderFooterPlistPath!)) { return false } let key: String = obj.tag let dictionary = NSDictionary(contentsOfFile: kHeaderFooterPlistPath!) var newDictionary: NSMutableDictionary! if (dictionary != nil) { newDictionary = NSMutableDictionary(dictionary: dictionary!) } else { newDictionary = NSMutableDictionary() } newDictionary.removeObject(forKey: key) let result = newDictionary.write(toFile: kHeaderFooterPlistPath!, atomically: true) if (result) { if (self.headFooterObjects.contains(obj)) { self.headFooterObjects.removeObject(obj) } } return result } func updateHeaderFooter(theModel: KMHeaderFooterModel) -> Bool { var flagModel: KMHeaderFooterModel! for model in self.headFooterObjects { if (model.tag == theModel.tag) { flagModel = model break } } if (flagModel == nil) { return false } let dict = NSDictionary(contentsOfFile: kHeaderFooterPlistPath!) var newDict:NSMutableDictionary! if (dict != nil) { newDict = NSMutableDictionary(dictionary: dict!) } else { newDict = NSMutableDictionary() } let watermarkDict = self.parseModel(model: theModel) newDict.setObject(watermarkDict, forKey: flagModel.tag as NSCopying) let result = newDict.write(toFile: kHeaderFooterPlistPath!, atomically: true) if (result) { if let index = self.headFooterObjects.firstIndex(of: flagModel) { self.headFooterObjects[index] = theModel } } return result } func updateModel(_ model: KMHeaderFooterModel, with dict: NSDictionary) { model.fontName = dict.object(forKey: "fontName") as! String model.fontsize = dict.object(forKey: "fontsize") as! CGFloat if let value = dict.object(forKey: "color") { model.color = NSColor.km_init(hex: value as! String) } model.leftMargin = dict.object(forKey: "leftMargin") as! Int model.rightMargin = dict.object(forKey: "rightMargin") as! Int model.bottomMargin = dict.object(forKey: "bottomMargin") as! Int model.topMargin = dict.object(forKey: "topMargin") as! Int model.topLeftString = dict.object(forKey: "topLeftString") as! String model.topCenterString = dict.object(forKey: "topCenterString") as! String model.topRightString = dict.object(forKey: "topRightString") as! String model.bottomLeftString = dict.object(forKey: "bottomLeftString") as! String model.bottomCenterString = dict.object(forKey: "bottomCenterString") as! String model.bottomRightString = dict.object(forKey: "bottomRightString") as! String model.dateFormatString = dict.object(forKey: "dateFormatString") as! String model.pageFormatString = dict.object(forKey: "pageFormatString") as! String model.startString = dict.object(forKey: "startString") as! String model.name = dict.object(forKey: "name") as! String if let value = dict.object(forKey: "tag") { model.tag = value as! String } } func updateCPDFHeaderFooter(_ headerFooter: CPDFHeaderFooter, withModel model: KMHeaderFooterModel, _ totalPDFCount: Int) { let fontSize = model.fontsize let fontName: String = model.fontName let font = NSFont.boldSystemFont(ofSize:fontSize) let style = NSMutableParagraphStyle() style.alignment = .center style.lineBreakMode = .byCharWrapping let size: NSSize = "text".boundingRect(with: NSSize(width: 1000, height: 1000), options: NSString.DrawingOptions(rawValue: 3), attributes: [NSAttributedString.Key.font : font, NSAttributedString.Key.paragraphStyle : style]).size headerFooter.margin = NSEdgeInsetsMake(max(CGFloat(model.topMargin)-size.height, 0), CGFloat(model.leftMargin), max(CGFloat(model.bottomMargin)-size.height, 0), CGFloat(model.rightMargin)) let strings = KMHeaderFooterModel.parseModel(model: model, pageCount: totalPDFCount) var count: Int = 0 let color = model.color for text in strings { headerFooter.setText(text, at: UInt(count)) headerFooter.setTextColor(color, at: UInt(count)) headerFooter.setFontSize(fontSize, at: UInt(count)) headerFooter.setFontName(fontName, at: UInt(count)) count += 1 } } //MARK: - Parse func parseModel(model: KMHeaderFooterModel) -> Dictionary { var dict: [String : Any] = [:] dict["fontName"] = model.fontName dict["fontsize"] = model.fontsize dict["color"] = model.color.toHex() dict["leftMargin"] = model.leftMargin dict["rightMargin"] = model.rightMargin dict["bottomMargin"] = model.bottomMargin dict["topMargin"] = model.topMargin dict["topLeftString"] = model.topLeftString dict["topCenterString"] = model.topCenterString dict["topRightString"] = model.topRightString dict["bottomLeftString"] = model.bottomLeftString dict["bottomCenterString"] = model.bottomCenterString dict["bottomRightString"] = model.bottomRightString dict["dateFormatString"] = model.dateFormatString dict["pageFormatString"] = model.pageFormatString dict["startString"] = model.startString dict["name"] = model.name dict["tag"] = model.tag return dict } private func parseDictionary(dict: NSDictionary) -> KMHeaderFooterModel { let model = KMHeaderFooterModel() model.fontName = dict.object(forKey: "fontName") as! String model.fontsize = dict.object(forKey: "fontsize") as! CGFloat if let value = dict.object(forKey: "color") { model.color = NSColor.km_init(hex: value as! String) } model.leftMargin = dict.object(forKey: "leftMargin") as! Int model.rightMargin = dict.object(forKey: "rightMargin") as! Int model.bottomMargin = dict.object(forKey: "bottomMargin") as! Int model.topMargin = dict.object(forKey: "topMargin") as! Int model.topLeftString = dict.object(forKey: "topLeftString") as! String model.topCenterString = dict.object(forKey: "topCenterString") as! String model.topRightString = dict.object(forKey: "topRightString") as! String model.bottomLeftString = dict.object(forKey: "bottomLeftString") as! String model.bottomCenterString = dict.object(forKey: "bottomCenterString") as! String model.bottomRightString = dict.object(forKey: "bottomRightString") as! String model.dateFormatString = dict.object(forKey: "dateFormatString") as! String model.pageFormatString = dict.object(forKey: "pageFormatString") as! String model.startString = dict.object(forKey: "startString") as! String model.name = dict.object(forKey: "name") as! String model.tag = dict.object(forKey: "tag") as! String return model } //MARK: - Get func fetchHeaderFooterAvailableName() -> String { var availableIndex = 0 for item in headFooterObjects { if item.name.hasPrefix("HeaderFooter") { if let index = Int(item.name.dropFirst("HeaderFooter".count)), index >= availableIndex { availableIndex = index + 1 } } } return "HeaderFooter\(availableIndex)" } //MARK: - Compare class func compareIsChangedModel(_ model: KMHeaderFooterModel, withDict dict: NSDictionary) -> Bool { if let value = dict["fontName"] { if model.fontName != (value as! String) { return true } } if let value = dict["fontsize"] { if model.fontsize != (value as! CGFloat) { return true } } if let value = dict["color"] { if model.color.toHex() != (value as! String) { return true } } if let value = dict["leftMargin"] { if model.leftMargin != (value as! Int) { return true } } if let value = dict["rightMargin"] { if model.rightMargin != (value as! Int) { return true } } if let value = dict["bottomMargin"] { if model.bottomMargin != (value as! Int) { return true } } if let value = dict["topMargin"] { if model.topMargin != (value as! Int) { return true } } if let value = dict["topLeftString"] { if model.topLeftString != (value as! String) { return true } } if let value = dict["topCenterString"] { if model.topCenterString != (value as! String) { return true } } if let value = dict["topRightString"] { if model.topRightString != (value as! String) { return true } } if let value = dict["bottomLeftString"] { if model.bottomLeftString != (value as! String) { return true } } if let value = dict["bottomCenterString"] { if model.bottomCenterString != (value as! String) { return true } } if let value = dict["bottomRightString"] { if model.bottomRightString != (value as! String) { return true } } if let value = dict["dateFormatString"] { if model.dateFormatString != (value as! String) { return true } } if let value = dict["pageFormatString"] { if model.pageFormatString != (value as! String) { return true } } if let value = dict["startString"] { if model.startString != (value as! String) { return true } } return false } } //MARK: - Class Method extension KMHeaderFooterManager { class func getdateFormatArray() -> [String] { return [ "m/d", "m/d/yy", "m/d/yyyy", "mm/dd/yy", "mm/dd/yyyy", "d/m/yy", "d/m/yyyy", "dd/mm/yy", "dd/mm/yyyy", "mm/yy", "mm/yyyy", "m.d.yy", "m.d.yyyy", "mm.dd.yy", "mm.dd.yyyy", "mm.yy", "mm.yyyy", "d.m.yy", "d.m.yyyy", "dd.mm.yy", "dd.mm.yyyy", "yy-mm-dd", "yyyy-mm-dd" ] } class func getPageFormats() -> [String] { return ["1", "1 of n", "1/n", "Page 1", "Page 1 of n"] } 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"] } }