Маскирование изображения с помощью CGLayerRef и CGContextDrawLayerInRect

Я хочу замаскировать изображение другим изображением, используя CGLayerRef во внеэкранном рендеринге, поскольку он подходит для высококачественного рендеринга, как указано в документации.

Рисование слоя базовой графики: объекты CGLayer позволяют вашему приложению использовать слои для рисования. Слои подходят для следующих целей: • Качественная закадровая визуализация рисунка, который вы планируете использовать повторно.

Но я не смог найти ни одного примера в objective-c, чтобы понять, как это работает. В моем контексте я хочу замаскировать изображение с помощью изображения формы (сплошная цветная форма), которую я использовал для этого таким образом

//The context I use to mask my image with the mask image.
CGColorSpaceRef colorSpace= CGColorSpaceCreateDeviceRGB();
    CGContextRef mainViewContentContext = CGBitmapContextCreate (NULL, _bigImageRect.size.width, _bigImageRect.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);

//Mask image
CGContextClipToMask(mainViewContentContext,
                       CGRectMake(0,
                                   -_bigImageRect.origin.y,
                                   _bigImageRect.size.width,
                                   _bigImageRect.size.height),
                                   _maskImage.CGImage);

//Drawing the image on the mask image.
CGContextDrawImage(mainViewContentContext,
                       CGRectMake(0,
                                  0,
                                  _bigImageRect.size.width,
                                  _bigImageRect.size.height),
                                  _ImageToBeMasked.CGImage);

CGImageRef mainViewContentBitmapContext = CGBitmapContextCreateImage(mainViewContentContext);
CGContextRelease(mainViewContentContext);
UIImage*maskedImage = [UIImage imageWithCGImage:mainViewContentBitmapContext];
CGImageRelease(mainViewContentBitmapContext)
return maskedImage;

Но как я могу замаскировать с помощью CGLayers, как показано ниже? Я ценю любую помощь.

CGLayerRef layer = CGLayerCreateWithContext(mainViewContentContext, _bigImageRect.size, NULL);
CGContextDrawLayerInRect(mainViewContentContext, _bigImageRect, layer);
CGLayerRelease(layer);
//And then.. how can I do the masking using this CGLayerRef???

person Reza.Ab    schedule 11.02.2018    source источник
comment
Я хочу замаскировать изображение другим изображением с помощью CGLayerRef Но что, если CGLayerRef не является способом маскирования?   -  person matt    schedule 11.02.2018
comment
Причина, по которой я должен использовать этот способ, заключается в том, что я пробовал буквально все возможные способы сделать маскировку высокого качества вне экрана, да, я использовал imageView.layer.mask = maskImageView.layer, но это низкое качество на -экранная маскировка. Мой текущий код выше работает, но проблема, с которой я столкнулся, заключалась в странном позиционировании, которое показывают CGContextDrawImage и CGContextClipToMask. Хотя я понимаю, что Core Graphics использует LLO, положение маски не имеет смысла. Поэтому я решил использовать CGLayer, поскольку в документации говорится, что это способ высококачественного рендеринга вне экрана. @matt   -  person Reza.Ab    schedule 11.02.2018
comment
imageView.layer.mask = maskImageView.layer, но это низкокачественная экранная маска. Это правда, но только потому, что вы применяете ее к слою представления изображения. Вы можете применить mask к любому слою, включая тот, который находится вне экрана. А что касается низкого качества, все зависит от contentsScale слоя, не так ли? Если вы создаете CALayer, и он не является частью интерфейса, и вы забываете установить его contentsScale, тогда вы должны винить только себя.   -  person matt    schedule 11.02.2018
comment
Дело в том, что я считаю, что формулировка вашего вопроса вводит в заблуждение. Мне кажется, это вопрос х-у. Вместо того, чтобы настаивать на том, чтобы мы ответили в терминах CGLayer, не следует ли вам быть более открытым в этом вопросе? Если вопрос в том, как замаскировать, не следует ли вам просто спросить об этом, вместо того, чтобы сказать «Не отвечайте, кроме как в следующих терминах», особенно если эти термины не подходят?   -  person matt    schedule 11.02.2018
comment
Я спросил, как это сделать с помощью CGLayerRef, потому что перепробовал все возможные способы. Если есть какой-то способ, который вы можете придумать, то еще лучше и в отношении Если вы создаете CALayer, и он не является частью интерфейса, и вы забываете установить его contentScale ДА Я пробовал это раньше, и это не дает мне качественное замаскированное изображение. Возможно, ваш способ маскировки с помощью CALayer будет работать вне экрана, но я не уверен, как вы его используете. @matt   -  person Reza.Ab    schedule 11.02.2018
comment
Что ж, может быть, если вы приведете реальный пример (вот мое изображение, вот моя маска, вот желаемый результат), я смогу помочь. А может и нет, конечно. Но все эти абстрактные разговоры, идущие по дороге, в которой я не уверен, что они актуальны, нас ни к чему не приведут. Я не буду пытаться использовать CGLayer, потому что не понимаю, насколько он актуален или нужен. На самом деле, насколько мне известно, я никогда не находил применения CGLayer на практике.   -  person matt    schedule 11.02.2018
comment
Хорошо, я немного покажу код, в котором я использую CALayer со шкалой содержимого для маскировки высококачественного рендера.   -  person Reza.Ab    schedule 11.02.2018


