12

I'm trying to create an image for a custom style UIButton using an image from the camera roll on iPhone. The button has a circular background and effectively appears as a circle. Now I need an image to go in the middle of the button that also appears round.

How do I cut a square UIImage to appear round with transparency outside of the round area?

If masking is involved, do I need to pre-render a mask or can I create one programmatically(ex: a circle)?

Thank you!

Alex Stone
  • 46,408
  • 55
  • 231
  • 407

10 Answers10

28

I have never done anything like that, but try using QuartzCore framework and its' cornerRadius property. Example:

#import <QuartzCore/QuartzCore.h>
//some other code ...
UIImageView *imgView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
imgView.layer.cornerRadius = 10.0f;

play around with it a bit and you will get what you want.

Hope it helps

Novarg
  • 7,390
  • 3
  • 38
  • 74
  • 12
    @AlexStone - you need to imgView.clipsToBounds = YES – evanflash Mar 22 '13 at 14:27
  • Here's why I like this solution, even though it's limited only to a circle: For the common case in which you'll be loading an image into the UIImageView dynamically (and likely changing the image, as when reusing a table view cell) this solution lets you set the mask once and have it apply forever. The other solutions here, while more general, require you to apply the mask every time you load a new image. Also, this one is one line :-) – evanflash Mar 22 '13 at 14:30
  • 12
    also, for a circle, cornerRadius = imageView.frame.size.width / 2 – evanflash Mar 22 '13 at 14:32
  • cell.imageView.layer.cornerRadius = cell.imageView.frame.size.width / 2 As like Evan said, above line Works Perfectly.....Thanks Evan – Hari1251 Dec 19 '13 at 06:26
  • 1
    Why this has so many upvotes? The question is not about UIImageView – deej Aug 24 '14 at 16:27
13

Yes you can use CoreGraphics to draw the mask dynamically. Then you can create the masked image.

Example for masking:

- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage
{
  CGImageRef maskRef = maskImage.CGImage;
  CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                      CGImageGetHeight(maskRef),
                                      CGImageGetBitsPerComponent(maskRef),
                                      CGImageGetBitsPerPixel(maskRef),
                                      CGImageGetBytesPerRow(maskRef),
                                      CGImageGetDataProvider(maskRef), NULL, false);

  CGImageRef maskedImageRef = CGImageCreateWithMask([image CGImage], mask);
  UIImage *maskedImage = [UIImage imageWithCGImage:maskedImageRef];
  CGImageRelease(maskedImageRef);
  CGImageRelease(mask);
  return maskedImage;
}
calimarkus
  • 9,955
  • 2
  • 28
  • 48
  • I want to show image in circle shape. So that we can see only circular path and other path remains transparent. – Alfa Dec 16 '13 at 08:14
  • 2
    Don't forget to release the created mask and image or you'll be leaking memory (*ARC* does not deal with *CoreGraphics*'s opaque types). Do this `CGImageRef maskedImageRef = CGImageCreateWithMask([image CGImage], mask); UIImage *maskedImage = [UIImage imageWithCGImage:masked]; CGImageRelease(maskImageRef); CGImageRelease(maskedImageRef); return maskedImage;`. – Ricardo Sanchez-Saez Aug 19 '15 at 15:20
7

I started looking into this a couple of weeks back. I tried all the suggestions here, none of which worked well. In the great tradition of RTFM I went and read Apple's documentation on Quartz 2D Programming and came up with this. Please try it out and let me know how you go.

The code could be fairly easily altered to crop to an elipse, or any other shape defined by a path.

Make sure you include Quartz 2D in your project.

#include <math.h>

+ (UIImage*)circularScaleNCrop:(UIImage*)image: (CGRect) rect{
    // This function returns a newImage, based on image, that has been:
    // - scaled to fit in (CGRect) rect
    // - and cropped within a circle of radius: rectWidth/2

    //Create the bitmap graphics context
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(rect.size.width, rect.size.height), NO, 0.0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    //Get the width and heights
    CGFloat imageWidth = image.size.width;
    CGFloat imageHeight = image.size.height;
    CGFloat rectWidth = rect.size.width;
    CGFloat rectHeight = rect.size.height;

    //Calculate the scale factor
    CGFloat scaleFactorX = rectWidth/imageWidth;
    CGFloat scaleFactorY = rectHeight/imageHeight;

    //Calculate the centre of the circle
    CGFloat imageCentreX = rectWidth/2;
    CGFloat imageCentreY = rectHeight/2;

    // Create and CLIP to a CIRCULAR Path
    // (This could be replaced with any closed path if you want a different shaped clip)
    CGFloat radius = rectWidth/2;
    CGContextBeginPath (context);
    CGContextAddArc (context, imageCentreX, imageCentreY, radius, 0, 2*M_PI, 0);
    CGContextClosePath (context);
    CGContextClip (context);

    //Set the SCALE factor for the graphics context
    //All future draw calls will be scaled by this factor
    CGContextScaleCTM (context, scaleFactorX, scaleFactorY);    

    // Draw the IMAGE
    CGRect myRect = CGRectMake(0, 0, imageWidth, imageHeight);
    [image drawInRect:myRect];

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

    return newImage;
}

Include the following code in your UIView class replacing "monk2.png" with your own image name.

- (void)drawRect:(CGRect)rect
{

    UIImage *originalImage = [UIImage imageNamed:[NSString stringWithFormat:@"monk2.png"]];
    CGFloat oImageWidth = originalImage.size.width;
    CGFloat oImageHeight = originalImage.size.height;
    // Draw the original image at the origin
    CGRect oRect = CGRectMake(0, 0, oImageWidth, oImageHeight);
    [originalImage drawInRect:oRect];

    // Set the newRect to half the size of the original image 
    CGRect newRect = CGRectMake(0, 0, oImageWidth/2, oImageHeight/2);
    UIImage *newImage = [self circularScaleNCrop:originalImage :newRect];

    CGFloat nImageWidth = newImage.size.width;
    CGFloat nImageHeight = newImage.size.height;

    //Draw the scaled and cropped image
    CGRect thisRect = CGRectMake(oImageWidth+10, 0, nImageWidth, nImageHeight);
    [newImage drawInRect:thisRect];

}
Chris Nelson
  • 466
  • 5
  • 4
6

Here is a quick way to create rounded corners on a square ImageView to make it look like a perfect circle. Basically you apply a corner radius equal to 1/2 the width (width == height on a square image).

#import <QuartzCore/QuartzCore.h> //you need QuartzCore
...

float width = imageView.bounds.size.width;  // we can also use the frame property instead of bounds since we just care about the Size and don't care about position
imageView.layer.cornerRadius = width/2;
ndnguru
  • 91
  • 1
  • 6
6
{
    imageView.layer.cornerRadius =  imageView.frame.size.height /2;
    imageView.layer.masksToBounds = YES;
    imageView.layer.borderWidth = 0;
}
slavoo
  • 5,798
  • 64
  • 37
  • 39
AP_
  • 1,013
  • 12
  • 13
5

UIImage category to mask an image with a circle:

UIImage *originalImage = [UIImage imageNamed:@"myimage.png"];
UImage *myRoundedImage = [UIImage roundedImageWithImage:originalImage];

Get it here.

Jagat Dave
  • 1,643
  • 3
  • 23
  • 30
Nikolay Dyankov
  • 6,491
  • 11
  • 58
  • 79
2

I have another solution:

- (UIImage *)roundedImageWithRect:(CGRect)rect radius:(CGFloat)radius
{
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, rect.size.width, rect.size.height) cornerRadius:radius];

CGFloat imageRatio = self.size.width / self.size.height;
CGSize imageSize = CGSizeMake(rect.size.height * imageRatio, rect.size.height);
CGRect imageRect = CGRectMake(0, 0, imageSize.width, imageSize.height);

[path addClip];
[self drawInRect:imageRect];

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

return image;

}

This variant is better for performance than set cornerRadius directly.

Igor
  • 4,235
  • 3
  • 34
  • 32
0

Following is the answer I given in How to crop UIImage on oval shape or circle shape? to make the image circle. It works for me..

Download the Support archive file

#import "UIImage+RoundedCorner.h"
#import "UIImage+Resize.h"

Following lines used to resize the image and convert in to round with radius

UIImage *mask = [UIImage imageNamed:@"mask.jpg"];

mask = [mask resizedImage:CGSizeMake(47, 47) interpolationQuality:kCGInterpolationHigh ];
mask = [mask roundedCornerImage:23.5 borderSize:1];
Community
  • 1
  • 1
Dilip Rajkumar
  • 7,006
  • 6
  • 60
  • 76
0

Just use

_profilePictureImgView.layer.cornerRadius = 32.0f;
_profilePictureImgView.layer.masksToBounds = YES;  
n.by.n
  • 2,458
  • 22
  • 31
0

Personally, I'd create a transparent circle image with opaque corners to overlay the photo. This solution is only suitable where you will be placing the image in one place on the UI, and assumes the opaque corners will blend in with the background.

aaroncatlin
  • 3,203
  • 1
  • 16
  • 27