KMBackgroundManager.swift 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. //
  2. // KMBackgroundManager.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by tangchao on 2022/12/23.
  6. //
  7. import Cocoa
  8. class KMBackgroundManager: NSObject, NSCoding {
  9. let kBackgroundFolderPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!).stringByAppendingPathComponent("background")
  10. let kBackgroundPlistPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last?.stringByAppendingPathComponent(Bundle.main.bundleIdentifier!).stringByAppendingPathComponent("background").stringByAppendingPathComponent("background.plist")
  11. var datas: Array<KMBackgroundModel> = []
  12. var backgroundObjects: [KMBackgroundObject] = []
  13. static let defaultManager = KMBackgroundManager()
  14. override init() {
  15. super.init()
  16. if let storedData = UserDefaults.standard.value(forKey: "kBackgroundInfoSaveKey") as? Data {
  17. NSKeyedUnarchiver.setClass(KMBackgroundObject.self, forClassName: "KMBackgroundObject")
  18. NSKeyedUnarchiver.setClass(KMBackgroundManager.self, forClassName: "KMBackgroundManager")
  19. if let man = NSKeyedUnarchiver.unarchiveObject(with: storedData) as? KMBackgroundManager {
  20. for object in man.backgroundObjects {
  21. let model = self.parseObject(object: object)
  22. self.datas.append(model)
  23. self.backgroundObjects.append(object)
  24. }
  25. }
  26. }
  27. // if (FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  28. // let dataDict = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  29. // if (dataDict == nil) {
  30. // return
  31. // }
  32. // var deleteKeys: Array<String> = []
  33. // for keyIndex in 0 ..< (dataDict?.allKeys.count)! {
  34. // let key: String = dataDict?.allKeys[keyIndex] as! String
  35. // let backgroundDict: NSDictionary = dataDict?.object(forKey: key) as! NSDictionary
  36. //
  37. // let model = parseDictionary(dict: backgroundDict)
  38. // /// 赋值id
  39. // model.backgroundID = key
  40. // if (model.type == .file) {
  41. // if (model.image == nil) {
  42. // deleteKeys.append(key)
  43. // } else {
  44. // self.datas.append(model)
  45. // }
  46. // } else {
  47. // self.datas.append(model)
  48. // }
  49. // }
  50. //
  51. // if (deleteKeys.count > 0) {
  52. // let newDict: NSMutableDictionary = NSMutableDictionary(dictionary: dataDict!)
  53. // for key in deleteKeys {
  54. // newDict.removeObject(forKey: key)
  55. // }
  56. // newDict.write(toFile: kBackgroundPlistPath!, atomically: true)
  57. // }
  58. // }
  59. }
  60. required init?(coder: NSCoder) {
  61. if let data = coder.decodeObject(forKey: "backgroundObjects") {
  62. self.backgroundObjects = data as? [KMBackgroundObject] ?? []
  63. }
  64. }
  65. func encode(with coder: NSCoder) {
  66. coder.encode(self.backgroundObjects, forKey: "backgroundObjects")
  67. }
  68. func addTemplate(model: KMBackgroundModel) -> Bool {
  69. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  70. let create: ()? = try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  71. if (create == nil) {
  72. return false
  73. }
  74. }
  75. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  76. let create = try?FileManager.default.createFile(atPath: kBackgroundPlistPath!, contents: nil)
  77. if (create == nil) {
  78. return false
  79. }
  80. }
  81. let dict = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  82. var newDict:NSMutableDictionary!
  83. if (dict != nil) {
  84. newDict = NSMutableDictionary(dictionary: dict!)
  85. } else {
  86. newDict = NSMutableDictionary()
  87. }
  88. let backgroundDict = self.parseModel(model: model)
  89. if (backgroundDict.isEmpty) {
  90. let alert = NSAlert()
  91. alert.alertStyle = .critical
  92. alert.messageText = NSLocalizedString("文件\(model.imagePath.lastPathComponent)已损坏", comment: "")
  93. alert.runModal()
  94. return false
  95. }
  96. let tag = fetchAvailableName()//tagString()
  97. newDict.addEntries(from: [tag : backgroundDict])
  98. model.backgroundID = tag
  99. let result = newDict.write(toFile: kBackgroundPlistPath!, atomically: true)
  100. if (result) {
  101. if (self.datas.count < 1) {
  102. self.datas.append(model)
  103. } else {
  104. self.datas.insert(model, at: 0)
  105. }
  106. }
  107. let obj = self.parseModeForObject(model)
  108. self._addBackground(obj)
  109. return result
  110. }
  111. func deleteTemplate(model: KMBackgroundModel) -> Bool {
  112. if (model.backgroundID.isEmpty) {
  113. return false
  114. }
  115. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  116. return false
  117. }
  118. let key: String = model.backgroundID
  119. let dictionary = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  120. var newDictionary: NSMutableDictionary!
  121. if (dictionary != nil) {
  122. newDictionary = NSMutableDictionary(dictionary: dictionary!)
  123. } else {
  124. newDictionary = NSMutableDictionary()
  125. }
  126. newDictionary.removeObject(forKey: key)
  127. let result = newDictionary.write(toFile: kBackgroundPlistPath!, atomically: true)
  128. if (result) {
  129. if (model.type == .file) {
  130. let filePath: String = model.imagePath
  131. try?FileManager.default.removeItem(atPath: filePath)
  132. }
  133. if (self.datas.contains(model)) {
  134. self.datas.removeObject(model)
  135. }
  136. }
  137. let obj = self.parseModeForObject(model)
  138. self._removeBackground(obj)
  139. return result
  140. }
  141. func deleteAllTemplates() -> Bool {
  142. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  143. return false
  144. }
  145. let dictionary = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  146. var newDictionary: NSMutableDictionary!
  147. if (dictionary != nil) {
  148. newDictionary = NSMutableDictionary(dictionary: dictionary!)
  149. } else {
  150. newDictionary = NSMutableDictionary()
  151. }
  152. newDictionary.removeAllObjects()
  153. let result = newDictionary.write(toFile: kBackgroundPlistPath!, atomically: true)
  154. if (result) {
  155. self.datas.removeAll()
  156. }
  157. self._clearStored()
  158. return result
  159. }
  160. func deleteAllColorTemplates() -> Bool {
  161. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  162. return false
  163. }
  164. let dictionary = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  165. var newDictionary: NSMutableDictionary!
  166. if (dictionary != nil) {
  167. newDictionary = NSMutableDictionary(dictionary: dictionary!)
  168. } else {
  169. newDictionary = NSMutableDictionary()
  170. }
  171. let count = self.datas.count-1
  172. var deleteArray: Array<KMBackgroundModel> = []
  173. for i in 0 ... count {
  174. let model = self.datas[i]
  175. if (model.type == .color) {
  176. newDictionary.removeObject(forKey: model.backgroundID as Any)
  177. deleteArray.append(model)
  178. }
  179. }
  180. let result = newDictionary.write(toFile: kBackgroundPlistPath!, atomically: true)
  181. if (result) {
  182. for model in deleteArray {
  183. self.datas.removeObject(model)
  184. }
  185. }
  186. self._clearStored()
  187. return result
  188. }
  189. func deleteAllFileTemplates() -> Bool {
  190. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  191. return false
  192. }
  193. let dictionary = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  194. var newDictionary: NSMutableDictionary!
  195. if (dictionary != nil) {
  196. newDictionary = NSMutableDictionary(dictionary: dictionary!)
  197. } else {
  198. newDictionary = NSMutableDictionary()
  199. }
  200. let count = self.datas.count-1
  201. var deleteArray: Array<KMBackgroundModel> = []
  202. for i in 0 ... count {
  203. let model = self.datas[i]
  204. if (model.type == .file) {
  205. newDictionary.removeObject(forKey: model.backgroundID as Any)
  206. deleteArray.append(model)
  207. }
  208. }
  209. let result = newDictionary.write(toFile: kBackgroundPlistPath!, atomically: true)
  210. if (result) {
  211. for model in deleteArray {
  212. self.datas.removeObject(model)
  213. }
  214. }
  215. self._clearStored()
  216. return result
  217. }
  218. func updateTemplate(model: KMBackgroundModel) -> Bool {
  219. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  220. let create = try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  221. if (create == nil) {
  222. return false
  223. }
  224. }
  225. if (!FileManager.default.fileExists(atPath: kBackgroundPlistPath!)) {
  226. let create = try?FileManager.default.createFile(atPath: kBackgroundPlistPath!, contents: nil)
  227. if (create == nil) {
  228. return false
  229. }
  230. }
  231. var flagModel: KMBackgroundModel!
  232. for model_ in self.datas {
  233. if (model_.backgroundID == model.backgroundID) {
  234. flagModel = model_
  235. break
  236. }
  237. }
  238. if (flagModel == nil) {
  239. return false
  240. }
  241. let dict = NSDictionary(contentsOfFile: kBackgroundPlistPath!)
  242. var newDict:NSMutableDictionary!
  243. if (dict != nil) {
  244. newDict = NSMutableDictionary(dictionary: dict!)
  245. } else {
  246. newDict = NSMutableDictionary()
  247. }
  248. let modelDict = self.parseModel(model: model)
  249. if (modelDict.isEmpty) {
  250. let alert = NSAlert()
  251. alert.alertStyle = .critical
  252. alert.messageText = NSLocalizedString("文件\(model.imagePath.lastPathComponent)已损坏", comment: "")
  253. alert.runModal()
  254. return false
  255. }
  256. newDict.setObject(modelDict, forKey: flagModel.backgroundID as NSCopying)
  257. let result = newDict.write(toFile: kBackgroundPlistPath!, atomically: true)
  258. if (result) {
  259. let index = self.datas.index(of: flagModel)
  260. self.datas[index!] = model
  261. }
  262. return result
  263. }
  264. /**
  265. `Private Methods`
  266. */
  267. private func parseModel(model: KMBackgroundModel) -> Dictionary<String, Any> {
  268. let tag = tagString()
  269. var dict: [String : Any] = [:]
  270. if (model.type == .color) {
  271. var red: CGFloat = 0.0
  272. var green: CGFloat = 0.0
  273. var blue: CGFloat = 0.0
  274. model.color!.usingColorSpaceName(NSColorSpaceName.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: nil)
  275. dict["red"] = red
  276. dict["green"] = green
  277. dict["blue"] = blue
  278. } else {
  279. if (!FileManager.default.fileExists(atPath: kBackgroundFolderPath!)) {
  280. try?FileManager.default.createDirectory(atPath: kBackgroundFolderPath!, withIntermediateDirectories: false)
  281. }
  282. let path = kBackgroundFolderPath?.stringByAppendingPathComponent("\(tag).png")
  283. let image = model.image
  284. let data = image?.tiffRepresentation
  285. let imageRep = NSBitmapImageRep(data: data!)
  286. imageRep?.size = image!.size
  287. var imageData: Data!
  288. let pathExtension = model.imagePath.components(separatedBy: ".").last
  289. if (pathExtension?.lowercased() == "png") {
  290. imageData = imageRep?.representation(using: NSBitmapImageRep.FileType.png, properties: [:])
  291. } else {
  292. imageData = imageRep?.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [:])
  293. }
  294. do {
  295. try imageData.write(to: URL(fileURLWithPath: path!))
  296. dict["imagePath"] = path?.lastPathComponent
  297. }
  298. catch {
  299. KMPrint("Failed to write to disk.")
  300. return [:]
  301. }
  302. }
  303. dict["type"] = model.type.rawValue
  304. dict["scale"] = model.scale
  305. dict["opacity"] = model.opacity
  306. dict["rotation"] = model.rotation
  307. dict["horizontalMode"] = model.horizontalMode
  308. dict["horizontalSpace"] = model.horizontalSpace
  309. dict["verticalMode"] = model.verticalMode
  310. dict["verticalSpace"] = model.verticalSpace
  311. dict["pageRangeType"] = model.pageRangeType.rawValue
  312. dict["pagesString"] = model.pagesString
  313. return dict
  314. }
  315. private func parseDictionary(dict: NSDictionary) -> KMBackgroundModel {
  316. let model = KMBackgroundModel()
  317. model.type = KMBackgroundType(rawValue: dict.object(forKey: "type") as! Int)!
  318. if (model.type == .file) {
  319. let path = kBackgroundFolderPath?.stringByAppendingPathComponent(dict.object(forKey: "imagePath") as! String)
  320. if (FileManager.default.fileExists(atPath: path!)) {
  321. model.image = NSImage(contentsOfFile: path!)
  322. model.imagePath = path!
  323. } else {
  324. model.image = nil
  325. }
  326. } else {
  327. let red: CGFloat = dict.object(forKey: "red") as! CGFloat
  328. let green: CGFloat = dict.object(forKey: "green") as! CGFloat
  329. let blue: CGFloat = dict.object(forKey: "blue") as! CGFloat
  330. model.color = NSColor(red: red, green: green, blue: blue, alpha: 1.0)
  331. }
  332. model.scale = dict.object(forKey: "scale") as! CGFloat
  333. model.rotation = CGFloat(Int(dict.object(forKey: "rotation") as! CGFloat))
  334. model.opacity = (dict.object(forKey: "opacity") as! CGFloat)
  335. model.verticalMode = (dict.object(forKey: "verticalMode") as! Int)
  336. model.verticalSpace = (dict.object(forKey: "verticalSpace") as! CGFloat)
  337. model.horizontalMode = (dict.object(forKey: "horizontalMode") as! Int)
  338. model.horizontalSpace = (dict.object(forKey: "horizontalSpace") as! CGFloat)
  339. model.pageRangeType = KMWatermarkeModelPageRangeType.init(rawValue: (dict.object(forKey: "pageRangeType") as! Int))!
  340. model.pagesString = (dict.object(forKey: "pagesString") as! String)
  341. return model
  342. }
  343. private func parseObject(object: KMBackgroundObject) -> KMBackgroundModel {
  344. let model = KMBackgroundModel()
  345. model.type = object.type
  346. if (model.type == .file) {
  347. model.image = object.image
  348. model.imagePath = object.imagePath ?? ""
  349. } else {
  350. model.color = object.color
  351. }
  352. model.scale = object.scale
  353. model.rotation = object.rotation.cgFloat
  354. model.opacity = object.opacity
  355. model.verticalMode = object.verticalMode
  356. model.verticalSpace = object.verticalSpace.cgFloat
  357. model.horizontalMode = object.horizontalMode
  358. model.horizontalSpace = object.horizontalSpace.cgFloat
  359. model.pageRangeType = KMWatermarkeModelPageRangeType.init(rawValue: object.pageRangeType.rawValue) ?? .all
  360. model.pagesString = object.pagesString
  361. model.backgroundID = object.backgroundID ?? "background0"
  362. return model
  363. }
  364. private func parseModeForObject(_ mode: KMBackgroundModel) -> KMBackgroundObject {
  365. let obj = KMBackgroundObject()
  366. obj.type = mode.type
  367. if (obj.type == .file) {
  368. obj.image = mode.image
  369. obj.imagePath = mode.imagePath
  370. } else {
  371. obj.color = mode.color ?? .red
  372. }
  373. obj.scale = mode.scale
  374. obj.rotation = Int(mode.rotation)
  375. obj.opacity = mode.opacity
  376. obj.verticalMode = mode.verticalMode
  377. obj.verticalSpace = Int(mode.verticalSpace)
  378. obj.horizontalMode = mode.horizontalMode
  379. obj.horizontalSpace = Int(mode.horizontalSpace)
  380. obj.pageRangeType = KMBatchOperatePageChoice.init(rawValue: mode.pageRangeType.rawValue) ?? .All
  381. obj.pagesString = mode.pagesString
  382. obj.backgroundID = mode.backgroundID
  383. return obj
  384. }
  385. private func _addBackground(_ obj: KMBackgroundObject) {
  386. self.backgroundObjects.insert(obj, at: 0)
  387. self._store()
  388. }
  389. private func _removeBackground(_ obj: KMBackgroundObject) {
  390. self.backgroundObjects.removeObject(obj)
  391. self._store()
  392. }
  393. private func _store() {
  394. let encodedObject = NSKeyedArchiver.archivedData(withRootObject: self)
  395. let defaults = UserDefaults.standard
  396. defaults.set(encodedObject, forKey: "kBackgroundInfoSaveKey")
  397. defaults.synchronize()
  398. }
  399. private func _clearStored() {
  400. let defaults = UserDefaults.standard
  401. defaults.set(nil, forKey: "kBackgroundInfoSaveKey")
  402. defaults.synchronize()
  403. }
  404. private func tagString() -> String {
  405. var result: String = ""
  406. let dateFormatter = DateFormatter()
  407. dateFormatter.dateFormat = "yyMMddHHmmss"
  408. result.append(dateFormatter.string(from: Date()))
  409. result = result.appendingFormat("%04d", arc4random()%10000)
  410. return result
  411. }
  412. func fetchAvailableName() -> String {
  413. var availableIndex = 0
  414. for item in datas {
  415. if item.backgroundID.hasPrefix("Background") {
  416. if let index = Int(item.backgroundID.dropFirst("Background".count)), index >= availableIndex {
  417. availableIndex = index + 1
  418. }
  419. }
  420. }
  421. return "Background\(availableIndex)"
  422. }
  423. }