Cómo enmascarar un UIImageView

Estoy tratando de enmascarar una image como esta:

introduzca la descripción de la imagen aquí

Encontré este tutorial pero no mencionó dónde puedo encontrar Image.png o Image.png .

TUTORIAL

¿Sería tan amable de ayudarme?

EDITAR :

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

El tutorial usa este método con dos parameters: image y maskImage , estos deben configurarse cuando llame al método. Una llamada de ejemplo podría verse así, suponiendo que el método está en la misma class y las imágenes están en su package:

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 proporcionar su código, agregué algunos numbers como comentarios para reference. Todavía tienes dos opciones. Todo esto es un método al que estás llamando en alguna parte. No necesita crear las imágenes dentro de él: esto networkinguce la reutilización del método a cero.

Para que su código funcione. Cambia el encabezado de methods ( 1. ) a

 - (UIImage *)maskImageMyImages { 

Luego, cambia 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 tendrá que llamar a este método en algún lugar. ¿Nos puede mostrar el código al que llama su método?

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

¡Pero descubrí que el problema está en el formatting de file png, NO en el código!
¡Solo para compartir mi hallazgo!

Si quieres usar

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

debe usar png de 24 bits sin canal alfa

Si desea usar la máscara CALayer, debe usar un png (24 bits o 8 bits) con un canal alfa en el que la parte transparente de su PNG enmascarará la image (para una máscara alfa gradual suave … use un png de 24 bits con un 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 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")!) 

Versión rápida 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 } 

Solo en caso de que alguien lo necesite.

Está funcionando para mí sin problemas.

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 storyboard.

 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. Cree un file nuevo y péguelo en ese código anterior.
  2. Agregue UIImageView a su guión gráfico (asigne una image si lo desea).
  3. En Identity Inspector: Cambie la class personalizada a "UIImageViewWithMask" (nombre de class personalizado arriba).
  4. En el Inspector de attributes: Seleccione la image de máscara que desee usar.

Ejemplo

Enmascaramiento en Storyboard

Notas

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

descubrimos que la respuesta correcta no funciona ahora e implementó una pequeña class drop-in, que ayuda a enmascarar cualquier image 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"];