在 UIImage 上使用 Core Graphic 绘制渐变结果不一致

Drawing Gradient with Core Graphic on UIImage result not consistent

Objective

我正在尝试在图像上绘制线性渐变。

设置

我有一个函数调用 imageWithGradient,它使用颜色和 imageView 来放置带有渐变的图像。我使用故事板将 imageView 添加到视图中。

问题

当我在模拟器上尝试代码时,有时不会出现渐变,有时不会出现 alpha(纯色),有时会翻转渐变。由于我是 运行 具有相同颜色的相同代码,它应该对所有图像应用相同的渐变,但很少这样做。

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    var c1 = UIColor(red: 1.0, green: 0, blue: 0, alpha: 0.9).CGColor
    var c2 = UIColor(red: 0, green: 0, blue: 0, alpha: 0).CGColor

    imageWithGradient(self.imageView1, startColor: c1, endColor: c2)
    imageWithGradient(self.imageView2, startColor: c1, endColor: c2)
}

func imageWithGradient(imgView:UIImageView, startColor: CGColor, endColor: CGColor){

    var img = UIImage(named:"sample.jpg")!

    UIGraphicsBeginImageContext(img.size)
    var context = UIGraphicsGetCurrentContext()

    img.drawAtPoint(CGPointMake(0, 0))

    var colorSpace = CGColorSpaceCreateDeviceRGB()

    var startColorComp = CGColorGetComponents(startColor)
    var endColorComp = CGColorGetComponents(endColor)
    var colorComps = [startColorComp[0], endColorComp[0]]

    var locations:[CGFloat] = [0.0, 1.0]

    var gradient = CGGradientCreateWithColorComponents(colorSpace, &colorComps, &locations, 2)

    var startPoint = CGPointMake(img.size.width/2, img.size.height/2)
    var endPoint = CGPointMake(img.size.width/2, img.size.height)

    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0)

    imgView.image = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()
}

结果

您实际上是在为颜色分量传递一个未初始化的内存块。

var colorComps = [startColorComp[0], endColorComp[0]]

创建一个由每种颜色的第一个分量组成的数组,所以 2 个分量(甚至不是您想要的分量)

进一步,您将 2 个元素的数组传递给 for:

let gradient = CGGradientCreateWithColorComponents(colorSpace, colorComps, locations, 2)

其中 colorComps 预计接收 8 个浮点数的数组,因此其他 6 个浮点数基本上是随机内存内容,因此结果差异很大。

您可以使用此函数将颜色分量提取到实际颜色分量的数组中。这构建了一个 swift 颜色的 4 个分量的数组(或者不管有多少,但它应该是 4)

func CGColorComponents(color:CGColorRef) -> [CGFloat] {
    let count = CGColorGetNumberOfComponents(color)
    var comps = CGColorGetComponents(color)

    var array = [CGFloat]()

    for i in 0 ..< count {
        array.append(comps.memory)
        comps = comps.successor()
    }

    return array
}

您可以使用以下方法构建适当的组件数组:

let startColorComp = CGColorComponents(startColor)
let endColorComp = CGColorComponents(endColor)
let colorComps =  startColorComp + endColorComp

将它们放在一起,您就可以创建一个函数来覆盖图像上的渐变:

func imageWithGradient(startColor: CGColor, endColor: CGColor) -> UIImage {
    var img = UIImage(named:"img_0002.png")!

    UIGraphicsBeginImageContext(img.size)
    var context = UIGraphicsGetCurrentContext()

    img.drawAtPoint(CGPointMake(0, 0))

    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let componentCount = CGColorSpaceGetNumberOfComponents(colorSpace)
    let startColorComp = CGColorComponents(startColor)
    let endColorComp = CGColorComponents(endColor)
    let colorComps =  startColorComp + endColorComp
    let locations:[CGFloat] = [0.0, 1.0]

    let gradient = CGGradientCreateWithColorComponents(colorSpace, colorComps, locations, 2)

    let startPoint = CGPointMake(img.size.width/2, img.size.height/2)
    let endPoint = CGPointMake(img.size.width/2, img.size.height)

    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0)

    let image = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()

    return image
}

不完全是你使用它的方式,但如果你真的想保持你的语义,你应该能够挖掘出功能。

更好的是,只需使用 CGGradientCreateWithColors 即可:

let gradient = CGGradientCreateWithColors(colorSpace, [startColor, endColor], locations)