UIImageView正在混合颜色但没有alpha值。

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

如果在白色上方,则表现如预期(它是透明的,并显示白色)。我尝试过使用不同的CGContext创建方式和不同的CALayer混合模式,但无法使它不混合没有alpha值的颜色。

enter image description here

以下是可复制该问题的示例代码:

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()
1个回答

3
问题在于这个:
setColorFor(255, g: 0, b: 0, a: 0, x: x, y: y)

.premultipliedLast不是有效的颜色值。预乘意味着颜色已经被 alpha 值乘以了。如果你将 255 乘以 0,你会得到 0,因此这里的正确红色值就是那个——正如第 10-12 行的结果所示。

如果您使用普通的 UIGraphicsImageRenderer 构建图像,而不使用原始的位图上下文,您可能会少搞混自己。但当然,如果您的使用情况排除了这种方法,那么请务必使用位图。但是,这样做错误的可能性就更大了。


谢谢Matt。问题似乎就像你指出的那样。由于上下文的创建方式,我需要预先乘以这些值。不幸的是,“正常”的图像构建方式对我的用例来说不可行。感谢您让我朝着正确的方向前进。 - Skyler Lauren
没问题。谢谢你提出这样一个构思清晰的问题。 - matt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接