Как я могу замаскировать UIImageView?
Я пытаюсь замаскировать изображение чем-то вроде этого:
не могли бы вы помочь мне?
Я использую этот код:
- (void) viewDidLoad {
UIImage *OrigImage = [UIImage imageNamed:@"dogs.png"];
UIImage *mask = [UIImage imageNamed:@"mask.png"];
UIImage *maskedImage = [self maskImage:OrigImage withMask:mask];
myUIIMage.image = maskedImage;
}
8 ответов:
есть более простой способ.
#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
учебник использует этот метод с двумя параметрами:
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"];
метод вернет ваши маскированные изображения, поэтому вам придется вызвать этот метод в каком-то месте. Можете ли вы показать нам код, где вы вызываете вашего метод?
я попробовал оба кода, используя либо CALayer или CGImageCreateWithMask, но ни один из них не работал для меня
но я узнал, что проблема с форматом файла png, а не с кодом!!
так что просто поделиться своим открытием!Если вы хотите использовать
- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage
вы должны использовать 24bit png без альфа-канал
Если вы хотите использовать маску CALayer, вы должны использовать (24bit или 8bit) png С альфа-канал где прозрачная часть вашего png будет маскировать изображение (для гладкой градиентной Альфа-маски.. используйте 24-битный png с альфа-каналом)
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 } } }
как использовать
- создайте новый файл и вставьте в этот код выше.
- добавить UIImageView к раскадровке (назначить изображение, если вы хотите).
- on Identity Inspector: измените пользовательский класс на "UIImageViewWithMask" (имя пользовательского класса выше).
- Атрибуты Инспектор: Выберите изображение маски вы захотите использовать.
пример
Примечания
- изображение маски должно иметь прозрачный фон (PNG) для не черной части.
- (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; }
это работает для меня.
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")!)
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 }
на всякий случай кому-то это нужно.
это работает для меня безотказно.
мы обнаружили, что правильный ответ не работает сейчас и реализован небольшой drop-in класс, который помогает маскировать любое изображение в 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"];