Bagaimana cara menutupi UIImageView?

100

Saya mencoba menutupi gambar dengan sesuatu seperti ini:

gambar yang akan ditutup

Maukah Anda membantu saya?

Saya menggunakan kode ini:

- (void) viewDidLoad {
    UIImage *OrigImage = [UIImage imageNamed:@"dogs.png"];
    UIImage *mask = [UIImage imageNamed:@"mask.png"];
    UIImage *maskedImage = [self maskImage:OrigImage withMask:mask];
    myUIIMage.image = maskedImage;
}
Mc.Lover
sumber
27
Saya orang yang menulis tutorial asli. Gambar topeng hanyalah gambar abu-abu sederhana yang saya buat di photoshop. Tidak ada yang istimewa tentang itu. Area hitam menjadi bagian "transparan" dari topeng. Ingatlah bahwa sembarang bayangan abu-abu diartikan sebagai derajat keburaman. Dengan cara ini, topeng juga bisa menjadi gradien yang berguna untuk membuat batas yang lebih lembut di sekitar topeng.
ra9r
Ini harus berukuran sama, bukan?
KarenAnne
kode hiper-elegan, terima kasih. hanya tautan yang berguna jika ada yang perlu memotong gambar sebelum menutupi ... stackoverflow.com/questions/17712797/…
Fattie
Ada ide tentang ini .. stackoverflow.com/questions/28122370/…
Patel Milan
1
Saya mendorong Anda untuk mengubah jawaban yang dipilih menjadi jawaban dengan suara positif hampir 3 kali lebih banyak. Menurut pendapat saya lebih baik di hampir segala hal.
Albert Renshaw

Jawaban:

165

Ada cara yang lebih mudah.

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

Untuk Swift 4 dan plus ikuti kode di bawah ini

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
Bartosz Ciechanowski
sumber
1
terima kasih tetapi saya memasang kode ini viewDidLoadtetapi tidak ada yang terjadi!
Mc.Lover
6
Anda harus menyetel properti lapisan untuk menggunakan topeng, yaitu [yourImageView.layer setMasksToBounds: YES];
Wolfgang Schreurs
3
Perhatikan bahwa ini perlu menjadi UIImageView untuk solusi ini. Solusi lain hanya berfungsi dengan UIImage.
adriendenat
1
Saya mencoba pendekatan ini tetapi tampaknya ini tidak berhasil di iOS 8
bdv
2
Untuk kode Swift, ketika dimasukkan ke dalam mask.contents, sebaiknya CGImage. Bukan [CGImage]. Jika menggunakan braket [], artinya Array.
strawnut
59

Tutorial menggunakan metode ini dengan dua parameter: imagedan maskImage, ini harus Anda setel saat memanggil metode. Contoh panggilan bisa terlihat seperti ini, dengan asumsi metode berada di kelas yang sama dan gambar ada di bundel Anda:

Catatan - gambarnya bahkan tidak harus berukuran sama.

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

Setelah Anda memberikan kode Anda, saya menambahkan beberapa nomor sebagai komentar untuk referensi. Anda masih punya dua pilihan. Semua ini adalah metode, yang Anda panggil ke suatu tempat. Anda tidak perlu membuat gambar di dalamnya: ini mengurangi kegunaan kembali metode menjadi nol.

Agar kode Anda berfungsi. Ubah metode head ( 1. ) menjadi