Ответы (2)


Обычно я пишу код на Swift, но однажды мне также пришлось иметь дело с маскированием и CGLayer.

Я решил проблему, выполнив следующие действия:

  1. Нарисуй маску
  2. Измените режим наложения на CGBlendMode.sourceIn
  3. Нарисуйте свое «цветное» изображение.

Это работает, потому что CGBlendMode.sourceIn указывает контексту умножить альфа-значение исходного изображения на цвет существующего пикселя. Поэтому невидимые части маски (alpha = 0.0) останутся невидимыми.

Документы Apple для CGBlendMode: https://developer.apple.com/documentation/coregraphics/cgblendmode

person anfark    schedule 11.02.2018

На самом деле это не отвечает на вопрос, но в конце концов я использовал обычные методы, такие как CGContextClipToMask и CGContextDrawImage, но мне удалось получить желаемое высокое качество перед маскированием. Опять же, я должен упомянуть, что это работает только в моем случае (который маскировал изображение с помощью визуализированного пути Безье, но при полном разрешении изображения). Если у вас есть такая же проблема для получения дополнительной информации, вы можете проверить другие мои связанные вопрос здесь

Маскирование изображения с использованием bezierpath с полным разрешением изображения < / а>

и мой рабочий проект на github.

https://github.com/Reza-Abdolahi/HighResMasking

Вот код, который у меня сработал:

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGImageRef maskImageRef = [_maskImage CGImage];
    CGContextRef myContext = CGBitmapContextCreate (NULL, _highResolutionImage.size.width, _highResolutionImage.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
    CGColorSpaceRelease(colorSpace);
    if (myContext==NULL)
        return NULL;

    CGFloat ratio = 0;
    ratio = _maskImage.size.width/ _highResolutionImage.size.width;
    if(ratio * _highResolutionImage.size.height < _maskImage.size.height) {
        ratio = _maskImage.size.height/ _highResolutionImage.size.height;
    }

    CGRect rectForMask  = {{0, 0}, {_maskImage.size.width, _maskImage.size.height}};
    CGRect rectForImageDrawing  = {{-((_highResolutionImage.size.width*ratio)-_maskImage.size.width)/2 , -((_highResolutionImage.size.height*ratio)-_maskImage.size.height)/2},
        {_highResolutionImage.size.width*ratio, _highResolutionImage.size.height*ratio}};

    CGContextClipToMask(myContext, rectForMask, maskImageRef);
    CGContextDrawImage(myContext, rectForImageDrawing, _highResolutionImage.CGImage);
    CGImageRef newImage = CGBitmapContextCreateImage(myContext);
    CGContextRelease(myContext);
    UIImage *theImage = [UIImage imageWithCGImage:newImage];
    CGImageRelease(newImage);
    return theImage;
person Reza.Ab    schedule 11.02.2018