web-dev-qa-db-fra.com

Comment masquer un UIImageView?

J'essaie de masquer une image avec quelque chose comme ceci:

image to be masked

Pourriez vous m'aider s'il vous plait?

J'utilise ce code:

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

Il y a un moyen plus facile.

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

Pour Swift 4 et plus suivent le code ci-dessous

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
160

Le tutoriel utilise cette méthode avec deux paramètres: image et maskImage, vous devez les définir lorsque vous appelez la méthode. Un exemple d'appel pourrait ressembler à ceci, en supposant que la méthode est dans la même classe et que les images sont dans votre bundle:

Remarque - étonnamment, les images n'ont même pas besoin d'être de la même taille.

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

Après avoir fourni votre code, j’ai ajouté quelques chiffres sous forme de commentaires pour référence. Vous avez encore deux options. Toute cette affaire est une méthode que vous appelez quelque part. Vous n'avez pas besoin de créer les images qu'il contient: cela réduit à zéro la possibilité de réutilisation de la méthode.

Pour que votre code fonctionne. Modifiez les méthodes head (1.) en

- (UIImage *)maskImageMyImages {

Puis changez le nom de la variable dans 2. en

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

La méthode retournera vos images masquées, vous devrez donc appeler cette méthode quelque part. Pouvez-vous nous montrer le code où vous appelez votre méthode?

59
Nick Weaver

Swift 3 - La solution la plus simple que j'ai trouvée

J'ai créé un @IBDesignable pour que vous puissiez voir l'effet tout de suite sur votre story-board.

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

Comment utiliser

  1. Créez un nouveau fichier et collez-le dans le code ci-dessus.
  2. Ajoutez UIImageView à votre scénario (attribuez une image si vous le souhaitez).
  3. Sur l’inspecteur d’identité: Modifiez la classe personnalisée en "UIImageViewWithMask" (nom de la classe personnalisée ci-dessus).
  4. Inspecteur d'attributs: sélectionnez l'image de masque que vous souhaitez utiliser.

Exemple

Masking on Storyboard

Remarques

  • Votre image de masque doit avoir un fond transparent (PNG) pour la partie non noire.
13
Mark Moeykens

J'ai essayé les deux codes avec CALayer ou CGImageCreateWithMask mais aucun d'entre eux n'a fonctionné pour moi

Mais j'ai découvert que le problème est avec le format de fichier png, pas le code !!
donc juste pour partager ma découverte!

Si vous voulez utiliser

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

vous devez utiliser 24bit png sans canal alpha

Si vous souhaitez utiliser le masque CALayer, vous devez utiliser (24 bits ou 8 bits) png avec le canal alpha où une partie transparente de votre png masquera l’image (pour un masque de dégradé lisse dégradé .. utilisez un png 24 bits avec alpha canal)

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

Cela fonctionne pour moi.

10
ZYiOS

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

}

// pour utilisation

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

Version rapide de la solution acceptée:

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

}

Juste au cas où quelqu'un en aurait besoin.

Cela fonctionne parfaitement pour moi.

3
Juan Valera

nous avons constaté que la réponse correcte ne fonctionnait pas maintenant et mis en œuvre une petite classe à accès restreint, ce qui permet de masquer une image dans UIImageView.

Il est disponible ici: https://github.com/Werbary/WBMaskedImageView

Exemple:

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