15

I need to show a tint colored image in CALayer.

It works for UIImageView:

imageView.image = image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)

But CALayer shows the image with its original color and not the tint color.

let tintedImage = image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
layer.contents = tintedImage.CGImage

Is there a way to show tinted image in CALayer as well?

Demo:

https://github.com/exchangegroup/calayer-with-tint-colored-image

enter image description here

Evgenii
  • 36,389
  • 27
  • 134
  • 170

4 Answers4

32

I think my solution is far less cumbersome:

let maskLayer = CALayer()
maskLayer.frame = layer.bounds
maskLayer.contents = tintedImage.CGImage
layer.mask = maskLayer
layer.backgroundColor = UIColor.redColor().CGColor

let me know if it works fine:)

balazs630
  • 3,421
  • 29
  • 46
J.Williams
  • 1,417
  • 1
  • 20
  • 22
  • 2
    much easier and more neat than the accepted answer. You might want to make it more complete by adding let layer = CALayer() and setting layer.frame. – Jeroen Bouma Dec 10 '15 at 14:04
3

I guess that is possible on OSX using the filter property of CALayer, but in ios is not used. I think you should redraw the image totally, here is a sample code, it tints everything that has alpha > 0.

- (UIImage *)tintedImageWithColor:(UIColor *)tintColor blendingMode:(CGBlendMode)blendMode highQuality:(BOOL) yerOrNo;
{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
    if (yerOrNo) {
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetShouldAntialias(context, true);
        CGContextSetAllowsAntialiasing(context, true);
        CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
    }
    [tintColor setFill];
    CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height);
    UIRectFill(bounds);
    [self drawInRect:bounds blendMode:blendMode alpha:1.0f];

    if (blendMode != kCGBlendModeDestinationIn)
        [self drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0];

    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return tintedImage;
}

I've found this snippet on the internet but I don't remember where.

Andrea
  • 26,120
  • 10
  • 85
  • 131
2

Adding an answer based on J.Williams's answer - but updated for Swift 5, using a system image. Included all the layer setting up, etc. Hope this is useful! (Note: I think it's ridiculous that we can't just change the tint on an UIImage in a layer without jumping through a lot of crazy hoops like this)

    let image = UIImage(systemName: "plus.circle.fill")
    let circleLayer = CAShapeLayer()
    let circleDiameter: CGFloat = 20.0
    circleLayer.frame = CGRect(x: x - (circleDiameter / 2),
                               y: y - (circleDiameter / 2),
                               width: circleDiameter, height: circleDiameter)
    let maskLayer = CALayer()
    maskLayer.frame = circleLayer.bounds
    maskLayer.contents = image?.cgImage
    circleLayer.mask = maskLayer
    circleLayer.backgroundColor = UIColor.systemPurple.cgColor
    myView.layer.addSublayer(circleLayer)
N.W
  • 672
  • 2
  • 8
  • 19
-1

Referring to the comment above.

My code:

    button.backgroundColor = UIColor.withAlphaComponent(UIColor.white)(0.1)

    button.layer.cornerRadius = button.frame.size.height / 2

    button.layer.borderWidth = 3

    button.layer.borderColor = UIColor.white.cgColor

    button.layer.contents = UIImage(named: "buttonImage.png")?.cgImage

    button.layer.contentsGravity = kCAGravityCenter

    button.layer.magnificationFilter = kCAFilterLinear

    button.layer.isGeometryFlipped = false

Applying the solution:

let maskLayer = CALayer()

And finally:

layer.backgroundColor = UIColor.redColor().CGColor

The result is horrible.

The solution is on the link below (the link in the comment)

But I show my code (take it from link):

            let image_ = UIImage(named: "image.png")

            let maskImage = image_?.cgImage

            let width = image_?.size.width
            let height = image_?.size.height

            let bounds = CGRect(x: 0, y: 0, width: width!, height: height!)

            let colorSpace = CGColorSpaceCreateDeviceRGB()

            let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)

            let bitmapContext = CGContext(data: nil,
                                          width: Int(width!),
                                          height: Int(height!),
                                          bitsPerComponent: 8,
                                          bytesPerRow: 0,
                                          space: colorSpace,
                                          bitmapInfo: bitmapInfo.rawValue)

            bitmapContext?.clip(to: bounds, mask: maskImage!)

            bitmapContext?.setFillColor(UIColor.yellow.cgColor)

            bitmapContext?.fill(bounds)

            let cImage = bitmapContext?.makeImage()

            let coloredImage = UIImage(cgImage: cImage!)


            self.myUIButton.layer.contents = coloredImage.cgImage

Please, let me tell you something (is important) Do not play with:

  • image@2x.png
  • or image@3x.png

The image name "someImage.png" must be exactly the file name in your project folder.

Markus
  • 1,147
  • 16
  • 26
  • I found the solution and it works for me (almost for me) I attached the link: https://stackoverflow.com/questions/31803157/how-to-color-a-uiimage-in-swift/31803460#31803460 – Markus Aug 09 '17 at 14:34