How to mask a square image into an image with round corners in iOS?
You can use CoreGraphics to create a path for a round rectangle with this code snippet:
static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight){ float fw, fh; if (ovalWidth == 0 || ovalHeight == 0) { CGContextAddRect(context, rect); return; } CGContextSaveGState(context); CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect)); CGContextScaleCTM (context, ovalWidth, ovalHeight); fw = CGRectGetWidth (rect) / ovalWidth; fh = CGRectGetHeight (rect) / ovalHeight; CGContextMoveToPoint(context, fw, fh/2); CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1); CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1); CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1); CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1); CGContextClosePath(context); CGContextRestoreGState(context);}
And then call CGContextClip(context); to clip it to the rectangle path. Now any drawing done, including drawing an image, will be clipped to the round rectangle shape.
As an example, assuming "image" is a UIImage, and this is in a drawRect: method:
CGContextRef context = UIGraphicsGetCurrentContext();CGContextSaveGState(context);addRoundedRectToPath(context, self.frame, 10, 10);CGContextClip(context);[image drawInRect:self.frame];CGContextRestoreGState(context);
Here is an even easier method that is available in iPhone 3.0 and up. Every View-based object has an associated layer. Each layer can have a corner radius set, this will give you just what you want:
UIImageView * roundedView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"wood.jpg"]];// Get the Layer of any viewCALayer * layer = [roundedView layer];[layer setMasksToBounds:YES];[layer setCornerRadius:10.0];// You can even add a border[layer setBorderWidth:4.0];[layer setBorderColor:[[UIColor blueColor] CGColor]];
To use these methods you might need to add:
#import <QuartzCore/QuartzCore.h>
I realize this is old news but just to boil it down a bit:
There are two possible questions here: (1) how do I apply rounded corners to a UIView (such as a UIImageView), which will be displayed on screen, and (2) how do I mask a square image (that is, a UIImage) to produce a new image with rounded corners.
For (1), the easiest course is to use CoreAnimation and set the view.layer.cornerRadius property
// Because we're using CoreAnimation, we must include QuartzCore.h // and link QuartzCore.framework in a build phases #import <QuartzCore/QuartzCore.h> // start with an image UIImage * fooImage = [UIImage imageNamed:@"foo.png"]; // put it in a UIImageView UIView * view = [UIImageView alloc] initWithImage:fooImage]; // round its corners. This mask now applies to the view's layer's *background* view.layer.cornerRadius = 10.f // enable masksToBounds, so the mask applies to its foreground, the image view.layer.masksToBounds = YES;
For (2), the best way is to use the UIKit graphics operations:
// start with an image UIImage * fooImage = [UIImage imageNamed:@"foo.png"];CGRect imageRect = CGRectMake(0, 0, fooImage.size.width, fooImage.size.height);// set the implicit graphics context ("canvas") to a bitmap context for imagesUIGraphicsBeginImageContextWithOptions(imageRect.size,NO,0.0);// create a bezier path defining rounded cornersUIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:10.f];// use this path for clipping in the implicit context[path addClip];// draw the image into the implicit context[fooImage drawInRect:imageRect];// save the clipped image from the implicit context into an image UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();// cleanupUIGraphicsEndImageContext();
What's tricky about problem (2) is that you might think you could do the whole operation using the view.layer.mask property in CoreAnimation. But you can't because the CALayer renderInContext:
method, which you'd use to generate a UIImage from the masked layer, seems to ignore the mask. Worse, the documentation for renderInContext:
doesn't mention this, and only alludes to the behavior for OSX 10.5.
Some further context: the above approach to (2) is using UIKit's wrappers around more basic CoreGraphics functionality. You can do the same thing using the CoreGraphics calls directly – that is what the chosen answer is doing -- but then you need build the rounded rect bezier path manually from curves and lines and you also need to compensate for the fact that CoreGraphics uses a drawing coordinate system which is flipped with respect to UIKit's.