Reputation: 11337
Given:
ctx
) with frame {0,0,100,100}
r
), with frame {25,25,50,50}
It's easy to clip the context to that rect:
CGContextClipToRect(ctx, r);
to mask out the red area below (red == mask):
But I want to invert this clipping rect to convert it into a clipping mask. The desired outcome is to mask the red portion below (red == mask):
I want to do this programmatically at runtime.
I do not want to manually prepare a bitmap image to ship statically with my app.
Given ctx
and r
, how can this be done at runtime most easily/straightforwardly?
Upvotes: 8
Views: 2275
Reputation: 1468
Here is a helpful extension for implementing rob's answer
extension UIBezierPath {
func addClipInverse() {
let paths = UIBezierPath()
paths.append(self)
paths.append(.init(rect: .infinite))
paths.usesEvenOddFillRule = true
paths.addClip()
}
}
Upvotes: 0
Reputation: 386038
Read about fill rules in the “Filling a Path” section of the Quartz 2D Programming Guide.
In your case, the easiest thing to do is use the even-odd fill rule. Create a path consisting of your small rectangle, and a much larger rectangle:
CGContextBeginPath(ctx);
CGContextAddRect(ctx, CGRectMake(25,25,50,50));
CGContextAddRect(ctx, CGRectInfinite);
Then, intersect this path into the clipping path using the even-odd fill rule:
CGContextEOClip(ctx);
Upvotes: 19
Reputation: 3389
You could clip the context with CGContextClipToRects()
by passing rects that make up the red frame you've wanted.
Upvotes: 3
Reputation: 243156
Can you just do all your painting as normal, and then do:
CGContextClearRect(ctx, r);
after everything has been done?
Upvotes: 1