2

I have a horizontal collection view so when selecting the specific cell will change the color of the image view, the problem is when selecting an image tint color changes successfully on images, and some image's tint color does not work with the right behavior display as the background color on the image.

this is the function to change tint color of image

 func imageWithColor(color1: UIColor) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        color1.setFill()

        let context = UIGraphicsGetCurrentContext()! as CGContext
        context.translateBy(x: 0, y: self.size.height)
        context.scaleBy(x: 1.0, y: -1.0);
        context.setBlendMode(CGBlendMode.normal)

        let rect = CGRectMake(0, 0, self.size.width, self.size.height) as CGRect
        context.clip(to: rect, mask: self.cgImage!)
        context.fill(rect)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()! as UIImage
        UIGraphicsEndImageContext()

        return newImage
    }

display image using kingfihser ` imageProduct.kf.setImage(with: URL(string:"imageurl"), placeholder: nil) { result in

                self.imageProduct.image = self.categoryImg.image?.imageWithColor(color1: UIColor.green)

           }`

The tint color must be changed successfully on any image read from url (this is screenshot from issue image when add tint color https://freeimage.host/i/H4nx1s9).

2 Answers2

1

The issue here seems to be related to how tint color is applied to the images that contain an alpha channel (transparency). If an image has an alpha channel, then when the tint color is applied, it might not be applied as expected and could be showing the background color on the image.

One approach could be to check if the image has an alpha channel and handle it differently. However, in your case, the quickest solution could be to use the renderingMode property of UIImage which controls how the image is drawn. You can set it to .alwaysTemplate which treats the image as a template for a mask that will be used in conjunction with the tintColor to create the final colored image.

Here is how you can change your code:

func imageWithColor(color1: UIColor) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
    color1.setFill()

    let context = UIGraphicsGetCurrentContext()! as CGContext
    context.translateBy(x: 0, y: self.size.height)
    context.scaleBy(x: 1.0, y: -1.0);
    context.setBlendMode(CGBlendMode.normal)

    let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
    context.clip(to: rect, mask: self.cgImage!)
    context.fill(rect)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()! as UIImage
    UIGraphicsEndImageContext()

    return newImage.withRenderingMode(.alwaysTemplate) // Add this line
}

imageProduct.kf.setImage(with: URL(string:"imageurl"), placeholder: nil) { result in
    switch result {
    case .success(let value):
        let image = value.image.imageWithColor(color1: .green)
        DispatchQueue.main.async {
            self.imageProduct.image = image
            self.imageProduct.tintColor = .green
        }
    case .failure(let error):
        print("Error: \(error)") // handle error
    }
}

In the code above, we set the renderingMode of the image to .alwaysTemplate before returning it. After the image is fetched successfully using Kingfisher, we apply the imageWithColor function to it, then set this image to the imageProduct imageView, and finally set the tintColor of the imageView to the desired color. Please note that UI updates should be done on the main thread, hence the DispatchQueue.main.async.

Emm
  • 1,963
  • 2
  • 20
  • 51
0

The issue might be related to the alpha channel of the image or the blend mode used in the context. To ensure consistent behaviour across all images, you can modify your imageWithColor like this

func imageWithColor(color: UIColor) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
    
    let context = UIGraphicsGetCurrentContext()!
    let rect = CGRect(origin: .zero, size: self.size)
    
    // Draw the image
    self.draw(in: rect)
    
    // Apply tint color
    context.setFillColor(color.cgColor)
    context.setBlendMode(.sourceAtop)
    context.fill(rect)
    
    // Create a new image with the tint color
    let tintedImage = UIGraphicsGetImageFromCurrentImageContext()!
    
    UIGraphicsEndImageContext()
    
    return tintedImage
}

You can then use this updated function to set the tint color of the image in your Kingfisher completion block,

imageProduct.kf.setImage(with: URL(string: "imageurl"), placeholder: nil) { result in
    if case .success(let value) = result {
        self.imageProduct.image = value.image.imageWithColor(color: UIColor.green)
    }
}
Sudeep P H
  • 244
  • 5