Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CGContextClip() using an inverted path

I want to have clipped drawing on my CGContext but I need it just the other way round, i.e. I want to add several rectangles to my clipping path using CGContextAddRect() and the clipping should be done in the way that all the rectangles that I have added to my clipping path stay unaffected by any drawing operations. Normally, it's just the other way round, i.e. drawing functions draw to the rectangles that have been added to the clipping path and leave the areas that haven't been added to the clipping path unaffected. So I guess what I need is just a way to reverse the clipping path before calling CGContextClip(). Back in the QuickDraw days, this could by easily done by using regions and then calling XorRgn() for every rectangle. But with Quartz it seems to be more complicated. Does anyone have an easy solution for achieving this or do I need to do all these path reversing calculations on my own?

like image 453
Andreas Avatar asked May 17 '12 14:05

Andreas


2 Answers

You could add your entire bounds as a rectangle, then add the rectangles you want to exclude from drawing and use CGContextEOClip.

Example:

- (void)drawRect:(NSRect)dirtyRect
    CGContextRef ctx = [[NSGraphicsContext currentContext] graphicsPort];
    //Fill the background with gray:
    CGContextSetRGBFillColor(ctx, 0.5, 0.5, 0.5, 1);
    CGContextFillRect(ctx, NSRectToCGRect(self.bounds));
    CGContextAddRect(ctx, NSRectToCGRect(self.bounds));
    //Add some rectangles:
    CGContextAddRect(ctx, CGRectMake(10, 10, 100, 100));
    CGContextAddRect(ctx, CGRectMake(120, 120, 50, 100));
    //Clip:
    CGContextEOClip(ctx);
    //Fill the entire bounds with red:
    CGContextSetRGBFillColor(ctx, 1.0, 0.0, 0.0, 1.0);
    CGContextFillRect(ctx, NSRectToCGRect(self.bounds));
}

The effect becomes more obvious if you draw an image at the end instead of filling a red rectangle.

like image 68
omz Avatar answered Sep 21 '22 11:09

omz


One way would be to draw the clipping path to a bitmap context, invert the resulting bitmap, and use it as a mask on the original image by calling CGContextClipToMask().

like image 28
user1118321 Avatar answered Sep 18 '22 11:09

user1118321