Search code examples
iosobjective-ccore-graphicsuibezierpath

Remove outside of bezier path


I have a function where I fill the image with a color and use a UIBezierPath to erase a point for corners.

CGRect rect = CGRectMake(0.0f, 0.0f, width, height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();

CGContextSetBlendMode(context, kCGBlendModeCopy);

// Fill image
CGContextSetFillColorWithColor(context, [[UIColor redColor] CGColor]);
CGContextFillRect(context, rect);

// Round corners
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:15.0];
CGContextSetStrokeColorWithColor(context, [[UIColor clearColor] CGColor]);
[bezierPath stroke];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

With the above, I get an image that does have the Bézier path cut out, and the background filled. Icon with Bézier path cut out

However, how can I remove the corners outside of the path, or get at least some way to reference where they are so I can clear them?


Solution

  • A couple of options:

    1. Use CoreGraphics, like you have, but clip it to a path:

      CGRect rect = CGRectMake(0.0f, 0.0f, width, height);
      
      UIGraphicsBeginImageContextWithOptions(rect.size, false, 0);
      CGContextRef context = UIGraphicsGetCurrentContext();
      CGContextSetBlendMode(context, kCGBlendModeCopy);
      
      // Round corners
      UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:15.0];
      CGContextAddPath(context, bezierPath.CGPath);
      CGContextClip(context);
      
      // Fill image
      CGContextSetFillColorWithColor(context, [[UIColor redColor] CGColor]);
      CGContextFillRect(context, rect);
      
      UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();
      
    2. Alternatively, eliminate CoreGraphics and just fill the UIBezierPath:

      UIGraphicsBeginImageContextWithOptions(rect.size, false, 0);
      [[UIColor redColor] setFill];
      [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:15.0] fill];
      UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();
      

    Note, in both of those examples, I used UIGraphicsBeginImageContextWithOptions, supplying a scale of 0 (a scale optimized for display on the device in question). If you really want, you can supply a scale of 1, which obviously will be a bit pixelated when rendered on a retina device, but that's up to you.