首页 > 解决方案 > 如何设置/更改 CGImage 上的 alphaInfo?

问题描述

我正在使用这个扩展来获取像素颜色:

extension UIImage {
    subscript (x: Int, y: Int) -> UIColor? {
        guard x >= 0 && x < Int(size.width) && y >= 0 && y < Int(size.height),
            let cgImage = cgImage,
            let provider = cgImage.dataProvider,
            let providerData = provider.data,
            let data = CFDataGetBytePtr(providerData) else {
            return nil
        }

        let numberOfComponents = 4
        let pixelData = ((Int(size.width) * y) + x) * numberOfComponents

        let r = CGFloat(data[pixelData]) / 255.0
        let g = CGFloat(data[pixelData + 1]) / 255.0
        let b = CGFloat(data[pixelData + 2]) / 255.0
        let a = CGFloat(data[pixelData + 3]) / 255.0

        return UIColor(red: r, green: g, blue: b, alpha: a)
    }
}

当我使用操场或模拟器运行时,一切正常,但是当我在我的设备(iPhone XR)上运行它时,我得到了不同的值。

经过一段时间的调试,我发现当我使用模拟器时,cgimage 有 alphaInfo kCGImageAlphaLast,当我使用设备时,alphaInfo 是kCGImageAlphaNoneSkipLast

调试:

// Simulator
<CGImage 0x7f9f674150f0> (IP)
    <<CGColorSpace 0x600002893120> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1)>
        width = 1000, height = 500, bpc = 8, bpp = 32, row bytes = 4000 
        kCGImageAlphaLast | 0 (default byte order)  | kCGImagePixelFormatPacked 
        is mask? No, has masking color? No, has soft mask? No, has matte? No, should interpolate? Yes
// -------------------------------------------- //

// Device
<CGImage 0x7f88df70d980> (DP)
    <<CGColorSpace 0x6000003dc540> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1)>
        width = 1000, height = 500, bpc = 8, bpp = 32, row bytes = 4000 
        kCGImageAlphaNoneSkipLast | 0 (default byte order)  | kCGImagePixelFormatPacked 
        is mask? No, has masking color? No, has soft mask? No, has matte? No, should interpolate? Yes

由于 alphaInfo 是一个只读属性,有没有办法设置它或重新创建将 alphaValue 设置为kCGImageAlphaLast.

我发现将颜色值乘以 alpha 值,但我对如何“恢复”“正确”值有点困惑。

https://developer.apple.com/documentation/coregraphics/cgimagealphainfo/kcgimagealphapremultipliedlast

标签: iosswiftcore-graphicscore-image

解决方案


更新:

自从苹果说:

kCGImageAlphaPremultipliedLast

The alpha component is stored in the least significant bits of each pixel and the color components have already been multiplied by this alpha value. For example, premultiplied RGBA.

它很容易修复,你的 RGB 值乘以 alpha 值,所以,你只需要恢复它。

premultiplied.R = (straight.R * straight.A / 255);
premultiplied.G = (straight.G * straight.A / 255);
premultiplied.B = (straight.B * straight.A / 255);
premultiplied.A = straight.A;

所以,我们只需要做相反的事情:

straight.R = (premultiplied.R / straight.A) * 255;
straight.G = (premultiplied.G / straight.A) * 255;
straight.B = (premultiplied.B / straight.A) * 255;
straight.A = premultiplied.A;

我创建了这个扩展来获得正确的像素颜色:

extension UIColor {

    func rgb(alphaInfo: CGImageAlphaInfo) -> (red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) {

        var fRed : CGFloat = 0
        var fGreen : CGFloat = 0
        var fBlue : CGFloat = 0
        var fAlpha: CGFloat = 0

        if self.getRed(&fRed, green: &fGreen, blue: &fBlue, alpha: &fAlpha) {

            var iRed = fRed * 255.0
            var iGreen = fGreen * 255.0
            var iBlue = fBlue * 255.0
            let iAlpha = fAlpha * 255.0

            switch alphaInfo {
            case .premultipliedLast, .premultipliedFirst:
                iRed = (iRed / iAlpha) * 255
                iGreen = (iGreen / iAlpha) * 255
                iBlue = (iBlue / iAlpha) * 255
            default:
                break
            }

             return (red:UInt8(iRed.rounded()),
green:UInt8(iBlue.rounded()), 
blue:UInt8(iGreen.rounded()), 
alpha:UInt8(iAlpha.rounded()))
        } else {
            // Could not extract RGBA components:
            return (0, 0, 0 , 0)
        }
    }
}

推荐阅读