我正在尝试使用CGContextSetBlendMode实现html5 canvas globalCompositeOperation并将html5 canvas运算符(源代码输入,source-atop等)转换为其CGBlendMode对应项(kCGBlendModeSourceIn,kCGBlendModeSourceAtop等)。
这是根据规格的预期结果:
使用CGContextSetBlendMode,我得到了这个:
一些结果是错误的。例如,source-out(在Quartz 2D中为kCGBlendModeSourceOut)不会剪切蓝色矩形。
我不确定哪种实现是正确的。但是我的问题是,是否有解决方法?经过一番修补,我想出了以下解决方案,该解决方案在应用操作之前会先对目标进行预处理:
裁剪除来源以外的所有内容(即红色圆圈)
删除目的地(仅将图像保留在圆圈中)
这是执行此操作的预处理步骤(假设源路径已设置):
auto save = CGContextCopyPath(ctx);
CGContextSaveGState(ctx);
CGContextAddRect(ctx, CGRectInfinite);
CGContextEOClip(ctx);
CGContextSetBlendMode(ctx, kCGBlendModeClear);
CGContextAddRect(ctx, CGRectInfinite);
CGContextFillPath(ctx);
CGContextRestoreGState(ctx);
CGContextAddPath(ctx, save);
CGPathRelease(save);
有了变通办法,我几乎得到了我想要的:
除了源输出中的工件外,在圆圈轮廓中带有一些(抗锯齿?)条纹。
有没有更好的办法?我做错了吗?我想念什么吗?
预先非常感谢您,请原谅这个冗长的问题。
最佳答案
混合模式是通过一个函数实现的,该函数基本上接受两种颜色(每种颜色来自一种来源)作为输入,并为您提供最终的颜色作为输出。
f(a,b) = c
在您的示例中,我们可以假设蓝色矩形来自一个来源
a
,红色圆圈来自另一个来源b
。我对Quartz 2D并不熟悉,但是如果它具有直接访问每个像素颜色的API,那么您可以遍历两个来源的像素,为每个像素调用一个混合函数并获得结果图像。c[1][1] = f(a[1][1], b[1][1])
c[1][2] = f(a[1][2], b[1][2])
...
c[n][m] = f(a[n][m], b[n][m])
其中
n
和m
-图像宽度和高度分别以像素为单位。请注意,遍历像素可能是一项昂贵的操作,尤其是在处理高分辨率图像时。
关于
source-out
-它是Porter / Duff合成运算符之一,在某种程度上类似于混合模式。除了两种颜色外,还需要这些颜色的Alpha通道值。 Alpha值表示在最终结果中应表示每个源的数量,并且根据要使用的运算符来使用或丢弃此“参与”值。function sourceOut(aColor, bColor, aAlpha, bAlpha) {
return bAlpha * (1 - aAlpha) * bColor;
}
See JSBin with full example
参考:
Alpha compositing
W3C Compositing and Blending Level 1 - 9. Advanced compositingfeatures
Søren Sandmann Pedersen - Porter/Duff Compositing and BlendModes