I am trying to implement html5 canvas globalCompositeOperation using CGContextSetBlendMode and translating the html5 canvas operators (source-in, source-atop, etc.) to its CGBlendMode counterparts (kCGBlendModeSourceIn, kCGBlendModeSourceAtop, etc.).
Here's the expected results according to the specs:
With CGContextSetBlendMode, I get this instead:
Some of the results are wrong. For example, source-out (kCGBlendModeSourceOut in Quartz 2D), does not clip the blue rectangle.
Which implementation is correct, I am not sure. But my question is, is there a workaround? After some tinkering, I came up with this solution that preprocesses the destination before applying the operation:
- Clip everything except the source (i.e the red circle)
- Erase the destination (leaving only the image in the circle)
Here's the preprocessing step that does that (assuming the source path is already set):
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);
With the workaround, I get almost what I want:
except for that artifact in source-out with some (anti-aliasing?) fringes in the circle's outline.
Is there a better way? Am I doing it wrong? Am I missing something?
Thank you very much in advance, and please pardon this longish question.




Blending modes are implemented by a function which basically accepts two colors (each from one source) as an input and gives you resulting color as an output.
In your example we can assume that blue rectangle comes from one source
a, and red circle comes from the other sourceb. I am not familiar with Quartz 2D, but if it has an API to directly access colors of each pixel, then you could walk over the pixels from both sources, call a blending function per pixel and get a resulting image.where
nandm- image width and height in pixels respectively.Be aware that walking over pixels might be an expensive operation, especially if you work with images of high resolution.
Regarding
source-out- it is one of the Porter/Duff compositing operators, which is somewhat similar to blending modes. Besides two colors it also needs an alpha channel values for these colors. Alpha value represents how much of each source should be represented in the final result, and this "participation" value is either used or discarded depending on the operator you want to use.See JSBin with full example
Reference: