Bir UIImageView'ı nasıl maskeleyebilirim?


100

Böyle bir şeyle bir görüntüyü maskelemeye çalışıyorum:

maskelenecek görüntü

Bana yardım edebilir misiniz?

Bu kodu kullanıyorum:

- (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
Orijinal öğreticiyi yazan kişi benim. Maske görüntüsü, Photoshop'ta oluşturduğum basit bir gri tonlamalı görüntü. Onunla ilgili özel bir şey yok. Siyah alan, maskenin "şeffaf" kısmı haline gelir. Herhangi bir gri tonunun opaklık derecesi olarak yorumlandığını unutmayın. Bu şekilde, maskeler degradeler olabilir ve bu, bir maske etrafında daha yumuşak kenarlıklar oluşturmak için yararlıdır.
ra9r

Bu aynı boyutta olmalı, değil mi?
KarenAnne

son derece zarif kod, teşekkürler. herhangi birinin maskelemeden önce bir resmi
kırpması

Bununla ilgili herhangi bir fikir .. stackoverflow.com/questions/28122370/…
Milan patel

1
Seçtiğiniz yanıtı neredeyse 3 kat daha fazla oyla değiştirmenizi rica ediyorum. Bence her yönden daha iyi.
Albert Renshaw

Yanıtlar:


165

Daha kolay bir yol var.

#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 ve plus için aşağıdaki kodu izleyin

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
teşekkür ederim ama bu kodu koydum viewDidLoadama hiçbir şey olmadı!
Mc.Lover

6
Maskeyi kullanmak için katman özelliğini ayarlamalısınız, yani [yourImageView.layer setMasksToBounds: YES];
Wolfgang Schreurs

3
Bunun, bu çözüm için UIImageView olması gerektiğine dikkat edin. Diğer çözüm yalnızca bir UIImage ile çalışır.
adriendenat

1
Bu yaklaşımı denedim ancak bu iOS 8'de çalışmıyor gibi görünüyor
bdv

2
Swift kodu için mask.contents içine koyulduğunda CGImage olmalıdır. [CGImage] değil. Parantez [] kullanırsanız, Dizi anlamına gelir.
2019

59

Öğretici bu yöntemi iki parametreyle kullanır: imageve maskImagebunları, yöntemi çağırdığınızda ayarlamanız gerekir. Yöntemin aynı sınıfta olduğunu ve resimlerin paketinizde olduğunu varsayarak, örnek bir çağrı şöyle görünebilir:

Not - şaşırtıcı bir şekilde görüntülerin aynı boyutta olması bile gerekmez.

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

Kodunuzu verdikten sonra, referans olması için yorum olarak bazı numaralar ekledim. Hala iki seçeneğiniz var. Bütün bunlar bir yerde aradığınız bir yöntem. İçindeki görüntüleri yaratmanıza gerek yoktur: bu, yöntemin yeniden kullanılabilirliğini sıfıra indirir.

Kodunuzun çalışmasını sağlamak için. Yöntem başlığını ( 1. ) olarak değiştirin.

- (UIImage *)maskImageMyImages {

Ardından 2. adımda değişkenin adını değiştirin .

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

Yöntem, maskelenmiş görüntülerinizi geri döndürecektir, böylece bu yöntemi bir yerde çağırmanız gerekecektir. Metodunuzu çağırdığınız kodu bize gösterebilir misiniz?


afedersiniz ! UIImage *imagekodu nereye yazmalı ? !!! çünkü -(UIimage *) maskeImagederleyicide yeniden tanımlama hatası veriyor!
Mc.Lover

pardon lütfen benim için bir örnek kod yükler misiniz? Kafam karıştı: -s
Mc.Lover

1
Mümkün değil, her şey var. Bize bu yöntemi nasıl adlandırdığınızı veya en azından resimlerinizi maskelemek ve sonucu göstermek istediğiniz kısmı göstermeniz gerekecek.
Nick Weaver

benim problemim onu ​​aramak, böyle bir şey mi olmalı ?? (viewDidLoad): düzenlenmiş
koduma

Ters maskeleme hakkında herhangi bir fikir. (Yukarıdaki işlemin tersi) .Doldurma alanını (saydam yap) ve Dolgulu Şeffaf alanı kaldırmak istediğim anlamına gelir.
Milan patel

17

Swift 3 - Bulduğum En Basit Çözüm

Bunun için bir tane oluşturdum, @IBDesignableböylece efektleri film şeridinizde hemen görebilirsiniz.

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

Nasıl kullanılır

  1. Yeni bir dosya oluşturun ve yukarıdaki kodu yapıştırın.
  2. UIImageView'ı film şeridinize ekleyin (isterseniz bir görüntü atayın).
  3. Identity Inspector'da: Özel sınıfı "UIImageViewWithMask" olarak değiştirin (yukarıdaki özel sınıf adı).
  4. Attributes Inspector'da: Kullanmak istediğiniz maske görüntüsünü seçin.

Misal

Storyboard'da Maskeleme

Notlar

  • Maske görüntünüzün siyah olmayan kısım için şeffaf bir arka planı (PNG) olmalıdır.

12

Her iki kodu da CALayer veya CGImageCreateWithMask kullanarak denedim ama hiçbiri benim için çalışmadı

Ama sorunun kodda DEĞİL, png dosya formatında olduğunu öğrendim!
bu yüzden sadece bulduğumu paylaşmak için!

Kullanmak istersen

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

Eğer kullanmalıdır 24bit png olmadan alfa kanalı

CALayer maskesini kullanmak istiyorsanız, png'nizin şeffaf kısmının görüntüyü maskeleyeceği alfa kanalı ile (24bit veya 8bit) png kullanmanız gerekir (yumuşak gradyan alfa maskesi için .. alfa kanalı ile 24 bit png kullanın)


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

Bu benim için çalışıyor.


teşekkür ederim, bu cevap, başkalarının gittikçe daha büyük resimlerle performans hakkında konuşmasından daha iyidir.
Radu Ursache

1
Ters maskeleme hakkında herhangi bir fikir. (Yukarıdaki işlemin tersi) .Doldurma alanını (saydam yap) ve Dolgulu Şeffaf alanı kaldırmak istediğim anlamına gelir.
Milan patel

Teşekkürler, bu kod ilkinden daha iyi çalışıyor !! Ama iki sorunum var: "kCGImageAlphaPremultipliedLast" ile ilgili uyarı (düzeltmek için "CGBitmapInfo" ya atıyorum) VE retina görüntüleri için çalışmıyor !! bana yardım edebilir misin ?? ...
parmak

@Milanpatel Kolay çözüm, maske görüntüsündeki renklerinizi tersine çevirmektir. :)
Dids

@ZyiOS maskeli görüntünün çerçevesini nasıl özelleştirebilirim. yani kullanıcı maskelenmiş görüntünün boyutunu artırabilir veya azaltabilir.
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

}

// kullanmak için

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

bana resmi verebilir misin
Ahmed Safadi

3

Kabul edilen çözümün hızlı versiyonu:

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

}

Sadece birinin ihtiyacı olması durumunda.

Benim için kusursuz çalışıyor.


Bunun Swift 3.0 sürümü var mı?
Van Du Tran

2

Doğru cevabın artık çalışmadığını ve UIImageView'daki herhangi bir görüntüyü maskelemeye yardımcı olan küçük bir drop-in sınıfı uyguladığını gördük.

Burada bulunabilir: https://github.com/Werbary/WBMaskedImageView

Misal:

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

1
İyi bir! Gerçekten yardımcı oldu.
abhimuralidharan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.