如何遮罩UIImageView?


100

我正在尝试使用以下方式遮盖图像:

要掩盖的图像

你能帮我吗?

我正在使用此代码:

- (void) viewDidLoad {
    UIImage *OrigImage = [UIImage imageNamed:@"dogs.png"];
    UIImage *mask = [UIImage imageNamed:@"mask.png"];
    UIImage *maskedImage = [self maskImage:OrigImage withMask:mask];
    myUIIMage.image = maskedImage;
}

27
我是撰写原始教程的人。蒙版图像只是我在photoshop中创建的简单灰度图像。没什么特别的。黑色区域成为蒙版的“透明”部分。请记住,任何灰色阴影都被解释为一定程度的不透明度。以这种方式,遮罩也可以是渐变的,这对于在遮罩周围创建较柔和的边界很有用。
ra9r

大小必须相同,对不对?
KarenAnne

超优雅的代码,谢谢。只是如果有人需要前屏蔽...裁剪图像有用的链接stackoverflow.com/questions/17712797/...
Fattie


1
我敦促您将选择的答案更改为几乎3倍的投票数。我认为这在几乎所有方面都更好。
艾伯特·伦肖

Answers:


163

有一种更简单的方法。

#import <QuartzCore/QuartzCore.h>
// remember to include Framework as well

CALayer *mask = [CALayer layer];
mask.contents = (id)[[UIImage imageNamed:@"mask.png"] CGImage];
mask.frame = CGRectMake(0, 0, <img_width>, <img_height>);
yourImageView.layer.mask = mask;
yourImageView.layer.masksToBounds = YES;

对于Swift 4及更高版本,请遵循以下代码

let mask = CALayer()
mask.contents =  [ UIImage(named: "right_challenge_bg")?.cgImage] as Any
mask.frame = CGRect(x: 0, y: 0, width: leftBGImage.frame.size.width, height: leftBGImage.frame.size.height)
leftBGImage.layer.mask = mask
leftBGImage.layer.masksToBounds = true

1
谢谢,但是我把这段代码放在上面,viewDidLoad但是什么也没发生!
Mc.Lover 2011年

6
您应该将layer属性设置为使用遮罩,即[yourImageView.layer setMasksToBounds:YES];
Wolfgang Schreurs,

3
请注意,对于此解决方案,这必须是UIImageView。另一种解决方案仅适用于UIImage。
2012年

1
我尝试了这种方法,但是在iOS 8中似乎无法使用
bdv 2014年

2
对于Swift代码,当将其放入mask.contents时,应使用CGImage。不是[CGImage]。如果使用括号[],则表示数组。
草莓草木

59

本教程将此方法与两个参数一起使用:imagemaskImage,在调用该方法时必须设置这些参数。假设方法在同一个类中,并且图片在您的包中,则示例调用可能看起来像这样:

注意-令人惊讶的是,图像甚至不必具有相同的大小。

...
UIImage *image = [UIImage imageNamed:@"dogs.png"];
UIImage *mask = [UIImage imageNamed:@"mask.png"];

// result of the masking method
UIImage *maskedImage = [self maskImage:image withMask:mask];

...

- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {

    CGImageRef maskRef = maskImage.CGImage; 

    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
        CGImageGetHeight(maskRef),
        CGImageGetBitsPerComponent(maskRef),
        CGImageGetBitsPerPixel(maskRef),
        CGImageGetBytesPerRow(maskRef),
        CGImageGetDataProvider(maskRef), NULL, false);

    CGImageRef maskedImageRef = CGImageCreateWithMask([image CGImage], mask);
    UIImage *maskedImage = [UIImage imageWithCGImage:maskedImageRef];

    CGImageRelease(mask);
    CGImageRelease(maskedImageRef);

    // returns new image with mask applied
    return maskedImage;
}

提供代码后,我在其中添加了一些数字作为注释,以供参考。您仍然有两个选择。整个过程是一个方法,您正在某个地方调用它。您无需在其中创建图像:这会将方法的可重用性降低为零。

使您的代码正常工作。将方法标题(1.)更改为

