swift - 在 Swift 中为 UIImage 着色
问题描述
我正在尝试编写一个将颜色蒙版应用于给定图像的辅助函数。我的功能必须将图像的所有不透明像素设置为相同的颜色。
这是我到目前为止所拥有的:
extension UIImage {
func applyColorMask(color: UIColor, context: CIContext) -> UIImage {
guard let cgImageInput = self.cgImage else {
print("applyColorMask: \(self) has no cgImage attribute.")
return self
}
// Throw away existing colors, and fill the non transparent pixels with the input color
// s.r = dot(s, redVector), s.g = dot(s, greenVector), s.b = dot(s, blueVector), s.a = dot(s, alphaVector)
// s = s + bias
let colorFilter = CIFilter(name: "CIColorMatrix")!
let ciColorInput = CIColor(cgColor: color.cgColor)
colorFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 0), forKey: "inputRVector")
colorFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 0), forKey: "inputGVector")
colorFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 0), forKey: "inputBVector")
colorFilter.setValue(CIVector(x: 0, y: 0, z: 0, w: 1), forKey: "inputAVector")
colorFilter.setValue(CIVector(x: ciColorInput.red, y: ciColorInput.green, z: ciColorInput.blue, w: 0), forKey: "inputBiasVector")
colorFilter.setValue(CIImage(cgImage: cgImageInput), forKey: kCIInputImageKey)
if let cgImageOutput = context.createCGImage(colorFilter.outputImage!, from: colorFilter.outputImage!.extent) {
return UIImage(cgImage: cgImageOutput)
} else {
print("applyColorMask: failed to apply filter to \(self)")
return self
}
}
}
该代码适用于黑白,但在应用更有趣的颜色时不是我所期望的。请参阅下面的原始图像和屏幕截图:边框和图像使用相同的颜色。虽然他们不同。我的功能做错了。我错过了过滤矩阵中的某些内容吗?
原始图像(中心有白点):
从上到下:过滤后的图像UIColor(1.0, 1.0, 1.0, 1.0)
插入到具有相同颜色边框的 UIImageView 中。然后与UIColor(0.6, 0.5, 0.4, 1.0)
. 最后与UIColor(0.2, 0.5, 1.0, 1.0)
编辑
运行Filterpedia给了我同样的结果。那么我对 CIColorMatrix 过滤器的理解可能是错误的。文档说:
该过滤器执行矩阵乘法,如下所示,以变换颜色向量:
- sr = 点(s,redVector)
- sg = 点(s,greenVector)
- sb = 点(s,blueVector)
- sa = dot(s, alphaVector)
- s = s + 偏差
然后,假设我用 (0,0,0,0) 向量抛出所有 RGB 数据,然后传递 (0.5, 0, 0, 0) 中红色作为偏置向量;我希望我的图像将所有完全不透明的像素都设置为 (127, 0, 0)。下面的截图显示它稍微轻一些(红色=186):
这是我想做的一些伪代码:
// image "im" is a vector of pixels
// pixel "p" is struct of rgba values
// color "col" is the input color or a struct of rgba values
for (p in im) {
p.r = col.r
p.g = col.g
p.b = col.b
// Nothing to do with the alpha channel
}
解决方案
正如@dfd 建议的那样,我终于写了一个 CIColorKernel,它工作正常:
class ColorFilter: CIFilter {
var inputImage: CIImage?
var inputColor: CIColor?
let kernel: CIColorKernel = {
let kernelString = "kernel vec4 colorize(__sample pixel, vec4 color)\n"
+ "{\n"
+ " pixel.rgb = color.rgb;\n"
+ " return pixel;\n"
+ "}\n"
return CIColorKernel(source: kernelString)!
}()
override var outputImage: CIImage? {
guard let inputImage = inputImage else {
print("\(self) cannot produce output because no input image provided.")
return nil
}
guard let inputColor = inputColor else {
print("\(self) cannot produce output because no input color provided.")
return nil
}
let inputs = [inputImage, inputColor] as [Any]
return kernel.apply(extent: inputImage.extent, arguments: inputs)
}
}
总而言之,我首先使用的 CIColorMatrix 似乎不是线性的(使用偏置向量时)。给出红色 0,5(浮点数)值不会在 [0-255] 区间内输出红色 127 颜色的图像。
编写自定义过滤器是我的解决方案。
推荐阅读
- c# - .Net core 3.1 中接受的各种 application/json Content-type
- docker - docker镜像之间的常用命令
- sendgrid - SendGrid 中的动态模板:检查字符串
- java - 尝试在 c:\Users\"firstname" "lastname" 中使用 vscode for Java Space 导致错误
- spring-boot - 骆驼上下文根本没有在 Hawtio JMX 中列出
- networking - aws ec2 实例的 Ubuntu 18.04 netplan 配置
- javascript - 为什么汉堡菜单在 Firefox 中无法正确显示并且无法在一页上打开?
- python - 如何有条件地格式化数据框
- amazon-web-services - 如何使用 Cloud Front 将视频从 AWS S3 流式传输到 Angular 8 应用程序
- c# - C#如何在另一个程序中使用字符串