使用自定义形状的孔创建图层蒙版

时间:2022-08-07 19:34:58

I've spent too much time trying to figure this out and simply cannot find a workable solution.

我花了太多时间试图解决这个问题,根本无法找到可行的解决方案。

Situation: 1. A picture of 'something' is displayed on the phone. 2. A semi-transparent (e.g. blue) layer is placed on top of the image, completely covering it. 3. A 'hole' in this layer exists where that part of the layer is fully transparent and is movable.

情况:1。手机上会显示“某事”的图片。 2.将半透明(例如蓝色)层放置在图像的顶部,完全覆盖它。 3.该层中的“洞”存在于该层的该部分完全透明且可移动的地方。

An example could be a zoom effect where you move this 'hole' around the image. Inside the hole you can see the image normally, while outside it's covered by the semi-transparent layer. NOTE: I'm implementing this in a cocos2d layer, where the image is represented by a CCSprite. It shouldn't matter though, if no cocos is used.

一个示例可以是缩放效果,您可以在图像周围移动此“洞”。在孔内,您可以正常看到图像,而在外面则被半透明层覆盖。注意:我在cocos2d层实现它,其中图像由CCSprite表示。但是,如果没有使用cocos,那应该没关系。

Problem: I've tried using CAShapeLayer and bitmaps as masks, but nothing is working (see code snippets below). With the CAShapeLayer, I create a UIBezierPath for the 'hole' and apply it to the colored layer. However, only the hole shows the color, while the rest is transparent. With an image, the mask is simply not working (I have no idea why). I've even tried masking masks to see if that would work. I've also tried swapping colors around...from white to black to clear for fill and background.

问题:我尝试使用CAShapeLayer和位图作为掩码,但没有任何工作(请参阅下面的代码片段)。使用CAShapeLayer,我为'hole'创建了一个UIBezierPath并将其应用于彩色层。但是,只有孔显示颜色,而其余部分是透明的。使用图像,掩码根本不起作用(我不知道为什么)。我甚至尝试过掩盖面具,看看是否可行。我也试过交换颜色......从白色到黑色,以清除填充和背景。

A simple solution, if it existed, would be to invert the area of the UIBezierPath. I've tried clipping, as well, using the path...but no luck.

如果存在,一个简单的解决方案是反转UIBezierPath的区域。我也尝试使用路径进行削波......但没有运气。

I'm hoping that it's something simple-stupid that I'm simply overlooking. Perhaps one of you will see this. The moving part I'm not, yet, concerned with. I need to get the actual mask working first. The sample code is ignoring the y-axis differences between iPhone SDK and openGL.

我希望这简直是愚蠢的,我只是俯视。也许你们其中一个人会看到这个。我不关心的那个动人的部分。我需要先让实际的面具工作。示例代码忽略了iPhone SDK和openGL之间的y轴差异。

CAShapeLayer Example:

CAShapeLayer示例:

CGSize winSize = [[CCDirector sharedDirector] winSize];
UIImage* img = [UIImage imageNamed:@"zebra.png"];
CCSprite* spr = [CCSprite spriteWithCGImage:img.CGImage key:@"img"];
spr.position = ccp( winSize.width / 2, winSize.width / 2 );
[self addSprite:spr];

UIBezierPath* path = [UIBezierPath bezierPathWithRect:rectHole];
CAShapeLayer* maskLayer = [CAShapeLayer layer];
maskLayer.bounds = [spr boundingBox];
maskLayer.position = spr.position;
maskLayer.fillColor = [UIColor whiteColor].CGColor;
maskLayer.backgroundColor = [UIColor clearColor].CGColor;
maskLayer.path = path.CGPath;

CALayer* colorLayer = [CALayer layer];
colorLayer.bounds = [spr boundingBox];
colorLayer.position = maskLayer.position;
[colorLayer setMask:maskLayer];

[[[[CCDirector sharedDirector] openGLView] layer] addSublayer:colorLayer];

Multiple Layer Mask Example:

多层掩码示例:

CGSize winSize = [[CCDirector sharedDirector] winSize];
UIImage* img = [UIImage imageNamed:@"zebra.png"];
CCSprite* spr = [CCSprite spriteWithCGImage:img.CGImage key:@"img"];
spr.position = ccp( winSize.width / 2, winSize.width / 2 );
[self addSprite:spr];

UIBezierPath* path = [UIBezierPath bezierPathWithRect:rectHole];
CAShapeLayer* maskLayer = [CAShapeLayer layer];
maskLayer.bounds = [spr boundingBox];
maskLayer.position = spr.position;
maskLayer.fillColor = [UIColor whiteColor].CGColor;
maskLayer.backgroundColor = [UIColor clearColor].CGColor;
maskLayer.path = path.CGPath;

UIBezierPath* pathOuter = [UIBezierPath bezierPathWithRect:img.frame];
CAShapeLayer* outerLayer = [CAShapeLayer layer];
outerLayer.bounds = [spr boundingBox];
outerLayer.position = spr.position;
outerLayer.fillColor = [UIColor blackColor].CGColor;
outerLayer.backgroundColor = [UIColor whiteColor].CGColor;
outerLayer = pathOuter.CGPath;
[outerLayer setMask:maskLayer];

