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