使用自定义形状的孔创建图层蒙版 [英] Create layer mask with custom-shaped hole

查看:18
本文介绍了使用自定义形状的孔创建图层蒙版的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

情况:1. 手机上显示某物"的图片.2. 半透明(例如蓝色)层放置在图像顶部,完全覆盖它.3. 该层中存在一个洞",该层的该部分完全透明且可移动.

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.

一个示例可能是缩放效果,您可以在图像周围移动这个洞".在洞内你可以正常看到图像,而在洞外则被半透明层覆盖.注意:我在 cocos2d 层中实现这一点,其中图像由 CCSprite 表示.不过,如果没有使用 cocos,应该没关系.

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.

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

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.

如果存在,一个简单的解决方案是反转 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.

我希望这是我忽略的简单愚蠢的事情.也许你们中的一个人会看到这一点.我还不关心的移动部分.我需要先让实际的面具工作.示例代码忽略了 iPhone SDK 和 openGL 之间的 y 轴差异.

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.

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

多层蒙版示例:

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

图像蒙版示例:

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

推荐答案

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

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.

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

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".

      [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)];

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

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.

      [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)];

然后将这条路径应用到一个图层 (maskLayer),该图层用作最后一层 (colorLayer) 上的蒙版.不需要外层".

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.

这篇关于使用自定义形状的孔创建图层蒙版的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