- (UIImage *)maskImageMyImages {

然后在2中将变量的名称更改为

UIImage *maskImage = [UIImage imageNamed:@"mask.png"];

该方法将返回蒙版图像,因此您必须在某个位置调用此方法。您能告诉我们您调用方法的代码吗?


对不起!应该在哪里写UIImage *image代码?!!! 因为在-(UIimage *) maskeImage编译器上会给出重新定义错误!
Mc.Lover

抱歉,请为我上传示例代码?Iam感到困惑:-s
McLover 2011年

1
不可能,一切都在那里。您必须向我们展示如何调用此方法,或者至少告诉您要遮罩图像并显示结果的部分。
Nick Weaver

我的问题是调用它,应该是这样吗?(viewDidLoad中):看到我编辑的代码
Mc.Lover

关于反向蒙版的任何想法。(上述过程的反向)。
米兰patel

16

Swift 3-我发现的最简单的解决方案

@IBDesignable为此创建了一个,因此您可以立即在情节提要上看到效果。

import UIKit

@IBDesignable
class UIImageViewWithMask: UIImageView {
    var maskImageView = UIImageView()

    @IBInspectable
    var maskImage: UIImage? {
        didSet {
            maskImageView.image = maskImage
            updateView()
        }
    }

    // This updates mask size when changing device orientation (portrait/landscape)
    override func layoutSubviews() {
        super.layoutSubviews()
        updateView()
    }

    func updateView() {
        if maskImageView.image != nil {
            maskImageView.frame = bounds
            mask = maskImageView
        }
    }
} 

如何使用

  1. 创建一个新文件并粘贴上面的代码。
  2. 将UIImageView添加到情节提要(如果需要,分配图像)。
  3. 在Identity Inspector上:将自定义类更改为“ UIImageViewWithMask”(上面的自定义类名称)。
  4. 在“属性”检查器上:选择要使用的蒙版图像。

故事板上的遮罩

笔记

  • 蒙版图像的非黑色部分应具有透明背景(PNG)。

12

我使用CALayer或CGImageCreateWithMask尝试了这两个代码,但是它们都不适合我

但是我发现问题出在png文件格式,而不是代码!
所以只是分享我的发现!

如果要使用

- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage

您必须使用没有 alpha通道的24位 png

如果要使用CALayer蒙版,则必须 alpha通道使用(24位或8位)png 其中png的透明部分将蒙版图像(对于平滑渐变alpha蒙版。对于alpha通道使用24位png)


10
- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

        CGImageRef maskImageRef = [maskImage CGImage];

        // create a bitmap graphics context the size of the image
        CGContextRef mainViewContentContext = CGBitmapContextCreate (NULL, maskImage.size.width, maskImage.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
        CGColorSpaceRelease(colorSpace);

        if (mainViewContentContext==NULL)
            return NULL;

        CGFloat ratio = 0;

        ratio = maskImage.size.width/ image.size.width;

        if(ratio * image.size.height < maskImage.size.height) {
            ratio = maskImage.size.height/ image.size.height;
        }

        CGRect rect1  = {{0, 0}, {maskImage.size.width, maskImage.size.height}};
        CGRect rect2  = {{-((image.size.width*ratio)-maskImage.size.width)/2 , -((image.size.height*ratio)-maskImage.size.height)/2}, {image.size.width*ratio, image.size.height*ratio}};


        CGContextClipToMask(mainViewContentContext, rect1, maskImageRef);
        CGContextDrawImage(mainViewContentContext, rect2, image.CGImage);


        // Create CGImageRef of the main view bitmap content, and then
        // release that bitmap context
        CGImageRef newImage = CGBitmapContextCreateImage(mainViewContentContext);
        CGContextRelease(mainViewContentContext);

        UIImage *theImage = [UIImage imageWithCGImage:newImage];

        CGImageRelease(newImage);

        // return the image
        return theImage;
}

这对我有用。


谢谢您,这个答案比其他人关于图像越来越大的性能更好。
Radu Ursache 2014年

1
关于反向蒙版的任何想法。(上述过程的反向)。意味着我想删除填充区域(使其透明)和带填充的透明区域。
米兰patel

谢谢,这段代码比第一个更好!但是我有两个麻烦:关于“ kCGImageAlphaPremultipliedLast”的警告(我将其强制转换为“ CGBitmapInfo”以进行修复),并且不适用于视网膜图像!你能帮我吗?? ...
fingerup 2015年

@Milanpatel简单的解决方案是简单地反转蒙版图像中的颜色。:)
Dids 2015年

@ZyiOS如何自定义蒙版图像的框架。也就是说,用户可以增加或减少蒙版图像的大小。
Dalvik

8

SWIFT 3 XCODE 8.1

func maskImage(image: UIImage, withMask maskImage: UIImage) -> UIImage {

    let maskRef = maskImage.cgImage

    let mask = CGImage(
        maskWidth: maskRef!.width,
        height: maskRef!.height,
        bitsPerComponent: maskRef!.bitsPerComponent,
        bitsPerPixel: maskRef!.bitsPerPixel,
        bytesPerRow: maskRef!.bytesPerRow,
        provider: maskRef!.dataProvider!,
        decode: nil,
        shouldInterpolate: false)

    let masked = image.cgImage!.masking(mask!)
    let maskedImage = UIImage(cgImage: masked!)

    // No need to release. Core Foundation objects are automatically memory managed.

    return maskedImage

}

// 用来

testImage.image = maskImage(image: UIImage(named: "OriginalImage")!, withMask: UIImage(named: "maskImage")!)

你能给我照片吗?
艾哈迈德·萨法迪

3

接受解决方案的Swift版本:

func maskImage(image: UIImage, withMask maskImage: UIImage) -> UIImage {

    let maskRef = maskImage.CGImage

    let mask = CGImageMaskCreate(
        CGImageGetWidth(maskRef),
        CGImageGetHeight(maskRef),
        CGImageGetBitsPerComponent(maskRef),
        CGImageGetBitsPerPixel(maskRef),
        CGImageGetBytesPerRow(maskRef),
        CGImageGetDataProvider(maskRef),
        nil,
        false)

    let masked = CGImageCreateWithMask(image.CGImage, mask)
    let maskedImage = UIImage(CGImage: masked)!

    // No need to release. Core Foundation objects are automatically memory managed.

    return maskedImage

}

以防万一有人需要它。

它为我完美地工作。


你有这个的Swift 3.0版本吗?
Van Du Tran

2

我们发现,正确的答案现在无法正常工作,并实现了少量的插入式类,这有助于掩盖UIImageView中的任何图像。

它可以在这里找到:https : //github.com/Werbary/WBMaskedImageView

例:

WBMaskedImageView *imgView = [[WBMaskedImageView alloc] initWithFrame:frame];
imgView.originalImage = [UIImage imageNamed:@"original_image.png"];
imgView.maskImage = [UIImage imageNamed:@"mask_image.png"];

1
好一个!真的有帮助。
abhimuralidharan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.