【问题标题】:Masking an image using CGLayerRef and CGContextDrawLayerInRect使用 CGLayerRef 和 CGContextDrawLayerInRect 屏蔽图像
【发布时间】:2018-07-21 21:52:40
【问题描述】:

我想在屏幕外渲染中使用 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???

【问题讨论】:

  • "我想使用 CGLayerRef 用另一张图像遮盖一张图像" 但是如果 CGLayerRef 不是一种遮盖方法怎么办?
  • 我必须使用这种方式的原因是我已经尝试了所有可能的方法来在屏幕外进行“高质量”掩蔽,是的,我曾经做过 imageView.layer.mask = maskImageView.layer 但这是低质量的屏幕遮罩。我上面的当前代码有效,但我遇到的问题是 CGContextDrawImage 和 CGContextClipToMask 显示的奇怪定位。尽管我了解 Core Graphics 使用 LLO,但蒙版的位置仍然没有意义。所以我决定使用 CGLayer,因为文档说它是高质量离屏渲染的方式。 @马特
  • "imageView.layer.mask = maskImageView.layer 但这是低质量的屏幕遮罩" 这是真的,但这只是因为您将它应用到图像视图的图层。您可以将mask 应用到任何 层,包括屏幕外的层。至于“低质量”,一切都取决于图层的contentsScale,不是吗?如果你创建了一个 CALayer 并且它不是界面的一部分,并且你忘记设置它的contentsScale,那么你只能怪你自己。
  • 重点是,我发现您的问题中的条款具有误导性。在我看来,这是一个 x-y 问题。与其坚持我们用 CGLayer 来回答,你不应该更开放一些吗?如果问题是如何掩饰,您不应该只问这个问题,而不是说“除了以下条款外不要回答”,尤其是在这些条款不合适的情况下?
  • 我之所以问“如何用 CGLayerRef 做到这一点”是因为我已经尝试了所有可能的方法。如果您有任何方法可以想出,那就更好了,关于“如果您创建一个 CALayer 并且它不是界面的一部分,并且您忘记设置它的 contentsScale”是的,我之前尝试过,但它没有t 给我高质量的蒙版图像。也许您通过 CALayer 进行遮罩的方式可以在屏幕外工作,但我不确定您如何使用它。 @马特

标签: ios objective-c uiimage core-graphics cgcontextref


【解决方案1】:

它并没有真正回答问题,但我最终使用了CGContextClipToMaskCGContextDrawImage 等传统方法,但我设法在屏蔽之前获得了我想要的高质量。再次,我需要提一下,这仅在我的情况下有效(它用渲染的贝塞尔路径掩盖了图像,但图像的全分辨率)如果您有同样的问题以获取更多信息,您可以查看我的其他 related 在这里提问

Masking an image using bezierpath with image's full resolution

还有我的 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;

【讨论】:

    【解决方案2】:

    我通常编写 Swift 代码,但曾经我还必须处理掩码和 CGLayer。

    我通过以下步骤解决了这个问题:

    1. 画出你的面具
    2. 将混合模式更改为CGBlendMode.sourceIn
    3. 绘制您的“彩色”图像。

    这是有效的,因为CGBlendMode.sourceIn 告诉上下文将源图像的 alpha 值与现有像素的颜色相乘。因此,掩码 (alpha = 0.0) 的不可见部分将保持不可见。

    CGBlendMode 的 Apple 文档:https://developer.apple.com/documentation/coregraphics/cgblendmode

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-31
      • 2015-02-26
      • 1970-01-01
      • 1970-01-01
      • 2018-10-01
      • 2014-09-24
      • 2015-01-05
      相关资源
      最近更新 更多