Как мне установить / изменить alphaInfo на CGImage? - PullRequest
0 голосов
/ 13 февраля 2020

Я использую это расширение, чтобы получить цвет пикселя:

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.

Я обнаружил, что умножает значение цвета на альфа-значение, но меня немного смущает, как "восстановить" "правильное" значение.

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

1 Ответ

0 голосов
/ 13 февраля 2020

Обновление:

Поскольку Apple сказала:

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 умножаются на альфа-значение, поэтому вам просто нужно вернуть это обратно.

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)
        }
    }
}
...