CGContextClipToMask返回空白图像

10

我是Quartz的新手。我有两张图片,一张背景和一张带有剪切形状的蒙版,我想将其覆盖在背景上以剪切出一个区域。最终的图像应该是剪切出来的形状。这是我的蒙版(中间的形状为0 alpha):

image mask

这是我的代码:

UIView *canvas = [[[sender superview] subviews] objectAtIndex:0];

UIGraphicsBeginImageContext(canvas.bounds.size);
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef cgContext = CGBitmapContextCreate(NULL, canvas.bounds.size.width, canvas.bounds.size.height, 8, 0, colourSpace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colourSpace);

CGImageRef maskImage = [[UIImage imageNamed:@"Mask.png"] CGImage];
CGContextClipToMask(cgContext, CGRectMake(0, 0, canvas.frame.size.width, canvas.frame.size.height), maskImage);

CGImageRef maskedImageRef = CGBitmapContextCreateImage(cgContext);
CGContextRelease(cgContext);

UIImage *maskedImage = [UIImage imageWithCGImage:maskedImageRef];
UIGraphicsEndImageContext();

[button setBackgroundImage:maskedImage forState:UIControlStateNormal];

除了什么也没有显示... 有没有想法我做错了哪里?非常感谢。


你似乎没有绘制任何东西。你从空白中剪切出了什么也没有,得到的也是什么也没有。这是意料之中的。在剪切到掩码和创建图像之间,你应该绘制一些东西。 - Svein Halvor Halvorsen
1个回答

11

使用遮罩剪辑上下文后,您应该在该上下文上实际绘制内容。

此外:

  • 您应该使用UIGraphicsBeginImageContextWithOptions来支持比例因子。
  • 您正在创建两个上下文,一个是使用UIGraphicsBeginImageContext创建的,另一个是使用CGBitmapContextCreate创建的。 一个就足够了 :)
  • 您应该“翻转”遮罩的alpha值,因为根据文档中的说法:遮罩的源样本确定剪切区域的哪些点发生了更改。 换句话说,透明将变为透明。

简单的示例代码,在其中我在imageView内裁剪图像,然后将其设置回去:

UIGraphicsBeginImageContextWithOptions(self.imageView.frame.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();

CGContextTranslateCTM(context, 0.0, self.imageView.frame.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

CGImageRef maskImage = [[UIImage imageNamed:@"mask.png"] CGImage];
CGContextClipToMask(context, self.imageView.bounds, maskImage); 

CGContextTranslateCTM(context, 0.0, self.imageView.frame.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

[[self.imageView image] drawInRect:self.imageView.bounds];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

self.imageView.image = image;

使用CGImageCreateWithMask的示例:

UIImage *image = [UIImage imageNamed:@"image"];

CGImageRef originalMask = [UIImage imageNamed:@"mask"].CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(originalMask),
                                    CGImageGetHeight(originalMask),
                                    CGImageGetBitsPerComponent(originalMask),
                                    CGImageGetBitsPerPixel(originalMask),
                                    CGImageGetBytesPerRow(originalMask),
                                    CGImageGetDataProvider(originalMask), nil, YES);

CGImageRef maskedImageRef = CGImageCreateWithMask(image.CGImage, mask);

UIImage *maskedImage = [UIImage imageWithCGImage:maskedImageRef scale:image.scale orientation:image.imageOrientation];

CGImageRelease(mask);
CGImageRelease(maskedImageRef);

我明白了,谢谢!只有几个问题。为什么需要调用TranslateCTM两次?另外,我得到了相反的效果 - 掩码的alpha 0部分被剪切掉了,而图像的黑色部分被绘制出来了。根据文档,我需要使用CGImageCreateWithMask将图像与图像进行遮罩,而不是使用掩码,但我在哪里使用它呢? - Smikey
UIKit和CGGraphics有不同的坐标系统,因此我们需要进行矩阵转换。 "遮罩的alpha 0部分正在被剪切" - 这正是CGContextClipToMaskCGImageCreateWithMask文档告诉您的。添加了CGImageCreateWithMask的示例。 - Evgeny Shurakov
很不幸,我测试过后发现这里的解决方案在 iOS 11 上均无法使用。我尝试使用两个 UIImages 进行遮罩并使用了这两种方法。第一种方法在剪裁后会挤压图像,而第二种方法返回 {0.0}。@Evgeny Shurakov - Reza.Ab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接