Come posso mascherare un UIImageView?


100

Sto cercando di mascherare un'immagine con qualcosa del genere:

immagine da mascherare

Mi aiuterebbe per favore?

Sto usando questo codice:

- (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
Sono la persona che ha scritto il tutorial originale. L'immagine della maschera è solo una semplice immagine in scala di grigi che ho creato in Photoshop. Niente di speciale. L'area nera diventa la parte "trasparente" della maschera. Tieni presente che qualsiasi sfumatura di grigio viene interpretata come un grado di opacità. In questo modo, anche le maschere possono essere sfumature utili per creare bordi più morbidi attorno a una maschera.
ra9r

Deve essere della stessa dimensione, giusto?
KarenAnne

codice iperelegante, grazie. solo un link utile se qualcuno ha bisogno di ritagliare un'immagine prima di mascheramento ... stackoverflow.com/questions/17712797/...
Fattie


1
Ti esorto a cambiare la risposta selezionata con quella con quasi 3 volte più voti positivi. Secondo me è meglio quasi in ogni modo.
Albert Renshaw

Risposte:


165

C'è un modo più semplice.

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

Per Swift 4 e plus segui il codice di seguito

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
grazie ma ho inserito questo codice viewDidLoadma non è successo niente!
Mc Lover

6
Dovresti impostare la proprietà del livello per usare la maschera, cioè [yourImageView.layer setMasksToBounds: YES];
Wolfgang Schreurs

3
Si noti che questo è necessario per essere un UIImageView per questa soluzione. L'altra soluzione funziona solo con un UIImage.
adriendenat

1
Ho provato questo approccio ma sembra non funzionare in iOS 8
bdv

2
Per il codice Swift, quando inserito in mask.contents, dovrebbe CGImage. Non [CGImage]. Se usa la parentesi [], significa Array.
strawnut

59

Il tutorial utilizza questo metodo con due parametri: imagee maskImage, questi devi impostare quando chiami il metodo. Una chiamata di esempio potrebbe essere simile a questa, supponendo che il metodo sia nella stessa classe e le immagini siano nel tuo pacchetto:

Nota: sorprendentemente le immagini non devono nemmeno avere le stesse dimensioni.

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

Dopo aver fornito il codice, ho aggiunto alcuni numeri come commenti per riferimento. Hai ancora due opzioni. Tutta questa cosa è un metodo, che stai chiamando da qualche parte. Non è necessario creare le immagini al suo interno: questo riduce a zero la riusabilità del metodo.

Per far funzionare il tuo codice. Modificare la testa dei metodi ( 1. ) in

- (UIImage *)maskImageMyImages {

Quindi modificare il nome della variabile in 2. in

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

Il metodo restituirà le tue immagini mascherate, quindi dovrai chiamare questo metodo da qualche parte. Puoi mostrarci il codice dove stai chiamando il tuo metodo?


spiacente ! dove dovrebbe scrivere il UIImage *imagecodice? !!! perché sul -(UIimage *) maskeImagecompilatore dà errore di ridefinizione!
Mc Lover

scusa potresti caricare un codice di esempio per me? Sono confuso: -s
Mc Lover,

1
Non è possibile, è tutto lì. Dovrai mostrarci come stai chiamando questo metodo, o almeno la parte in cui vorresti mascherare le tue immagini e mostrare il risultato.
Nick Weaver

il mio problema è chiamarlo, dovrebbe essere qualcosa del genere ?? (viewDidLoad): vedi il mio codice modificato
Mc.Lover

Qualche idea sul mascheramento inverso (processo inverso) Significa che voglio rimuovere l'area di riempimento (renderla trasparente) e l'area trasparente con riempimento.
Milan patel

17

Swift 3 - La soluzione più semplice che ho trovato

Ne ho creato uno @IBDesignableper questo in modo che tu possa vedere subito l'effetto sul tuo 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
        }
    }
} 

Come usare

  1. Crea un nuovo file e incolla il codice sopra.
  2. Aggiungi UIImageView al tuo storyboard (assegna un'immagine se lo desideri).
  3. In Identity Inspector: cambia la classe personalizzata in "UIImageViewWithMask" (nome della classe personalizzata sopra).
  4. Nell'ispettore degli attributi: seleziona l'immagine della maschera che desideri utilizzare.

Esempio

Mascheramento sullo Storyboard

Appunti

  • L'immagine della maschera dovrebbe avere uno sfondo trasparente (PNG) per la parte non nera.

12

Ho provato entrambi i codici utilizzando CALayer o CGImageCreateWithMask ma nessuno di loro non ha funzionato per me

Ma ho scoperto che il problema è con il formato di file png, NON il codice !!
quindi solo per condividere la mia scoperta!

Se vuoi usare

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

è necessario utilizzare png a 24 bit senza canale alfa

Se vuoi usare la maschera CALayer, devi usare png (24 bit o 8 bit) con canale alfa dove la parte trasparente del tuo png maschererà l'immagine (per maschera alfa sfumata uniforme .. usa png 24 bit con canale alfa)


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

Questo funziona per me.


grazie, questa risposta è migliore di quella di altri che parlano di prestazioni con immagini sempre più grandi.
Radu Ursache

1
Qualche idea sul mascheramento inverso (processo inverso) Significa che voglio rimuovere l'area di riempimento (renderla trasparente) e l'area trasparente con riempimento.
Milan patel

Grazie, questo codice funziona meglio del primo !! Ma ho due problemi: Avviso su "kCGImageAlphaPremultipliedLast" (ho eseguito il cast su "CGBitmapInfo" per risolverlo) E non funziona per le immagini retina !! puoi aiutarmi ?? ...
fingerup

@Milanpatel La soluzione facile è semplicemente invertire i colori nell'immagine della maschera. :)
Dids

@ZyiOS come posso personalizzare la cornice dell'immagine mascherata. cioè l'utente può aumentare o diminuire la dimensione dell'immagine mascherata.
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

}

// per uso

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

puoi darmi la foto
Ahmed Safadi

3

Versione rapida della soluzione accettata:

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

}

Nel caso qualcuno ne avesse bisogno.

Funziona perfettamente per me.


Hai una versione Swift 3.0 di questo?
Van Du Tran

2

abbiamo scoperto che la risposta corretta ora non funziona e abbiamo implementato una piccola classe drop-in, che aiuta a mascherare qualsiasi immagine in UIImageView.

È disponibile qui: https://github.com/Werbary/WBMaskedImageView

Esempio:

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

1
Buono! Ha davvero aiutato.
abhimuralidharan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.