Crear máscara de capa con agujero en forma personalizada

He pasado mucho time tratando de resolver esto y simplemente no puedo encontrar una solución viable.

Situación: 1. Aparece una image de "algo" en el teléfono. 2. Se coloca una capa semitransparente (p. Ej. Azul) sobre la image, cubriéndola por completo. 3. Existe un "agujero" en esta capa donde esa parte de la capa es completamente transparente y es mobile.

Un ejemplo podría ser un efecto de zoom en el que mueve este 'agujero' alnetworkingedor de la image. Dentro del agujero, puedes ver la image normalmente, mientras que afuera está cubierta por la capa semitransparente. NOTA: Estoy implementando esto en una capa de cocos2d, donde la image está representada por un CCSprite. Sin embargo, no debería importar, si no se usa cocos.

Problema: he intentado usar CAShapeLayer y maps de bits como máscaras, pero nada funciona (ver los fragments de código a continuación). Con el CAShapeLayer, creo un UIBezierPath para el 'agujero' y lo aplico a la capa de color. Sin embargo, solo el agujero muestra el color, mientras que el rest es transparente. Con una image, la máscara simplemente no funciona (no tengo idea de por qué). Incluso he intentado ocultar las máscaras para ver si eso funcionaría. También he intentado intercambiar colors … de blanco a negro para borrar por relleno y background.

Una solución simple, si existiera, sería invertir el área del UIBezierPath. También he intentado cortar, usando la ruta … pero sin suerte.

Espero que sea algo simple, estúpido que simplemente estoy pasando por alto. Tal vez uno de ustedes verá esto. La parte mobile no estoy preocupada. Necesito que primero funcione la máscara real. El código de ejemplo ignora las diferencias entre ejes y entre iPhone SDK y openGL.

CAShapeLayer Ejemplo:

CGSize winSize = [[CCDirector shanetworkingDirector] 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 shanetworkingDirector] openGLView] layer] addSublayer:colorLayer]; 

Ejemplo de máscara de capa múltiple:

 CGSize winSize = [[CCDirector shanetworkingDirector] 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 shanetworkingDirector] openGLView] layer] addSublayer:colorLayer]; 

Ejemplo de máscara de image:

 CGSize winSize = [[CCDirector shanetworkingDirector] 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 shanetworkingDirector] openGLView] layer] addSublayer:colorLayer]; CGImageRelease( ref ); 

Volví a esto más tarde después de aprender otras técnicas básicas de charts. La solución está más cerca del ejemplo de máscara de capa múltiple anterior. Sin embargo, en lugar de crear una capa interna y externa, debe combinar dos routes en un solo UIBezierPath en direcciones opuestas.

Por lo tanto, por ejemplo, cree una ruta del área interna que se recortará (CW). NOTA: x, y, w, h se refieren al origen y al tamaño del "agujero".

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

Luego, agregue al mismo path el área exterior en la dirección opuesta (CCW). NOTA: x, y, w, h se refieren al origen y tamaño del rect exterior.

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

Esta ruta se aplica a una capa (maskLayer), que se utiliza como máscara en la capa final (colorLayer). El "outerLayer" no es necesario.