CALayer* colorLayer = [CALayer layer];
colorLayer.bounds = [spr boundingBox];
colorLayer.position = outerLayer.position;
[colorLayer setMask:outerLayer];

[[[[CCDirector sharedDirector] openGLView] layer] addSublayer:colorLayer];

Image Mask Example:

图像掩码示例:

CGSize winSize = [[CCDirector sharedDirector] winSize];
UIImage* img = [UIImage imageNamed:@"zebra.png"];
CCSprite* spr = [CCSprite spriteWithCGImage:img.CGImage key:@"img"];
spr.position = ccp( winSize.width / 2, winSize.width / 2 );
[self addSprite:spr];

CGRect r = [spr boundingBox];
CGSize sz = CGSizeMake( r.size.width, r.size.height );
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef context = CGBitmapContextCreate( NULL, w, h, 8, 0, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaNone );
CGColorSpaceRelease( colorSpace );
CGContextSetFillColorWithColor( context, [UIColor whiteColor].CGColor );
CGContextFillRect( context, r );
CGContextSetFillColorWithColor( context, [UIColor blackColor].CGColor );
CGContextFillRect( context, rectHole );
CGImageRef ref = CGBitmapContextCreateImage( context );
CGContextRelease( context );

CALayer* maskLayer = [CALayer layer];
maskLayer.bounds = [spr boundingBox];
maskLayer.position = spr.position;
[maskLayer setContents:(id)ref];

CALayer* colorLayer = [CALayer layer];
colorLayer.bounds = [spr boundingBox];
colorLayer.position = maskLayer.position;
[colorLayer setMask:maskLayer];

[[[[CCDirector sharedDirector] openGLView] layer] addSublayer:colorLayer];
CGImageRelease( ref );

1 个解决方案

#1


13  

I came back to this later after learning other core graphics techniques. The solution is closest to the Multiple Layer Mask Example above. However, instead of creating an inner and outer layer, you need to combine two paths into a single UIBezierPath in opposite directions.

在学习了其他核心图形技术之后,我又回到了这里。该解决方案最接近上面的多层掩码示例。但是,您需要将两个路径组合成一个方向相反的单个UIBezierPath,而不是创建内层和外层。

So, e.g., create a path of the inner area to be cropped (CW). NOTE: x,y,w,h are referring to the origin and size of the "hole".

因此,例如,创建要裁剪的内部区域的路径(CW)。注:x,y,w,h是指“孔”的原点和大小。

      [path moveToPoint:ccp(x,y)];
      [path addLineToPoint:ccp(x+w,y)];
      [path addLineToPoint:ccp(x+w,y+h)];
      [path addLineToPoint:ccp(x,y+h)];
      [path addLineToPoint:ccp(x,y)];

Then, add to the same path the outer area in the opposite direction (CCW). NOTE: x,y,w,h are referring to the origin and size of the outer rect.

然后,将相反方向的外部区域(CCW)添加到相同的路径。注意:x,y,w,h是指外直肠的原点和大小。

      [path moveToPoint:ccp(x,y)];
      [path addLineToPoint:ccp(x,y+h)];
      [path addLineToPoint:ccp(x+w,y+h)];
      [path addLineToPoint:ccp(x+w,y)];
      [path addLineToPoint:ccp(x,y)];

This path is then applied to a layer (maskLayer), which is used as the mask on the final layer (colorLayer). The "outerLayer" is not needed.

然后将此路径应用于图层(maskLayer),该图层用作最终图层(colorLayer)上的蒙版。不需要“outerLayer”。

#1


13  

I came back to this later after learning other core graphics techniques. The solution is closest to the Multiple Layer Mask Example above. However, instead of creating an inner and outer layer, you need to combine two paths into a single UIBezierPath in opposite directions.

在学习了其他核心图形技术之后,我又回到了这里。该解决方案最接近上面的多层掩码示例。但是,您需要将两个路径组合成一个方向相反的单个UIBezierPath,而不是创建内层和外层。

So, e.g., create a path of the inner area to be cropped (CW). NOTE: x,y,w,h are referring to the origin and size of the "hole".

因此,例如,创建要裁剪的内部区域的路径(CW)。注:x,y,w,h是指“孔”的原点和大小。

      [path moveToPoint:ccp(x,y)];
      [path addLineToPoint:ccp(x+w,y)];
      [path addLineToPoint:ccp(x+w,y+h)];
      [path addLineToPoint:ccp(x,y+h)];
      [path addLineToPoint:ccp(x,y)];

Then, add to the same path the outer area in the opposite direction (CCW). NOTE: x,y,w,h are referring to the origin and size of the outer rect.

然后,将相反方向的外部区域(CCW)添加到相同的路径。注意:x,y,w,h是指外直肠的原点和大小。

      [path moveToPoint:ccp(x,y)];
      [path addLineToPoint:ccp(x,y+h)];
      [path addLineToPoint:ccp(x+w,y+h)];
      [path addLineToPoint:ccp(x+w,y)];
      [path addLineToPoint:ccp(x,y)];

This path is then applied to a layer (maskLayer), which is used as the mask on the final layer (colorLayer). The "outerLayer" is not needed.

然后将此路径应用于图层(maskLayer),该图层用作最终图层(colorLayer)上的蒙版。不需要“outerLayer”。