为什么 CILinearGradient 会导致非常非线性的梯度?

Sin*_*r20 5 ios swift

我是一个相对较新的 Swift 开发人员,我正在使用 CILinearGradient CIFilter 生成渐变,然后我可以将其用作背景和纹理。我对它的工作方式非常满意,直到我意识到从中产生的梯度似乎严重偏向远离光谱的黑端。

起初我以为我疯了,但后来我创建了纯黑到白和白到黑的渐变,并将它们并排放置在屏幕上。我截取了屏幕截图并将其带入了 Photoshop。然后我查看了颜色值。您可以看到每个渐变的末端对齐(一端为纯黑色,另一端为纯白色,另一端则相反),但每个渐变的中间点明显偏向黑色端。

在此处输入图片说明

这是 CIFilter 的问题还是我做错了什么?感谢任何对此有任何见解的人!

这是我的代码:

func gradient2colorIMG(UIcolor1: UIColor, UIcolor2: UIColor, width: CGFloat, height: CGFloat) -> CGImage? {
    if let gradientFilter = CIFilter(name: "CILinearGradient") {   
        let startVector:CIVector = CIVector(x: 0 + 10, y: 0)
        let endVector:CIVector = CIVector(x: width - 10, y: 0)
        let color1 = CIColor(color: UIcolor1)
        let color2 = CIColor(color: UIcolor2)
        let context = CIContext(options: nil)
        if let currentFilter = CIFilter(name: "CILinearGradient") {
            currentFilter.setValue(startVector, forKey: "inputPoint0")
            currentFilter.setValue(endVector, forKey: "inputPoint1")
            currentFilter.setValue(color1, forKey: "inputColor0")
            currentFilter.setValue(color2, forKey: "inputColor1")
            if let output = currentFilter.outputImage {
                if let cgimg = context.createCGImage(output, from: CGRect(x: 0, y: 0, width: width, height: height)) {
                    let gradImage = cgimg
                    return gradImage
                }
            }
        }
    }
    return nil
}
Run Code Online (Sandbox Code Playgroud)

然后我使用此代码在 SpriteKit 中调用它(但这只是为了我可以在屏幕上看到它们以比较函数输出的 CGImages)...

if let gradImage = gradient2colorIMG(UIcolor1: UIColor(red: 255.0 / 255.0, green: 255.0 / 255.0, blue: 255.0 / 255.0, alpha: 1.0), UIcolor2: UIColor(red: 0.0 / 255.0, green: 0.0 / 255.0, blue: 0.0 / 255.0, alpha: 1.0), width: 250, height: 80) {        
    let sampleback = SKShapeNode(path: CGPath(roundedRect: CGRect(x: 0, y: 0, width: 250, height: 80), cornerWidth: 5, cornerHeight: 5, transform: nil))
    sampleback.fillColor = .white
    sampleback.fillTexture = SKTexture(cgImage: gradImage)
    sampleback.zPosition = 200
    sampleback.position = CGPoint(x: 150, y: 50)
    self.addChild(sampleback)
}    
if let gradImage2 = gradient2colorIMG(UIcolor1: UIColor(red: 0.0 / 255.0, green: 0.0 / 255.0, blue: 0.0 / 255.0, alpha: 1.0), UIcolor2: UIColor(red: 255.0 / 255.0, green: 255.0 / 255.0, blue: 255.0 / 255.0, alpha: 1.0), width: 250, height: 80) {    
    let sampleback2 = SKShapeNode(path: CGPath(roundedRect: CGRect(x: 0, y: 0, width: 250, height: 80), cornerWidth: 5, cornerHeight: 5, transform: nil))
    sampleback2.fillColor = .white
    sampleback2.fillTexture = SKTexture(cgImage: gradImage2)
    sampleback2.zPosition = 200
    sampleback2.position = CGPoint(x: 150, y: 150)
    self.addChild(sampleback2)
}
Run Code Online (Sandbox Code Playgroud)

作为另一个后续,我尝试做一个红蓝渐变(纯粹是色调的变化),它是完美的线性(见下文)。问题似乎与亮度有关。

红蓝渐变确实以完美的线性方式渐变其色调

mat*_*att 3

想象一下黑色为 0,白色为 1。那么这里的问题是,我们直观地认为黑色的 50%“是”0.5 \xe2\x80\x94 的灰度值,但事实并非如此。

\n

要了解这一点,请考虑以下核心图像实验:

\n
let con = CIContext(options: nil)\nlet white = CIFilter(name:"CIConstantColorGenerator")!\nwhite.setValue(CIColor(color:.white), forKey:"inputColor")\nlet black = CIFilter(name:"CIConstantColorGenerator")!\nblack.setValue(CIColor(color:UIColor.black.withAlphaComponent(0.5)),\n    forKey:"inputColor")\nlet atop = CIFilter(name:"CISourceAtopCompositing")!\natop.setValue(white.outputImage!, forKey:"inputBackgroundImage")\natop.setValue(black.outputImage!, forKey:"inputImage")\nlet cgim = con.createCGImage(atop.outputImage!, \n    from: CGRect(x: 0, y: 0, width: 201, height: 50))!\nlet image = UIImage(cgImage: cgim)\nlet iv = UIImageView(image:image)\nself.view.addSubview(iv)\niv.frame.origin = CGPoint(x: 100, y: 150)\n
Run Code Online (Sandbox Code Playgroud)\n

我在这里所做的是将 50% 透明度的黑色样本放在白色样本上。我们直观地想象结果将是一个读数为 0.5 的样本。但事实并非如此;它是 0.737,与渐变中点处出现的颜色完全相同:

\n

在此输入图像描述

\n

原因是这里的一切都在发生,不是在某些数学真空中,而是在针对特定伽玛调整的色彩空间中。

\n

现在,您可能会问:“但是我在哪里指定了这个色彩空间?这不是我想要的!” 啊哈。当您创建 CIContext 时,您在第一行中指定了它,而不覆盖默认的工作颜色空间。

\n

让我们解决这个问题。将第一行更改为:

\n
let con = CIContext(options: [.workingColorSpace : NSNull()])\n
Run Code Online (Sandbox Code Playgroud)\n

现在输出是这样的:

\n

在此输入图像描述

\n

转眼间,这就是你的 0.5 灰色!

\n

所以我想说的是,如果你像这样创建 CIContext,你将得到你想要的渐变,中间点为 0.5 灰度。我并不是说这比您得到的结果更“正确”,但至少它展示了如何使用您已有的代码获得特定结果。

\n

(事实上​​,我认为你最初得到的更“正确”,因为它是根据人类的感知进行调整的。)

\n