ImageProcess.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. //
  2. // ImageProcess.swift
  3. // KdanAuto
  4. //
  5. // Created by 朱东勇 on 2023/2/7.
  6. //
  7. import Foundation
  8. import AppKit
  9. class ImageProcess : NSObject {
  10. // Image compare
  11. class func compareJPEG(_ resultPath:String, checkPath:String, processCover:Bool) -> Double {
  12. autoreleasepool {
  13. if !FileManager.default.fileExists(atPath: resultPath) || !FileManager.default.fileExists(atPath: checkPath) {
  14. return -1
  15. }
  16. let rImage = NSImage.init(contentsOfFile: resultPath) ?? nil
  17. let cImage = NSImage.init(contentsOfFile: checkPath) ?? nil
  18. if nil == rImage || nil == cImage {
  19. return -1
  20. }
  21. let resultImage = rImage!
  22. let checkImage = cImage!
  23. let resultImageRep = NSBitmapImageRep.init(cgImage: resultImage.cgImage(forProposedRect: nil, context: nil, hints: nil)!)
  24. let checkImageRep = NSBitmapImageRep.init(cgImage: checkImage.cgImage(forProposedRect: nil, context: nil, hints: nil)!)
  25. let rWidth = resultImageRep.pixelsWide
  26. let rHeight = resultImageRep.pixelsHigh
  27. // let rBitPerPixel = resultImageRep.bitsPerPixel / 8
  28. // let rBytePerRow = resultImageRep.bytesPerRow
  29. let cWidth = checkImageRep.pixelsWide
  30. let cHeight = checkImageRep.pixelsHigh
  31. // let cBitPerPixel = checkImageRep.bitsPerPixel / 8
  32. // let cBytePerRow = checkImageRep.bytesPerRow
  33. let maxWidth = min(rWidth, cWidth) - 1
  34. let maxHeight = min(rHeight, cHeight) - 1
  35. // check background color
  36. // 挑选图片 对角斜线 上的相素进行识别
  37. let markInfo = NSMutableDictionary.init()
  38. for w in 0...maxWidth {
  39. let x = Int(w)
  40. for mark in 0...1 {
  41. let color = checkImageRep.colorAt(x: min(x, cWidth-1), y: min(mark == 0 ? x : (maxWidth - x), (cHeight-1))) as! NSColor
  42. if (markInfo[color] != nil) {
  43. let count = (markInfo[color] as? NSNumber)!.intValue
  44. markInfo[color] = NSNumber.init(value: count + 1)
  45. }else {
  46. markInfo[color] = NSNumber.init(value: 1)
  47. }
  48. }
  49. }
  50. var maxCount = Int(0);
  51. var bgColor : NSColor = NSColor.clear
  52. for color in markInfo.allKeys {
  53. let count = (markInfo[color] as? NSNumber)!.intValue
  54. if count > maxCount {
  55. maxCount = count
  56. bgColor = color as! NSColor
  57. }
  58. }
  59. // if nil != bgColor {
  60. // NSLog(String("识别到背景色\(bgColor)"))
  61. // }
  62. // let bg_r = Int(bgColor.redComponent*255);
  63. // let bg_g = Int(bgColor.redComponent*255);
  64. // let bg_b = Int(bgColor.redComponent*255);
  65. // let bg_a = Int(bgColor.redComponent*255);
  66. //
  67. let data = NSMutableData.init(length: cWidth * cHeight * 4)
  68. // Compare
  69. let compareDifValue = DataModel.shared.comparativeDifference()
  70. var equalCount = 0 as Double
  71. var bgCount = 0 as Double
  72. for w in 0...maxWidth {
  73. let x = Int(w)
  74. for h in 0...maxHeight {
  75. let y = Int(h)
  76. let cColor = checkImageRep.colorAt(x: x, y: y) as! NSColor
  77. let rColor = resultImageRep.colorAt(x: x, y: y) as! NSColor
  78. let cr = Int(cColor.redComponent*255)
  79. let cg = Int(cColor.greenComponent*255)
  80. let cb = Int(cColor.blueComponent*255)
  81. let ca = Int(cColor.blueComponent*255)
  82. let rr = Int(rColor.redComponent*255)
  83. let rg = Int(rColor.greenComponent*255)
  84. let rb = Int(rColor.blueComponent*255)
  85. let ra = Int(rColor.blueComponent*255)
  86. // if (cColor.isEqual(to: rColor)) {
  87. if (abs(cr - rr) <= compareDifValue &&
  88. abs(cg - rg) <= compareDifValue &&
  89. abs(cb - rb) <= compareDifValue &&
  90. abs(ca - ra) <= compareDifValue) {
  91. equalCount = equalCount + 1
  92. if cColor.isEqual(to: bgColor) {
  93. bgCount += 1
  94. }
  95. }else if (processCover && nil != data){
  96. let addr = cWidth * 4 * y + x * 4
  97. var r = uint8(255)
  98. data!.replaceBytes(in: NSRange.init(location: addr+0, length: 1), withBytes: &r)
  99. var g = uint8(255 * rColor.greenComponent/2)
  100. data!.replaceBytes(in: NSRange.init(location: addr+1, length: 1), withBytes: &g)
  101. var b = uint8(255 * rColor.blueComponent/2)
  102. data!.replaceBytes(in: NSRange.init(location: addr+2, length: 1), withBytes: &b)
  103. var a = uint8(255 * rColor.alphaComponent * 0.7)
  104. data!.replaceBytes(in: NSRange.init(location: addr+3, length: 1), withBytes: &a)
  105. }
  106. }
  107. }
  108. let outDegree = Double(max(equalCount-bgCount, 1)/(max(Double(cWidth) * Double(cHeight)-bgCount, 1)) * 100.0)
  109. if (abs(outDegree - 100) > 0 && processCover && nil != data) {
  110. DispatchQueue.global().async {
  111. let cfData = CFDataCreate(kCFAllocatorDefault, data?.bytes, data!.length)
  112. let dataProvider = CGDataProvider.init(data: cfData!)
  113. let colorSpace = CGColorSpaceCreateDeviceRGB()
  114. let cgImage = CGImage.init(width: cWidth,
  115. height: cHeight,
  116. bitsPerComponent: 8,
  117. bitsPerPixel: 8 * 4,
  118. bytesPerRow: cWidth * 4,
  119. space: colorSpace,
  120. bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrderDefault.rawValue) ?? CGBitmapInfo.byteOrderDefault,
  121. provider: dataProvider!,
  122. decode: nil,
  123. shouldInterpolate: true,
  124. intent: CGColorRenderingIntent.defaultIntent)
  125. if nil != cgImage {
  126. let coverPath = NSString(format: "%@_cover.png", NSString(string: resultPath).deletingPathExtension) as! String
  127. let rep = NSBitmapImageRep.init(cgImage: cgImage!)
  128. if let saveData = rep.representation(using: .png, properties: [:]) {
  129. let url = URL.init(fileURLWithPath: coverPath, isDirectory: false)
  130. try? saveData.write(to: url)
  131. }
  132. }
  133. }
  134. }
  135. NSLog(String("过滤点数目\(bgCount)"))
  136. return outDegree
  137. }
  138. }
  139. //Genera Image
  140. class func processImage(_ resultPath:String, checkPath:String) -> NSImage? {
  141. autoreleasepool {
  142. if !FileManager.default.fileExists(atPath: resultPath) || !FileManager.default.fileExists(atPath: checkPath) {
  143. return nil
  144. }
  145. let rImage = NSImage.init(contentsOfFile: resultPath) ?? nil
  146. let cImage = NSImage.init(contentsOfFile: checkPath) ?? nil
  147. if nil == rImage || nil == cImage {
  148. return nil
  149. }
  150. let resultImage = rImage as! NSImage
  151. let checkImage = cImage as! NSImage
  152. let resultImageRep = NSBitmapImageRep.init(cgImage: resultImage.cgImage(forProposedRect: nil, context: nil, hints: nil)!)
  153. let checkImageRep = NSBitmapImageRep.init(cgImage: checkImage.cgImage(forProposedRect: nil, context: nil, hints: nil)!)
  154. let rWidth = resultImageRep.pixelsWide
  155. let rHeight = resultImageRep.pixelsHigh
  156. let rBitPerPixel = resultImageRep.bitsPerPixel / 8
  157. let rBytePerRow = resultImageRep.bytesPerRow
  158. let cWidth = checkImageRep.pixelsWide
  159. let cHeight = checkImageRep.pixelsHigh
  160. let cBitPerPixel = checkImageRep.bitsPerPixel / 8
  161. let cBytePerRow = checkImageRep.bytesPerRow
  162. let data = NSMutableData.init(length: cWidth * cHeight * 4)
  163. if nil == data {
  164. return nil
  165. }
  166. let maxWidth = min(rWidth, cWidth) - 1
  167. let maxHeight = min(rHeight, cHeight) - 1
  168. // check background color
  169. // 挑选图片 对角斜线 上的相素进行识别
  170. var markInfo = NSMutableDictionary.init()
  171. for w in 0...maxWidth {
  172. let x = Int(w)
  173. for mark in 0...1 {
  174. let color = checkImageRep.colorAt(x: min(x, cWidth-1), y: min(mark == 0 ? x : (maxWidth - x), (cHeight-1))) as! NSColor
  175. if (markInfo[color] != nil) {
  176. let count = (markInfo[color] as? NSNumber)!.intValue ?? 0
  177. markInfo[color] = NSNumber.init(value: count + 1)
  178. }else {
  179. markInfo[color] = NSNumber.init(value: 1)
  180. }
  181. }
  182. }
  183. var maxCount = Int(0);
  184. var bgColor : NSColor? = nil
  185. for color in markInfo.allKeys {
  186. let count = (markInfo[color] as? NSNumber)!.intValue ?? 0
  187. if count > maxCount {
  188. maxCount = count
  189. bgColor = color as! NSColor
  190. }
  191. }
  192. if nil != bgColor {
  193. NSLog(String("识别到背景色\(bgColor)"))
  194. }
  195. // Compare
  196. let compareDifValue = DataModel.shared.comparativeDifference()
  197. for w in 0...maxWidth {
  198. let x = Int(w)
  199. for h in 0...maxHeight {
  200. let y = Int(h)
  201. let cColor = checkImageRep.colorAt(x: x, y: y) as! NSColor
  202. let rColor = resultImageRep.colorAt(x: x, y: y) as! NSColor
  203. let cr = Int(cColor.redComponent*255)
  204. let cg = Int(cColor.greenComponent*255)
  205. let cb = Int(cColor.blueComponent*255)
  206. let ca = Int(cColor.blueComponent*255)
  207. let rr = Int(rColor.redComponent*255)
  208. let rg = Int(rColor.greenComponent*255)
  209. let rb = Int(rColor.blueComponent*255)
  210. let ra = Int(rColor.blueComponent*255)
  211. // if (cColor.isEqual(to: rColor)) {
  212. if (abs(cr - rr) <= compareDifValue &&
  213. abs(cg - rg) <= compareDifValue &&
  214. abs(cb - rb) <= compareDifValue &&
  215. abs(ca - ra) <= compareDifValue) {
  216. if bgColor != nil &&
  217. cColor.isEqual(to: bgColor) {
  218. }
  219. }else {
  220. // NSLog("(\(cr),\(cg),\(cb),\(cr))=(\(rr),\(rg),\(rb),\(rr))")
  221. let addr = cWidth * 4 * y + x * 4
  222. var r = uint8(255)
  223. data!.replaceBytes(in: NSRange.init(location: addr+0, length: 1), withBytes: &r)
  224. var g = uint8(255 * rColor.greenComponent/2)
  225. data!.replaceBytes(in: NSRange.init(location: addr+1, length: 1), withBytes: &g)
  226. var b = uint8(255 * rColor.blueComponent/2)
  227. data!.replaceBytes(in: NSRange.init(location: addr+2, length: 1), withBytes: &b)
  228. var a = uint8(255 * rColor.alphaComponent * 0.7)
  229. data!.replaceBytes(in: NSRange.init(location: addr+3, length: 1), withBytes: &a)
  230. }
  231. }
  232. }
  233. let cfData = CFDataCreate(kCFAllocatorDefault, data?.bytes, data!.length)
  234. let dataProvider = CGDataProvider.init(data: cfData!)
  235. let colorSpace = CGColorSpaceCreateDeviceRGB()
  236. let cgImage = CGImage.init(width: cWidth,
  237. height: cHeight,
  238. bitsPerComponent: 8,
  239. bitsPerPixel: 8 * 4,
  240. bytesPerRow: cWidth * 4,
  241. space: colorSpace,
  242. bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrderDefault.rawValue) ?? CGBitmapInfo.byteOrderDefault,
  243. provider: dataProvider!,
  244. decode: nil,
  245. shouldInterpolate: true,
  246. intent: CGColorRenderingIntent.defaultIntent)
  247. if nil != cgImage {
  248. return NSImage.init(cgImage: cgImage!, size: NSSize.init(width: cWidth, height: cHeight))
  249. }
  250. return nil
  251. }
  252. }
  253. }