Як можна замаскувати 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


1
Я закликаю вас змінити обрану відповідь на ту, що має майже в 3 рази більше відгуків. На мою думку, це краще майже в усіх напрямках.
— Альберт Реншо

Відповіді:


163

Є простіший спосіб.

#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 і плюс дотримуйтесь коду нижче

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: ТАК];
— Вольфганг Шреурс

3
Зауважте, що для цього рішення потрібно мати UIImageView. Інше рішення працює лише з UIImage.
— adriendenat

1
Я спробував такий підхід, але це, здається, не працює в iOS 8
— bdv

2
Для коду Swift, якщо він розміщений у mask.contents, повинен CGImage. Не [CGImage]. Якщо використовується дужка [], це означає масив.
— 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;
}

Після того, як ви надали свій код, я додав деякі номери як коментарі до нього для довідки. У вас є ще два варіанти. Вся ця річ - це метод, який ви кудись дзвоните. Не потрібно створювати зображення всередині нього: це зводить повторно використаний метод до нуля.

Щоб ваш код працював. Змініть голову методів ( 1. ) на

- (UIImage *)maskImageMyImages {

Потім змініть ім'я змінної на 2. до

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

Метод поверне ваші замасковані зображення, тому вам доведеться викликати цей спосіб десь. Чи можете ви показати нам код, де ви викликаєте свій метод?


вибачте! де слід написати UIImage *imageкод? !!! тому що -(UIimage *) maskeImageкомпілятор дає помилку переосмислення!
— Mc.Lover

Вибачте, будь ласка, завантажте для мене зразок коду? Iam плутався: -s
— Mc.Lover

1
Не можливо, все є. Вам доведеться показати нам, як ви називаєте цей метод, або хоча б ту частину, в якій ви хочете замаскувати свої зображення та показати результат.
— Нік Вівер

моя проблема полягає в тому, щоб назвати це, чи має бути щось подібне ?? (viewDidLoad): дивіться мій відредагований код
— Mc.Lover

Будь-яка ідея про реверсне маскування. (Зворотний процес, описаний вище). Людям я хочу видалити область заливки (зробити її прозорою) та прозору область із заливкою.
— Міланський патель

16

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. Про Інспектор ідентичності: Змініть спеціальний клас на "UIImageViewWithMask" (назва спеціального класу вище).
  4. On Attributes Inspector: Виберіть зображення маски, яке ви хочете використовувати.

Приклад

Маскування на аркуші

Примітки

  • Зображення вашої маски має мати прозорий фон (PNG) для чорної частини.

12

Я спробував обидва коди, використовуючи або CALayer, або CGImageCreateWithMask, але жоден з них не працював для мене

Але я дізнався, що проблема полягає у форматі файлу png, а не в коді !!
так що просто поділитися моїми висновками!

Якщо ви хочете використовувати

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

ви повинні використовувати 24-бітний png без альфа-каналу

Якщо ви хочете використовувати маску CALayer, ви повинні використовувати (24-бітовий або 8-бітовий) png з альфа-каналом, де прозора частина вашого png маскує зображення (для гладкої градієнтної альфа-маски. Використовуйте 24-бітний png з альфа-каналом)


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

Це працює для мене.


дякую, ця відповідь краще, ніж інші говорять про продуктивність із більшими та більшими зображеннями.
— Раду Уршаче

1
Будь-яке уявлення про зворотному маскуванні. (Зворотний процес, описаний вище). Людям я хочу видалити область заливки (зробити її прозорою) та прозору область із заливкою.
— Міланський патель

Дякую, цей код працює краще, ніж перший !! Але у мене є дві неприємності: попередження про "kCGImageAlphaPremultifiedLast" (я передаю "CGBitmapInfo" для виправлення) І не працює для зображень сітківки !! Ви можете мені допомогти ?? ...
— пальчиком

@Milanpatel Найпростішим рішенням є просто інвертувати кольори у зображення маски. :)
— Діди

@ZyiOS як я можу налаштувати кадр маскуваного зображення. тобто користувач може збільшувати або зменшувати розмір маскуваного зображення.
— Далвік

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")!)

ви можете мені подарувати фотографію
— Ахмед Сафаді

3

Швидка версія прийнятого рішення:

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
Хороший! Це справді допомогло.
— абхімуралідхаран
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.