4

这就是我想要做的:左边是一个通用的、未着色的 RGBA 图像,我在屏幕外创建并缓存了速度(最初创建速度很慢,但以后用任何颜色着色都非常快,如需要)。这是一个带有圆形漩涡的方形图像。在圆圈内,图像的 alpha/opacity 为 1。在圆圈外,它的 alpha/opacity 为 0。我在 UIView 中显示了它,背景颜色为[UIColor scrollViewTexturedBackgroundColor]. 右边是当我尝试通过在设置后在其顶部填充一个纯红色矩形来为图像着色时发生的情况CGContextSetBlendMode(context, kCGBlendModeColor)

未着色 着色不正确

这不是我想要的,也不是我所期望的。显然,出于某种奇怪的原因,对完全透明的像素(例如,alpha 值为 0)进行着色会导致完全填充颜色,而不是像我预期的那样保持透明。

我想要的实际上是这样的:

正确着色

现在,在这种特殊情况下,我可以将剪切区域设置为一个圆圈,这样圆圈之外的区域就不会受到影响——这就是我在这里所做的一种解决方法。

但在我的应用程序中,我还需要能够为我不知道剪切/轮廓路径的任意形状着色。一个示例是通过叠加渐变来为白色文本着色。这是怎么做到的?我怀疑必须有某种方法可以有效地做到这一点——通常,没有奇怪的路径/剪辑技巧——使用图像蒙版……但我还没有找到关于这方面的教程。显然这是可能的,因为我在其他游戏中看到过彩色渐变文本。

顺便说一句,我不能从渐变开始,然后剪裁/清除我不需要的部分——因为(如上例所示)我的未着色源图像通常是灰度而不是纯白色。所以我真的需要从未着色的图像开始,然后对其进行着色。

ps —kCGBlendModeMultiply在为部分透明的图像着色时也有相同的缺陷/缺点/特质。有谁知道为什么苹果决定这样做?就好像 Quartz 着色代码将 RGBA(0,0,0,0) 视为 RGBA(0,0,0,1),即它完全忽略并破坏了 alpha 通道。

4

1 回答 1

1

您可以采用的一种可行的方法是从原始图像构造一个蒙版,然后在使用多重混合模式集渲染图像之前调用 CGContextClipToMask() 方法。这是在将图像绘制为彩色之前设置遮罩的 CoreGraphics 代码。

  CGContextRef context = [frameBuffer createBitmapContext];
  CGRect bounds = CGRectMake( 0.0f, 0.0f, width, height );
  CGContextClipToMask(context, bounds, maskImage.CGImage);
  CGContextDrawImage(context, bounds, greyImage.CGImage);

稍微棘手的部分是获取原始图像并生成一个 maskImage。为此,您可以编写一个循环来检查每个像素并写入一个黑色或白色像素作为掩码值。如果图像中要着色的原始像素是完全透明的,则写入黑色像素,否则写入白色像素。请注意,掩码值将是 24BPP 图像。这里有一些代码可以给你正确的想法。

  uint32_t *inPixels = (uint32_t*) MEMORY_ADDR_OF_ORIGINAL_IMAGE;
  uint32_t *maskPixels = malloc(numPixels * sizeof(uint32_t));
  uint32_t *maskPixelsPtr = maskPixels;

  for (int rowi = 0; rowi < height; rowi++) {
    for (int coli = 0; coli < width; coli++) {
      uint32_t inPixel = *inPixels++;
      uint32_t inAlpha = (inPixel >> 24) & 0xFF;
      uint32_t cval = 0;
      if (inAlpha != 0) {
        cval = 0xFF;
      }
      uint32_t outPixel = (0xFF << 24) | (cval << 16) | (cval << 8) | cval;
      *maskPixelsPtr++ = outPixel;
    }
  }

您当然需要填写所有细节并创建图形上下文等。但总体思路是简单地创建自己的蒙版,以过滤掉圆圈外部红色部分的绘制。

于 2013-03-21T06:52:06.647 回答