Swift 图片转成单通道灰度

这里只是玩一玩, 追求效率的同学可以参考 Apple 的 Accelerate.vImage


extension UIImage {
    
    func graySacled() -> UIImage? {
        
        guard
            let cgImage = cgImage,
            let data = cgImage.dataProvider?.data as Data? else {
                return nil
        }
        
        let width = cgImage.width
        let height = cgImage.height
        let channels = 4
        let size = data.count / channels
        
        let buffer = UnsafeMutablePointer.allocate(capacity: size)
        defer { free(buffer) }

        stride(from: 0, to: data.count, by: channels).forEach {
            /// 这里灰色使用最简单的算法 `G = (R + G + B) / 3`
            buffer.advanced(by: $0 / channels).pointee = avarage(($0..<$0 + 3).map { data[$0].uint16 }).uint8
        }
        /// =================== buffer 已经是`单通道` `灰色`, 下面是合成图片 ===================
        
        let releaseData: CGDataProviderReleaseDataCallback = {
            (info, buffer, length) in
        }
        
        return CGDataProvider(
                dataInfo: nil,
                data: buffer,
                size: size,
                releaseData: releaseData)
            .flatMap {
                CGImage(
                width: width,
                height: height,
                bitsPerComponent: 8,
                bitsPerPixel: 8,
                bytesPerRow: width,
                space: CGColorSpaceCreateDeviceGray(),
                bitmapInfo: CGBitmapInfo(rawValue: 0),
                provider: $0,
                decode: nil,
                shouldInterpolate: true,
                intent: .defaultIntent)
            }
            .flatMap(UIImage.init)

    }
}

public func avarage(
    _ sequence: S)
    -> S.Element where S.Element: FixedWidthInteger {
        return sequence.reduce(0, +) / S.Element(sequence.count)
}

extension UInt16 {
    var uint8: UInt8 {
        return UInt8(self)
    }
}

extension UInt8 {
    var uint16: UInt16 {
        return UInt16(self)
    }
}

你可能感兴趣的:(Swift 图片转成单通道灰度)