// MARK: - 图片扩展
extension UIImage {
// 获取主色 (直方图方法)
func dominantColor() -> UIColor? {
guard let cgImage = self.cgImage else { return nil }
let width = 40, height = 40
let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue
let colorSpace = CGColorSpaceCreateDeviceRGB()
guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 4 * width, space: colorSpace, bitmapInfo: bitmapInfo)
else { return nil }
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
guard let data = context.data else { return nil }
let ptr = data.bindMemory(to: UInt8.self, capacity: width * height * 4)
var colorCounts = [UInt32: Int]()
for x in 0..<width {
for y in 0..<height {
let offset = 4 * (y * width + x)
let r = ptr[offset]
let g = ptr[offset + 1]
let b = ptr[offset + 2]
let a = ptr[offset + 3]
if a < 127 { continue }
let rgb = (UInt32(r) << 16) | (UInt32(g) << 8) | UInt32(b)
colorCounts[rgb, default: 0] += 1
}
}
let mostCommon = colorCounts.max { $0.value < $1.value }?.key
if let rgb = mostCommon {
return UIColor(
red: CGFloat((rgb >> 16) & 0xFF) / 255.0,
green: CGFloat((rgb >> 8) & 0xFF) / 255.0,
blue: CGFloat(rgb & 0xFF) / 255.0,
alpha: 1.0
)
}
return nil
}
// 替换主色为指定颜色(简单直接替换主色的像素)
func replaceDominantColor(with color: UIColor, threshold: CGFloat = 60.0) -> UIImage? {
guard let cgImage = self.cgImage else { return nil }
guard let domColor = self.dominantColor() else { return nil }
let width = cgImage.width
let height = cgImage.height
let bytesPerRow = 4 * width
let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue
let colorSpace = CGColorSpaceCreateDeviceRGB()
guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo)
else { return nil }
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
guard let data = context.data else { return nil }
let ptr = data.bindMemory(to: UInt8.self, capacity: width * height * 4)
// 获取主色和替换色的rgb
func rgbArray(from color: UIColor) -> [CGFloat] {
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
color.getRed(&r, green: &g, blue: &b, alpha: &a)
return [r * 255, g * 255, b * 255]
}
let srcRGB = rgbArray(from: domColor)
let dstRGB = rgbArray(from: color)
for i in 0..<(width * height) {
let offset = i * 4
let r = CGFloat(ptr[offset])
let g = CGFloat(ptr[offset + 1])
let b = CGFloat(ptr[offset + 2])
let a = ptr[offset + 3]
if a < 127 { continue }
// 欧氏距离
let dist = sqrt(pow(r - srcRGB[0], 2) + pow(g - srcRGB[1], 2) + pow(b - srcRGB[2], 2))
if dist < threshold { // 可调阈值
ptr[offset] = UInt8(dstRGB[0])
ptr[offset + 1] = UInt8(dstRGB[1])
ptr[offset + 2] = UInt8(dstRGB[2])
}
}
if let newCGImage = context.makeImage() {
return UIImage(cgImage: newCGImage, scale: self.scale, orientation: self.imageOrientation)
}
return nil
}
}