ฉันจะปิดบัง UIImageView ได้อย่างไร


100

ฉันกำลังพยายามปกปิดรูปภาพด้วยสิ่งนี้:

ภาพที่จะมาสก์

คุณช่วยฉันได้ไหม

ฉันใช้รหัสนี้:

- (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
ฉันเป็นคนที่เขียนบทแนะนำต้นฉบับ ภาพมาสก์เป็นเพียงภาพสีเทาธรรมดาที่ฉันสร้างใน photoshop ไม่มีอะไรพิเศษเกี่ยวกับมัน พื้นที่สีดำกลายเป็นส่วนที่ "โปร่งใส" ของหน้ากาก โปรดทราบว่าเฉดสีเทาใด ๆ จะถูกตีความว่าเป็นระดับความทึบ ในลักษณะนี้มาสก์สามารถไล่ระดับสีได้เช่นกันซึ่งมีประโยชน์ในการสร้างเส้นขอบที่นุ่มนวลขึ้นรอบ ๆ หน้ากาก
ra9r

ต้องมีขนาดเท่ากันใช่ไหม?
KarenAnne

รหัสหรูหรามากขอบคุณ แค่ลิงค์ที่มีประโยชน์ถ้าใครต้องการครอปภาพก่อนมาสก์ ... stackoverflow.com/questions/17712797/…
Fattie

มีความคิดอย่างไรกับเรื่องนี้ .. stackoverflow.com/questions/28122370/…
Milan patel

1
ฉันขอให้คุณเปลี่ยนคำตอบที่เลือกเป็นคำตอบที่มีการโหวตเพิ่มขึ้นเกือบ 3 เท่า ในความคิดของฉันมันดีกว่าในทุกทาง
Albert Renshaw

คำตอบ:


165

มีวิธีที่ง่ายกว่านี้

#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 และ plus ตามโค้ดด้านล่าง

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
ขอบคุณ แต่ฉันใส่รหัสนี้viewDidLoadแต่ไม่มีอะไรเกิดขึ้น!
Mc.Lover

6
คุณควรตั้งค่าคุณสมบัติเลเยอร์เพื่อใช้มาสก์เช่น[yourImageView.layer setMasksToBounds: YES];
Wolfgang Schreurs

3
โปรดสังเกตว่าจำเป็นต้องเป็น UIImageView สำหรับโซลูชันนี้ โซลูชันอื่นใช้ได้กับ UIImage เท่านั้น
adriendenat

1
ฉันลองใช้วิธีนี้ แต่ดูเหมือนว่าจะไม่ได้ผลใน iOS 8
bdv

2
สำหรับ Swift code เมื่อใส่ mask.contents ควรใช้ CGImage ไม่ใช่ [CGImage] ถ้าใช้วงเล็บ [] หมายความว่า Array
strawnut

59

บทช่วยสอนใช้วิธีนี้กับสองพารามิเตอร์: imageและmaskImageคุณต้องตั้งค่าเมื่อคุณเรียกใช้เมธอด ตัวอย่างการโทรอาจมีลักษณะเช่นนี้โดยสมมติว่าเมธอดอยู่ในคลาสเดียวกันและรูปภาพอยู่ในบันเดิลของคุณ:

หมายเหตุ - ภาพไม่จำเป็นต้องมีขนาดเท่ากันด้วยซ้ำ

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

หลังจากที่คุณระบุรหัสของคุณแล้วฉันได้เพิ่มตัวเลขเป็นความคิดเห็นเพื่อใช้อ้างอิง คุณยังมีสองทางเลือก ทั้งหมดนี้เป็นวิธีการที่คุณกำลังโทรหาที่ไหนสักแห่ง คุณไม่จำเป็นต้องสร้างภาพภายในสิ่งนี้จะช่วยลดความสามารถในการนำกลับมาใช้ใหม่ให้เป็นศูนย์

เพื่อให้รหัสของคุณทำงานได้ เปลี่ยนวิธีการ head ( 1. ) เป็น

- (UIImage *)maskImageMyImages {

จากนั้นเปลี่ยนชื่อของตัวแปรใน2.เป็น

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

วิธีนี้จะส่งคืนภาพที่มาสก์ของคุณดังนั้นคุณจะต้องเรียกวิธีนี้ในบางที่ คุณสามารถแสดงรหัสที่คุณเรียกใช้วิธีการของคุณได้หรือไม่?


ขอโทษ! ควรเขียนUIImage *imageโค้ดที่ไหน !!! เนื่องจากใน-(UIimage *) maskeImageคอมไพเลอร์ให้ข้อผิดพลาดในการกำหนดนิยามใหม่!
Mc.Lover

ขอโทษคุณช่วยอัพโหลดโค้ดตัวอย่างให้ฉันได้ไหม เอี่ยมสับสน: -s
Mc.Lover

1
เป็นไปไม่ได้ทุกอย่างอยู่ที่นั่น คุณจะต้องแสดงให้เราเห็นว่าคุณเรียกวิธีนี้ว่าอย่างไรหรืออย่างน้อยก็ส่วนที่คุณต้องการมาสก์รูปภาพของคุณและแสดงผลลัพธ์
Nick Weaver

ปัญหาของฉันคือเรียกมันว่ามันควรจะเป็นแบบนี้ไหม ?? (viewDidLoad): ดูรหัสที่แก้ไขของฉัน
Mc.Lover

ความคิดใด ๆ เกี่ยวกับการมาสก์ย้อนกลับ (ย้อนกลับของกระบวนการด้านบน) หมายความว่าฉันต้องการลบพื้นที่เติม (ทำให้โปร่งใส) และพื้นที่โปร่งใสพร้อมการเติม
Milan patel

17

Swift 3 - โซลูชันที่ง่ายที่สุดที่ฉันพบ

ฉันสร้างสิ่ง@IBDesignableนี้ขึ้นมาเพื่อให้คุณเห็นเอฟเฟกต์บนกระดานเรื่องราวของคุณได้ทันที

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

วิธีใช้

  1. สร้างไฟล์ใหม่และวางโค้ดด้านบน
  2. เพิ่ม UIImageView ลงในสตอรีบอร์ดของคุณ (กำหนดรูปภาพหากคุณต้องการ)
  3. ใน Identity Inspector: เปลี่ยนคลาสที่กำหนดเองเป็น "UIImageViewWithMask" (ชื่อคลาสที่กำหนดเองด้านบน)
  4. ใน Attributes Inspector: เลือกภาพมาสก์ที่คุณต้องการใช้

ตัวอย่าง

การมาสก์บนกระดานเรื่องราว

หมายเหตุ

  • ภาพหน้ากากของคุณควรมีพื้นหลังโปร่งใส (PNG) สำหรับส่วนที่ไม่ใช่สีดำ

12

ฉันลองใช้ทั้งสองรหัสโดยใช้ CALayer หรือ CGImageCreateWithMask แต่ไม่มีรหัสใดที่ไม่ได้ผลสำหรับฉัน

แต่ฉันพบว่าปัญหาอยู่ที่รูปแบบไฟล์ png ไม่ใช่รหัส !!
เพื่อแบ่งปันการค้นพบของฉัน!

หากต้องการใช้

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

คุณต้องใช้24 บิต png โดยไม่มีช่องอัลฟา

หากคุณต้องการใช้มาสก์ CALayer คุณต้องใช้ png (24 บิตหรือ 8 บิต) กับช่องอัลฟาซึ่งส่วนโปร่งใสของ png ของคุณจะมาสก์รูปภาพ (สำหรับมาสก์อัลฟาไล่ระดับสีที่ราบรื่น .. ใช้ png 24 บิตพร้อมช่องอัลฟา)


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

สิ่งนี้ใช้ได้กับฉัน


ขอบคุณคำตอบนี้ดีกว่าเมื่อคนอื่นพูดถึงประสิทธิภาพด้วยภาพที่ใหญ่ขึ้นเรื่อย ๆ
Radu Ursache

1
ความคิดใด ๆ เกี่ยวกับการมาสก์ย้อนกลับ (ย้อนกลับของกระบวนการด้านบน) หมายความว่าฉันต้องการลบพื้นที่เติม (ทำให้โปร่งใส) และพื้นที่โปร่งใสพร้อมการเติม
Milan patel

ขอบคุณรหัสนี้ทำงานได้ดีกว่าครั้งแรก !! แต่ฉันมีปัญหาสองประการ: คำเตือนเกี่ยวกับ "kCGImageAlphaPremultipliedLast" (ฉันส่งไปที่ "CGBitmapInfo" เพื่อแก้ไข) และใช้ไม่ได้กับภาพเรตินา !! คุณช่วยฉันได้ไหม ?? ...
fingerup

@Milanpatel วิธีแก้ปัญหาง่ายๆคือเพียงแค่กลับสีของคุณในภาพมาสก์ :)
Dids

@ZyiOS ฉันจะปรับแต่งเฟรมของภาพที่มาสก์ได้อย่างไร เช่นผู้ใช้สามารถเพิ่มหรือลดขนาดของภาพมาสก์
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

}

// สำหรับการใช้งาน

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

คุณสามารถให้ภาพฉัน
Ahmed Safadi

3

โซลูชันที่ยอมรับเวอร์ชัน Swift:

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

}

ในกรณีที่มีคนต้องการ

มันทำงานให้ฉันได้อย่างไม่มีที่ติ


คุณมี Swift 3.0 เวอร์ชันนี้หรือไม่?
Van Du Tran

2

เราพบว่าคำตอบที่ถูกต้องใช้งานไม่ได้ในขณะนี้และใช้คลาสดร็อปอินเล็ก ๆ น้อย ๆ ซึ่งช่วยปกปิดรูปภาพใด ๆ ใน UIImageView

มีให้ที่นี่: https://github.com/Werbary/WBMaskedImageView

ตัวอย่าง:

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

1
สิ่งที่ดี! มันช่วยได้จริงๆ
abhimuralidharan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.