UIImageView 在没有 Alpha 的情况下混合颜色

Sky*_*ren 5 core-graphics colors uiimageview swift

我已经被这个问题困扰了好几天了,找不到解决方案。我有一个带有透明背景的 UIImageView 。它位于另一个视图之上(在示例中只是一个具有蓝色背景颜色的 UIView)。由于某种原因,即使它的 alpha 值为 0,它也会混合颜色(在这种情况下,全红色,没有 alpha 值显示为粉红色)。期望的输出是它会像没有 alpha 值的黑色一样清晰显示。

如果超过白色,则其行为符合预期(它是透明的并显示白色)。我尝试了不同的方法来创建 CGContext 和不同的 CALayer 混合模式,但无法让它不混合没有 alpha 值的颜色。

在此输入图像描述

这是一些复制该问题的示例代码。

import UIKit
import PlaygroundSupport
import CoreGraphics

class MyViewController : UIViewController {
    var pixelPointer: UnsafeMutablePointer<UInt8>!
    
    let imageWidth = 20
    let imageHeight = 20
    
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .blue
        
        let viewSize: CGFloat = 150
        
        // Test Image
        pixelPointer  =  UnsafeMutablePointer<UInt8>.allocate(capacity: imageWidth * imageWidth * 4)
        let ctx  = CGContext(data: pixelPointer,
                             width: imageWidth,
                             height: imageHeight,
                             bitsPerComponent: 8,
                             bytesPerRow: 4 * imageWidth,
                             space: CGColorSpaceCreateDeviceRGB(),
                             bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
        for x in 0 ..< imageWidth {
            for y in 0 ..< imageHeight {
                if y == 7 || y == 8 || y == 9 {
                    // Red No Alpha -> Expected to be transparent
                    setColorFor(255, g: 0, b: 0, a: 0, x: x, y: y)
                } else if y == 10 || y == 11 || y == 12 {
                    // Black No Alpha -> Is transparent
                    setColorFor(0, g: 0, b: 0, a: 0, x: x, y: y)
                } else {
                    // Red
                    setColorFor(255, g: 0, b: 0, a: 255, x: x, y: y)
                }
                
            }
        }
        let cgImage = ctx.makeImage()!
        
        // ImageView with Clear Background
        let imageViewClearBackground = UIImageView()
        imageViewClearBackground.backgroundColor = .clear
        imageViewClearBackground.frame.origin = CGPoint(x: 10, y: 10)
        imageViewClearBackground.layer.borderColor = UIColor.black.cgColor
        imageViewClearBackground.layer.borderWidth = 1
        imageViewClearBackground.frame.size = CGSize(width: viewSize, height: viewSize)
        imageViewClearBackground.layer.magnificationFilter = CALayerContentsFilter.nearest
        
        imageViewClearBackground.image = UIImage(cgImage: cgImage)
        view.addSubview(imageViewClearBackground)
        
        // ImageView with White Background
        let imageViewWhiteBackground = UIImageView()
        imageViewWhiteBackground.layer.borderColor = UIColor.black.cgColor
        imageViewWhiteBackground.layer.borderWidth = 1
        imageViewWhiteBackground.backgroundColor = .white
        imageViewWhiteBackground.frame.size = CGSize(width: viewSize, height: viewSize)
        imageViewWhiteBackground.frame.origin = CGPoint(x: viewSize + 20, y: 10)
        imageViewWhiteBackground.layer.magnificationFilter = CALayerContentsFilter.nearest
        
        imageViewWhiteBackground.image = UIImage(cgImage: cgImage)
        view.addSubview(imageViewWhiteBackground)
        
        self.view = view
    }
    
    func setColorFor(_ r: Int, g: Int, b: Int, a: Int, x: Int, y: Int) {
        let offset = (y * Int(imageWidth) * 4) + x * 4
        pixelPointer[offset+0] = UInt8(r)
        pixelPointer[offset+1] = UInt8(g)
        pixelPointer[offset+2] = UInt8(b)
        pixelPointer[offset+3] = UInt8(a)
    }
}

// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
Run Code Online (Sandbox Code Playgroud)

mat*_*att 3

问题是这样的:

\n
setColorFor(255, g: 0, b: 0, a: 0, x: x, y: y)\n
Run Code Online (Sandbox Code Playgroud)\n

不是有效的.premultipliedLast颜色值。预乘意味着颜色已经乘以 Alpha。如果将 255 乘以 0,则会得到 0,因此就是此处 \xe2\x80\x94 中正确的红色值,如第 10-12 行中的结果所示。

\n

如果您只是以正常方式使用 UIGraphicsImageRenderer 而不是原始位图上下文来构造图像,您可能会少很多困惑。但是,当然,如果您的用例排除了这一点,那么请务必使用位图 \xe2\x80\x94 ,但这样就有更多的空间让您错误地使用它。

\n