我是一个相对较新的 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)
作为另一个后续,我尝试做一个红蓝渐变(纯粹是色调的变化),它是完美的线性(见下文)。问题似乎与亮度有关。
想象一下黑色为 0,白色为 1。那么这里的问题是,我们直观地认为黑色的 50%“是”0.5 \xe2\x80\x94 的灰度值,但事实并非如此。
\n要了解这一点,请考虑以下核心图像实验:
\nlet 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)\nRun Code Online (Sandbox Code Playgroud)\n我在这里所做的是将 50% 透明度的黑色样本放在白色样本上。我们直观地想象结果将是一个读数为 0.5 的样本。但事实并非如此;它是 0.737,与渐变中点处出现的颜色完全相同:
\n\n原因是这里的一切都在发生,不是在某些数学真空中,而是在针对特定伽玛调整的色彩空间中。
\n现在,您可能会问:“但是我在哪里指定了这个色彩空间?这不是我想要的!” 啊哈。当您创建 CIContext 时,您在第一行中指定了它,而不覆盖默认的工作颜色空间。
\n让我们解决这个问题。将第一行更改为:
\nlet con = CIContext(options: [.workingColorSpace : NSNull()])\nRun Code Online (Sandbox Code Playgroud)\n现在输出是这样的:
\n\n转眼间,这就是你的 0.5 灰色!
\n所以我想说的是,如果你像这样创建 CIContext,你将得到你想要的渐变,中间点为 0.5 灰度。我并不是说这比您得到的结果更“正确”,但至少它展示了如何使用您已有的代码获得特定结果。
\n(事实上,我认为你最初得到的更“正确”,因为它是根据人类的感知进行调整的。)
\n