以下是我要做的事情:左侧是一个通用的,未着色的RGBA图像,我在屏幕外创建并缓存速度(最初创建速度非常慢,但是根据需要,以后可以很快地用任何颜色着色。这是一个圆形漩涡的方形图像。在圆圈内,图像的alpha /不透明度为1.在圆圈外,它的alpha /不透明度为0.我在UIView中显示了它,背景颜色为[UIColor scrollViewTexturedBackgroundColor]
。 右侧是指在设置CGContextSetBlendMode(context, kCGBlendModeColor)
后,通过在图像顶部填充一个红色的固定矩形来尝试着色图像时会发生的情况。
这不是我想要的,也不是我的预期。显然,为完全透明的像素着色(例如,alpha值为0)会导致完全填充颜色出于某种奇怪的原因,而不是像我预期的那样保持透明。
我想要的是这个:
现在,在这种特殊情况下,我可以将剪裁区域设置为圆形,这样圆圈外的区域保持不变 - 这就是我在这里所做的解决方法。 / p>
但在我的应用程序中,我还需要能够着色任意形状,我不知道剪切/轮廓路径。一个例子是通过叠加渐变来着色白色文本。这是怎么做到的?我怀疑必须有一些方法来有效地做到这一点 - 通常,没有奇怪的路径/剪辑技巧 - 使用图像掩码......但我还没有找到这方面的教程。显然这是可能的,因为我在其他游戏中看过彩色渐变文本。
顺便提一下,我不能做的是从渐变开始,剪掉/清除掉我不需要的部分 - 因为(如上例所示)我的未着色源图像通常是灰度而不是纯粹的白色。所以我真的需要从未着色的图像开始,然后着色它。
P.S。 - kCGBlendModeMultiply
在部分透明图像着色时也有相同的缺陷/缺点/特性。有谁知道为什么 Apple决定这样做?就好像Quartz着色代码将RGBA(0,0,0,0)视为RGBA(0,0,0,1),即它完全忽略并破坏了alpha通道。
答案 0 :(得分: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;
}
}
您当然需要填写所有细节并创建图形上下文等。但一般的想法是简单地创建自己的蒙版来过滤出圆圈外部的红色部分的绘制。