ImageProcess.swift 13 KB

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