如何设置UIImage的不透明度/透明度?

89

我知道可以通过UIImageView实现这一点,但是能否对UIImage进行操作呢? 我想让UIImageView的动画图片数组属性成为相同图像的数组,但具有不同的透明度。 你有什么想法吗?

9个回答

124

我只需要做这个,但认为Steven的解决方案会很慢。这应该会利用图形硬件。在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;
}

3
我甚至都记不得为什么我需要这个了 :) - Marty
1
请确保您在主线程上调用UIGraphicsBeginImageContextWithOptions,因为后台渲染将是不可预测的。 - Steven Veltema
1
根据苹果的说法,自从 iOS 4 及以后版本,你可以在任何线程上调用 UIGraphicsBeginImageContextWithOptions 方法。 - Ants
6
非常好,非常感谢。对于其他新手来说,以下是创建UIImage分类的步骤:
  1. 在您的项目目录中右键单击,选择“新建文件”。
  2. 在出现的屏幕上,选择Objective-C类别文件类型。
  3. 在.m文件中添加答案代码以及对该方法的声明。
  4. 在使用图像进行透明处理的文件中,#import该文件。
  5. 对UIImage实例使用imageByApplyingAlpha方法。
- Danny
如果您正在寻找一种方法来将不透明度应用于UIImage,以便在导航栏中使用作为按钮(可能是高亮状态),那么请使用此解决方案。 在iOS 7.1中对我非常有效。 - Alex

81

设置其所显示视图的不透明度。

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

在动画中使用它。您可以在动画中更改alpha值并设置其持续时间。

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
//Set alpha
[UIView commitAnimations];

是的,我在想也许需要使用计时器来不断改变透明度,但我认为如果有一个动画图像数组属性,它就可以自动播放,这样会更容易些。 - Marty
你可以使用动画委托将其像心跳一样“向内”和“向外”进行动画处理。不要使用计时器,动画会平滑地改变alpha值。祝好运。 - Mats Stijlaart
3
只有开发者使用UIImageView才能起作用。问题明确说明这不是情况。 - Raul Huerta
1
这适用于在CALayer中呈现的UIImage,只需设置layer.opacity而无需修改图像即可。感谢Mats! - Chris
太棒了!可以在 UIButton 上使用,正是我所需要的。 - NecipAllef

61

基于Alexey Ishkov的答案,但用Swift实现

我使用了UIImage类的扩展。

Swift 2:

UIImage扩展:

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

使用方法:

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

Swift 3/4/5:

请注意,此实现返回可选的UIImage。这是因为在Swift 3中,UIGraphicsGetImageFromCurrentImageContext现在返回一个可选值。如果上下文为nil或未使用UIGraphicsBeginImageContext创建,则该值可能为空。

UIImage扩展:

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

使用方法:

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

我更喜欢这个 Swift 3 版本。 - AechoLiu
谢谢。在Swift 4中它的工作方式相同,我更新了答案以反映这一点。 - zeeshan
干得好,先生。 - Ryan Brodie

17

有更简单的解决方案:

- (UIImage *)tranlucentWithAlpha:(CGFloat)alpha
{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    [self drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:alpha];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

1
可能应该被接受为答案。获取结果的最快/最有效的方法。 - Will Von Ullrich

5

嘿,感谢来自Xamarin用户的支持! :) 下面是翻译成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;
        }

}

使用示例:

var MySupaImage = UIImage.FromBundle("opaquestuff.png").WithAlpha(0.15f);

4

我知道现在已经有点晚了,但是我需要类似的功能,因此我设计了一个快速且简单的方法来实现这个功能。

+ (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;
}

2
更好的名称应该是 setImage:withAlpha: - Alexander
9
“set”通常指代属性,以某种方式改变接收器的状态。将其命名为image:withAlpha:会更好吗? - Jonathan.
2
是的。同时,调用 set 方法会将相同的对象应用于设置,而不是返回一个新图像。 - some_id

4

与其他人相同的结果,不同的风格:

extension UIImage {

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

}

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()
  }
}

0

如果你正在尝试使用Metal渲染,并提取由imageByApplyingAlpha生成的CGImage,你可能会得到比预期更大的Metal渲染结果。在使用Metal进行实验时,你可能想要改变imageByApplyingAlpha中的一行代码:

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

如果您使用的是缩放因子为3.0的设备,如iPhone 11 Pro Max,则上面显示的0.0缩放因子将给您一个比您预期的大三倍的CGImage。将缩放因子更改为1.0应该避免任何缩放。

希望这个答复能够为初学者节省很多困扰。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接