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