¿Cómo puedo enmascarar un UIImageView?

Estoy tratando de enmascarar una imagen con algo como esto:

imagen que se enmascarará

¿Sería tan amable de ayudarme?

Estoy usando este código:

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

Hay una manera más fácil.

 #import  // remember to include Framework as well CALayer *mask = [CALayer layer]; mask.contents = (id)[[UIImage imageNamed:@"mask.png"] CGImage]; mask.frame = CGRectMake(0, 0, , ); yourImageView.layer.mask = mask; yourImageView.layer.masksToBounds = YES; 

Para Swift 4 y plus, siga el siguiente código

 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 

El tutorial utiliza este método con dos parámetros: image y maskImage , estos deben establecerse al llamar al método. Una llamada de ejemplo podría verse así, suponiendo que el método está en la misma clase y las imágenes están en su paquete:

Nota: sorprendentemente las imágenes ni siquiera tienen que ser del mismo tamaño.

 ... 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; } 

Después de que hayas proporcionado tu código, he agregado algunos números como comentarios para referencia. Aún tienes dos opciones. Todo esto es un método al que llamas en algún lugar. No es necesario que cree las imágenes en su interior: esto reduce la reutilización del método a cero.

Para hacer que tu código funcione Cambie la cabeza de métodos ( 1. ) a

 - (UIImage *)maskImageMyImages { 

Luego cambie el nombre de la variable en 2. a

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

El método devolverá las imágenes enmascaradas por lo que deberá llamar a este método en algún lugar. ¿Puede mostrarnos el código al que llama su método?

Intenté ambos códigos usando CALayer o CGImageCreateWithMask pero ninguno de ellos no funcionó para mí

¡Pero descubrí que el problema es con el formato de archivo png, NO con el código!
¡solo para compartir mi hallazgo!

Si quieres usar

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

debes usar png de 24 bits sin canal alfa

Si desea utilizar la máscara CALayer, debe usar png (24 bits u 8 bits) con canal alfa donde la parte transparente de su png enmascarará la imagen (para una máscara alfa de degradado suave … use png de 24 bits con canal alfa)

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

Esto funciona para mí

Swift 3 – La solución más simple que encontré

@IBDesignable un @IBDesignable para esto para que pudieras ver el efecto de inmediato en tu guión gráfico.

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

Cómo utilizar

  1. Crea un nuevo archivo y pega ese código arriba.
  2. Agregue UIImageView a su guión gráfico (asigne una imagen si lo desea).
  3. En Identity Inspector: cambie la clase personalizada a “UIImageViewWithMask” (nombre de clase personalizado más arriba).
  4. En Attributes Inspector: seleccione la imagen de máscara que desea usar.

Ejemplo

Enmascaramiento en Storyboard

Notas

  • La imagen de la máscara debe tener un fondo transparente (PNG) para la parte no negra.

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 } 

// para usar

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

Swift versión de la solución aceptada:

 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 } 

En caso de que alguien lo necesite.

Me funciona a la perfección.

descubrimos que la respuesta correcta no funciona ahora e implementaba una pequeña clase adicional, que ayuda a enmascarar cualquier imagen en UIImageView.

Está disponible aquí: https://github.com/Werbary/WBMaskedImageView

Ejemplo:

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