How to set the opacity/alpha of a UIImage?
Asked Answered
B

9

89

I know you can do this with a UIImageView, but can it be done to a UIImage? I want to have the animation images array property of a UIImageView to be an array of the same image but with different opacities. Thoughts?

Brandebrandea answered 22/2, 2011 at 22:35 Comment(0)
H
124

I just needed to do this, but thought Steven's solution would be slow. This should hopefully use graphics HW. Create a category on UIImage:

- (UIImage *)imageByApplyingAlpha:(CGFloat) alpha {
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGRect area = CGRectMake(0, 0, self.size.width, self.size.height);

    CGContextScaleCTM(ctx, 1, -1);
    CGContextTranslateCTM(ctx, 0, -area.size.height);

    CGContextSetBlendMode(ctx, kCGBlendModeMultiply);

    CGContextSetAlpha(ctx, alpha);

    CGContextDrawImage(ctx, area, self.CGImage);

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return newImage;
}
Howsoever answered 30/5, 2012 at 15:11 Comment(5)
can't even remember why i needed this :)Brandebrandea
Just be sure that you are calling UIGraphicsBeginImageContextWithOptions on the main thread because background rendering will be unpredictable.Austenite
According to Apple you can call UIGraphicsBeginImageContextWithOptions on any thread since iOS 4 and later.Pagandom
Works great, thanks a ton. For other newbies to the logistics around iOS development, here are the steps to making a category for UIImage. 1. Right click in your project's director and select New File. 2. In the screen that appears, select the Objective-C category file type. 3. Add the answer's code in the .m file and a declaration for the method in the .h file. 4. In the file that uses the image to be transparent, #import the file. 5. Use the method imageByApplyingAlpha on an instance of a UIImage.Donald
If you're looking for a solution to apply opacity to an UIImage, which you want to use as a button in a navigation bar (probably for the highlighted state), then use this solution. Worked perfect for me in iOS 7.1.Stapleton
P
81

Set the opacity of its view it is showed in.

UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageWithName:@"SomeName.png"]];
imageView.alpha = 0.5; //Alpha runs from 0.0 to 1.0

Use this in an animation. You can change the alpha in an animation for an duration.

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
//Set alpha
[UIView commitAnimations];
Petiolule answered 22/2, 2011 at 22:39 Comment(5)
yeah i was thinking i might have to do it like this with a timer to change the opacity constantly, just thought it would be much easier to have an array for the animation images array property so it would animate on its own.Brandebrandea
You can animate it 'in' and 'out' like an heartbeat with the animation delegate. Don't use a timer, the animation will change the alpha smoothly. Good luck.Petiolule
This only works if the developer is using a UIImageView. The question clearly says that's not the case.Seedman
This works with a UIImage presented in a CALayer, only you set layer.opacity without having to modify the image at all. Thanks Mats!Sunburst
Great! Works on UIButton, exactly what I needed.Knickerbocker
U
61

Based on Alexey Ishkov's answer, but in Swift

I used an extension of the UIImage class.

Swift 2:

UIImage Extension:

extension UIImage {
    func imageWithAlpha(alpha: CGFloat) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        drawAtPoint(CGPointZero, blendMode: .Normal, alpha: alpha)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
}

To use:

let image = UIImage(named: "my_image")
let transparentImage = image.imageWithAlpha(0.5)

Swift 3/4/5:

Note that this implementation returns an optional UIImage. This is because in Swift 3 UIGraphicsGetImageFromCurrentImageContext now returns an optional. This value could be nil if the context is nil or what not created with UIGraphicsBeginImageContext.

UIImage Extension:

extension UIImage {
    func image(alpha: CGFloat) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        draw(at: .zero, blendMode: .normal, alpha: alpha)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
}

To use:

let image = UIImage(named: "my_image")
let transparentImage = image?.image(alpha: 0.5)
Ukulele answered 21/6, 2016 at 22:21 Comment(3)
I prefer this Swift 3 version.Chelton
Thanks. It works the same in Swift 4, I updated the answer to reflect this.Nonflammable
Bravo sir, bravoDedie
S
17

