Подтвердить что ты не робот

Создайте маску слоя с выборочным отверстием

Я потратил слишком много времени, пытаясь понять это, и просто не могу найти работоспособного решения.

Ситуация: 1. На телефоне отображается изображение "что-то". 2. Полупрозрачный (например, синий) слой помещается поверх изображения, полностью покрывая его. 3. "Отверстие" в этом слое существует там, где эта часть слоя полностью прозрачна и подвижна.

Примером может быть эффект масштабирования, при котором вы перемещаете это "отверстие" вокруг изображения. Внутри отверстия вы можете видеть изображение нормально, а снаружи оно покрыто полупрозрачным слоем. ПРИМЕЧАНИЕ. Я реализую это в слое cocos2d, где изображение представлено CCSprite. Это не имеет значения, если не используется кокос.

Проблема: Я пытался использовать CAShapeLayer и растровые изображения в качестве масок, но ничего не работает (см. Фрагменты кода ниже). С CAShapeLayer я создаю UIBezierPath для "дыры" и применяю его к цветному слою. Однако только отверстие показывает цвет, а остальное прозрачно. С изображением маска просто не работает (я понятия не имею, почему). Я даже пытался маскировать маски, чтобы увидеть, будет ли это работать. Я также попытался изменить цвета вокруг... от белого до черного, чтобы очистить заливку и фон.

Простое решение, если оно существовало, было бы инвертировать область UIBezierPath. Я тоже попробовал обрезать, используя путь... но не повезло.

Я надеюсь, что это что-то просто-глупое, что я просто не замечаю. Возможно, один из вас это увидит. Движущаяся часть меня пока не беспокоит. Мне нужно сначала запустить маску. Образец кода игнорирует различия по оси Y между iPhone SDK и 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 );
4b9b3361

Ответ 1

Я вернулся к этому позже после изучения других основных графических технологий. Решение ближе всего к описанному выше примеру многослойной маски. Однако вместо создания внутреннего и внешнего слоев вам необходимо объединить два пути в один UIBezierPath в противоположных направлениях.

Итак, например, создайте путь для внутренней обрезки (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)];

Затем добавьте к тому же пути внешнюю область в противоположном направлении (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)];

Этот путь затем применяется к слою (maskLayer), который используется как маска на конечном уровне (colorLayer). "Внешний слой" не требуется.