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

Posted

技术标签:

【中文标题】在 UIImage 上使用 Core Graphic 绘制渐变结果不一致【英文标题】:Drawing Gradient with Core Graphic on UIImage result not consistent 【发布时间】:2015-02-07 04:31:11 【问题描述】:

目标

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

设置

我有一个函数调用 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()

结果

【问题讨论】:

【参考方案1】:

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

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

创建一个由每种颜色的第一个组件组成的数组,因此 2 个组件(甚至不是您想要的组件)

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

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

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

您可以使用此函数将颜色分量提取到实际颜色分量的数组中。这会构建一个由 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)

【讨论】:

你的回答很清楚。非常感谢。我正在尝试在图像上覆盖一些文本,并将使用渐变为文本提供某种对比度,例如 Flipboard link。你认为这是一种有效的方法吗?因为我必须将此应用于从服务器获取的大量照片。

以上是关于在 UIImage 上使用 Core Graphic 绘制渐变结果不一致的主要内容,如果未能解决你的问题,请参考以下文章

使用 Core Graphics 绘制 UIImage?

在 Core Data 中保存 UIImage 的最佳方法

将 UIImage 保存到 Core Data 时出错

如何从 UIImage (Cocoa Touch) 或 CGImage (Core Graphics) 获取像素数据?

Core Data 不会从内存中释放 UIImage 数据 (ImageIO_PNG_Data)

如何在 Documents 文件夹中保存 UIImagePicker 中的 UIImage 并获取路径字符串以保存在 Swift 中的 Core Data 中