there is much easier solution:

- (UIImage *)tranlucentWithAlpha:(CGFloat)alpha
{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    [self drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:alpha];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
Sculptor answered 7/11, 2015 at 20:45 Comment(1)
Probably should have been the accepted answer. Fastest / most efficient way to get the resultAristarchus
M
6

Hey hey thanks from Xamarin user! :) Here it goes translated to c#

//***************************************************************************
public static class ImageExtensions
//***************************************************************************
{
    //-------------------------------------------------------------
    public static UIImage WithAlpha(this UIImage image, float alpha)  
    //-------------------------------------------------------------
        {
        UIGraphics.BeginImageContextWithOptions(image.Size,false,image.CurrentScale);
        image.Draw(CGPoint.Empty, CGBlendMode.Normal, alpha);
        var newImage = UIGraphics.GetImageFromCurrentImageContext();
        UIGraphics.EndImageContext();
        return newImage;
        }

}

Usage example:

var MySupaImage = UIImage.FromBundle("opaquestuff.png").WithAlpha(0.15f);
Metronymic answered 11/6, 2017 at 22:17 Comment(0)
A
4

I realize this is quite late, but I needed something like this so I whipped up a quick and dirty method to do this.

+ (UIImage *) image:(UIImage *)image withAlpha:(CGFloat)alpha{

    // Create a pixel buffer in an easy to use format
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    UInt8 * m_PixelBuf = malloc(sizeof(UInt8) * height * width * 4);

    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(m_PixelBuf, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    //alter the alpha
    int length = height * width * 4;
    for (int i=0; i<length; i+=4)
    {
        m_PixelBuf[i+3] =  255*alpha;
    }


    //create a new image
    CGContextRef ctx = CGBitmapContextCreate(m_PixelBuf, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGImageRef newImgRef = CGBitmapContextCreateImage(ctx);  
    CGColorSpaceRelease(colorSpace);
    CGContextRelease(ctx);  
    free(m_PixelBuf);

    UIImage *finalImage = [UIImage imageWithCGImage:newImgRef];
    CGImageRelease(newImgRef);  

    return finalImage;
}
Austenite answered 8/5, 2012 at 3:41 Comment(3)
Better name would be setImage:withAlpha:Newsworthy
set usually refer to properties, in some way changing the receiver's state. it would be better to name it image:withAlpha:?Photomultiplier
Yeah. Also calling set applies setting the same object passed in, rather than returning a new image.Cubby
I
4

same result as others, different style:

extension UIImage {

    func withAlpha(_ alpha: CGFloat) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { _ in
            draw(at: .zero, blendMode: .normal, alpha: alpha)
        }
    }

}
Instanter answered 19/2, 2020 at 11:47 Comment(0)
O
3

Swift 5:

extension UIImage {
  func withAlphaComponent(_ alpha: CGFloat) -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(size, false, scale)
    defer { UIGraphicsEndImageContext() }

    draw(at: .zero, blendMode: .normal, alpha: alpha)
    return UIGraphicsGetImageFromCurrentImageContext()
  }
}
Olvan answered 21/6, 2020 at 22:6 Comment(0)
S
0

If you're experimenting with Metal rendering & you're extracting the CGImage generated by imageByApplyingAlpha in the first reply, you may end up with a Metal rendering that's larger than you expect. While experimenting with Metal, you may want to change one line of code in imageByApplyingAlpha:

    UIGraphicsBeginImageContextWithOptions (self.size, NO, 1.0f);
//  UIGraphicsBeginImageContextWithOptions (self.size, NO, 0.0f);

If you're using a device with a scale factor of 3.0, like the iPhone 11 Pro Max, the 0.0 scale factor shown above will give you an CGImage that's three times larger than you're expecting. Changing the scale factor to 1.0 should avoid any scaling.

Hopefully, this reply will save beginners a lot of aggravation.

Schnorkle answered 30/3, 2020 at 21:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.