- (UIImage *)maskImageMyImages {

Kemudian ubah nama variabel di 2. menjadi

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

Metode ini akan mengembalikan gambar bertopeng sehingga Anda harus memanggil metode ini di suatu tempat. Dapatkah Anda menunjukkan kepada kami kode di mana Anda memanggil metode Anda?

Nick Weaver
sumber
maaf! dimana harus menulis UIImage *imagekode? !!! karena pada -(UIimage *) maskeImagecompiler memberikan redefinition error!
Mc.Lover
maaf, tolong unggah kode contoh untuk saya? Saya bingung: -s
Mc.Lover
1
Tidak mungkin, semuanya ada di sana. Anda harus menunjukkan kepada kami bagaimana Anda memanggil metode ini, atau setidaknya bagian di mana Anda ingin menutupi gambar Anda dan menunjukkan hasilnya.
Nick Weaver
Masalah saya adalah menyebutnya, apakah harus seperti ini ?? (viewDidLoad): lihat kode yang saya edit
Mc.Lover
Tahu tentang Reverse masking. (Kebalikan dari proses di atas). Berarti saya ingin menghapus area isian (membuatnya transparan) dan area Transparan dengan isian.
Patel Milan
17

Swift 3 - Solusi Paling Sederhana yang Saya Temukan

Saya membuat @IBDesignableuntuk ini sehingga Anda dapat melihat efeknya langsung di papan cerita Anda.

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

Cara Penggunaan

  1. Buat file baru dan tempel kode di atas.
  2. Tambahkan UIImageView ke storyboard Anda (tetapkan gambar jika Anda mau).
  3. Pada Identity Inspector: Ubah kelas khusus menjadi "UIImageViewWithMask" (nama kelas khusus di atas).
  4. Pada Attributes Inspector: Pilih gambar topeng yang ingin Anda gunakan.

Contoh

Masking di Storyboard

Catatan

  • Gambar topeng Anda harus memiliki latar belakang transparan (PNG) untuk bagian non-hitam.
Mark Moeykens
sumber
12

Saya mencoba kedua kode menggunakan CALayer atau CGImageCreateWithMask tetapi tidak ada yang tidak berhasil untuk saya

Tetapi saya menemukan bahwa masalahnya ada pada format file png, BUKAN kodenya !!
jadi hanya untuk berbagi temuan saya!

Jika Anda ingin menggunakan

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

Anda harus menggunakan png 24bit tanpa alpha channel

Jika Anda ingin menggunakan CALayer mask, Anda harus menggunakan (24bit atau 8bit) png dengan alpha channel dimana bagian transparan dari png Anda akan menutupi gambar (untuk smooth gradient alpha mask .. gunakan 24bit png dengan alpha channel)

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

Ini berhasil untuk saya.

ZYiOS
sumber
terima kasih, jawaban ini lebih baik daripada yang lain berbicara tentang kinerja dengan gambar yang lebih banyak dan lebih besar.
Radu Ursache
1
Tahu tentang reverse masking. (Kebalikan dari proses di atas). Berarti saya ingin menghapus area isian (membuatnya transparan) dan area Transparan dengan isian.
Patel Milan
Terima kasih, kode ini bekerja lebih baik dari sebelumnya !! Tetapi saya memiliki dua masalah: Peringatan pada "kCGImageAlphaPremultipliedLast" (saya mentransmisikan ke "CGBitmapInfo" untuk memperbaikinya) DAN tidak berfungsi untuk gambar retina !! bisakah kamu membantuku ?? ...
fingerup
@Milanpatel Solusi mudahnya adalah dengan membalikkan warna Anda pada gambar topeng. :)
Dilakukan pada
@ZyiOS bagaimana cara menyesuaikan bingkai Gambar bertopeng. yaitu pengguna dapat menambah atau mengurangi ukuran gambar bertopeng.
Dalvik
8

SWIFT 3 XCODE 8.1.0

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

}

// untuk digunakan

testImage.image = maskImage(image: UIImage(named: "OriginalImage")!, withMask: UIImage(named: "maskImage")!)
Ahmed Safadi
sumber
dapatkah Anda memberi saya fotonya
Ahmed Safadi
3

Versi cepat dari solusi yang diterima:

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

}

Untuk berjaga-jaga jika seseorang membutuhkannya.

Ini bekerja untuk saya dengan sempurna.

Juan Valera
sumber
Apakah Anda memiliki versi Swift 3.0 ini?
Van Du Tran
2

kami menemukan, bahwa jawaban yang benar tidak berfungsi sekarang dan menerapkan kelas drop-in kecil, yang membantu menutupi gambar apa pun di UIImageView.

Tersedia di sini: https://github.com/Werbary/WBMaskedImageView

Contoh:

WBMaskedImageView *imgView = [[WBMaskedImageView alloc] initWithFrame:frame];
imgView.originalImage = [UIImage imageNamed:@"original_image.png"];
imgView.maskImage = [UIImage imageNamed:@"mask_image.png"];
werbary
sumber
1
Bagus! Ini sangat membantu.
abhimuralidharan