UIImage rounded corners

IphoneCocoa Touch

Iphone Problem Overview


I try to get rounded corners on a UIImage, what I read so far, the easiest way is to use a mask images. For this I used code from TheElements iPhone Example and some image resize code I found. My problem is that resizedImage is always nil and I don't find the error...

- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize
{
	CGSize imageSize = [self size];
	float width = imageSize.width;
	float height = imageSize.height;
	
	// scaleFactor will be the fraction that we'll
	// use to adjust the size. For example, if we shrink
	// an image by half, scaleFactor will be 0.5. the
	// scaledWidth and scaledHeight will be the original,
	// multiplied by the scaleFactor.
	//
	// IMPORTANT: the "targetHeight" is the size of the space
	// we're drawing into. The "scaledHeight" is the height that
	// the image actually is drawn at, once we take into
	// account the ideal of maintaining proportions
	
	float scaleFactor = 0.0; 
	float scaledWidth = targetSize.width;
	float scaledHeight = targetSize.height;
	
	CGPoint thumbnailPoint = CGPointMake(0,0);
	
	// since not all images are square, we want to scale
	// proportionately. To do this, we find the longest
	// edge and use that as a guide.
	
	if ( CGSizeEqualToSize(imageSize, targetSize) == NO )
	{ 
		// use the longeset edge as a guide. if the
		// image is wider than tall, we'll figure out
		// the scale factor by dividing it by the
		// intended width. Otherwise, we'll use the
		// height.
		
		float widthFactor = targetSize.width / width;
		float heightFactor = targetSize.height / height;
		
		if ( widthFactor < heightFactor )
			scaleFactor = widthFactor;
		else
			scaleFactor = heightFactor;
		
		// ex: 500 * 0.5 = 250 (newWidth)
		
		scaledWidth = width * scaleFactor;
		scaledHeight = height * scaleFactor;
		
		// center the thumbnail in the frame. if
		// wider than tall, we need to adjust the
		// vertical drawing point (y axis)
		
		if ( widthFactor < heightFactor )
			thumbnailPoint.y = (targetSize.height - scaledHeight) * 0.5;
		
		else if ( widthFactor > heightFactor )
			thumbnailPoint.x = (targetSize.width - scaledWidth) * 0.5;
	}
	
	
	CGContextRef mainViewContentContext;
    CGColorSpaceRef colorSpace;
	
    colorSpace = CGColorSpaceCreateDeviceRGB();
	
	// create a bitmap graphics context the size of the image
    mainViewContentContext = CGBitmapContextCreate (NULL, targetSize.width, targetSize.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
	
	// free the rgb colorspace
    CGColorSpaceRelease(colorSpace);	
	
	if (mainViewContentContext==NULL)
		return NULL;

	//CGContextSetFillColorWithColor(mainViewContentContext, [[UIColor whiteColor] CGColor]);
	//CGContextFillRect(mainViewContentContext, CGRectMake(0, 0, targetSize.width, targetSize.height));
	
	CGContextDrawImage(mainViewContentContext, CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledWidth, scaledHeight), self.CGImage);

	// Create CGImageRef of the main view bitmap content, and then
	// release that bitmap context
	CGImageRef mainViewContentBitmapContext = CGBitmapContextCreateImage(mainViewContentContext);
	CGContextRelease(mainViewContentContext);
	
	CGImageRef maskImage = [[UIImage imageNamed:@"Mask.png"] CGImage];
	
	CGImageRef resizedImage = CGImageCreateWithMask(mainViewContentBitmapContext, maskImage);
	CGImageRelease(mainViewContentBitmapContext);
	
	// convert the finished resized image to a UIImage 
	UIImage *theImage = [UIImage imageWithCGImage:resizedImage];

	// image is retained by the property setting above, so we can 
	// release the original
	CGImageRelease(resizedImage);
	
	// return the image
	return theImage;
}

Iphone Solutions


Solution 1 - Iphone

If you are using a UIImageView to display the image you can simply do the following:

imageView.layer.cornerRadius = 5.0;
imageView.layer.masksToBounds = YES;

And to add a border:

imageView.layer.borderColor = [UIColor lightGrayColor].CGColor;
imageView.layer.borderWidth = 1.0;

I believe that you'll have to import <QuartzCore/QuartzCore.h> and link against it for the above code to work.

Solution 2 - Iphone

How about these lines...

// Get your image somehow
UIImage *image = [UIImage imageNamed:@"image.jpg"];

// Begin a new image that will be the new image with the rounded corners 
// (here with the size of an UIImageView)
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);

// Add a clip before drawing anything, in the shape of an rounded rect
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds                             cornerRadius:10.0] addClip];
// Draw your image
[image drawInRect:imageView.bounds];

// Get the image, here setting the UIImageView image
imageView.image = UIGraphicsGetImageFromCurrentImageContext();

// Lets forget about that we were drawing
UIGraphicsEndImageContext();

Solution 3 - Iphone

I created an UIImage-extension in swift, based on @epatel's great answer:

extension UIImage{
    var roundedImage: UIImage {
        let rect = CGRect(origin:CGPoint(x: 0, y: 0), size: self.size)
        UIGraphicsBeginImageContextWithOptions(self.size, false, 1)
        defer { 
            // End context after returning to avoid memory leak
            UIGraphicsEndImageContext() 
        }
       
        UIBezierPath(
            roundedRect: rect,
            cornerRadius: self.size.height
            ).addClip()
        self.drawInRect(rect)
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}

Tested in a storyboard:

storyboard

Solution 4 - Iphone

The problem was the use of CGImageCreateWithMask which returned an all black image. The solution I found was to use CGContextClipToMask instead:

CGContextRef mainViewContentContext;
CGColorSpaceRef colorSpace;

colorSpace = CGColorSpaceCreateDeviceRGB();

// create a bitmap graphics context the size of the image
mainViewContentContext = CGBitmapContextCreate (NULL, targetSize.width, targetSize.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);

// free the rgb colorspace
CGColorSpaceRelease(colorSpace);    

if (mainViewContentContext==NULL)
	return NULL;

CGImageRef maskImage = [[UIImage imageNamed:@"mask.png"] CGImage];
CGContextClipToMask(mainViewContentContext, CGRectMake(0, 0, targetSize.width, targetSize.height), maskImage);
CGContextDrawImage(mainViewContentContext, CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledWidth, scaledHeight), self.CGImage);


// Create CGImageRef of the main view bitmap content, and then
// release that bitmap context
CGImageRef mainViewContentBitmapContext = CGBitmapContextCreateImage(mainViewContentContext);
CGContextRelease(mainViewContentContext);

// convert the finished resized image to a UIImage 
UIImage *theImage = [UIImage imageWithCGImage:mainViewContentBitmapContext];
// image is retained by the property setting above, so we can 
// release the original
CGImageRelease(mainViewContentBitmapContext);

// return the image
return theImage;

Solution 5 - Iphone

Extending Besi's excellent answer, with correct scale, in Swift 4:

extension UIImage {

    public func rounded(radius: CGFloat) -> UIImage {
        let rect = CGRect(origin: .zero, size: size)
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        UIBezierPath(roundedRect: rect, cornerRadius: radius).addClip()
        draw(in: rect)
        return UIGraphicsGetImageFromCurrentImageContext()!
    }

}

Solution 6 - Iphone

You aren't actually doing anything other than scaling there. What you need to do is to "mask" the corners of the image by clipping it with a CGPath. For instance -

 - (void)drawRect:(CGRect)rect {
	CGContextRef context = UIGraphicsGetCurrentContext();
	CGContextBeginTransparencyLayerWithRect(context, self.frame, NULL);
	CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);	
	CGFloat roundRadius = (radius) ? radius : 12.0;
	CGFloat minx = CGRectGetMinX(self.frame), midx = CGRectGetMidX(self.frame), maxx = CGRectGetMaxX(self.frame);
	CGFloat miny = CGRectGetMinY(self.frame), midy = CGRectGetMidY(self.frame), maxy = CGRectGetMaxY(self.frame);

	// draw the arcs, handle paths
	CGContextMoveToPoint(context, minx, midy);
	CGContextAddArcToPoint(context, minx, miny, midx, miny, roundRadius);
	CGContextAddArcToPoint(context, maxx, miny, maxx, midy, roundRadius);
	CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, roundRadius);
	CGContextAddArcToPoint(context, minx, maxy, minx, midy, roundRadius);
	CGContextClosePath(context);
	CGContextDrawPath(context, kCGPathFill);
	CGContextEndTransparencyLayer(context);
}

I suggest checking out the Quartz 2D programming guide or some other samples.

Solution 7 - Iphone

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);
}

+ (UIImage *)imageWithRoundCorner:(UIImage*)img andCornerSize:(CGSize)size
{
	UIImage * newImage = nil;
  
	if( nil != img)
	{
	   @autoreleasepool {
		int w = img.size.width;
		int h = img.size.height;
    
		CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
		CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
    
		CGContextBeginPath(context);
		CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
		addRoundedRectToPath(context, rect, size.width, size.height);
		CGContextClosePath(context);
		CGContextClip(context);
    
		CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
    
		CGImageRef imageMasked = CGBitmapContextCreateImage(context);
		CGContextRelease(context);
		CGColorSpaceRelease(colorSpace);
		[img release];
    
		newImage = [[UIImage imageWithCGImage:imageMasked] retain];
		CGImageRelease(imageMasked);
    
	   }
	}
  
  return newImage;
}

Solution 8 - Iphone

I think this could be very related: In iOS 11 there is a very elgant way of rounding each single corner of a (Image)View.

let imageView = UIImageView(image: UIImage(named: "myImage"))    
imageView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
imageView.layer.cornerRadius = 10.0

Solution 9 - Iphone

The reason it worked with clipping, not with masking, seems to be the color space.

Apple Documentation's below.

mask A mask. If the mask is an image, it must be in the DeviceGray color space, must not have an alpha component, and may not itself be masked by an image mask or a masking color. If the mask is not the same size as the image specified by the image parameter, then Quartz scales the mask to fit the image.

Solution 10 - Iphone

Hi guys try this code,

+ (UIImage *)roundedRectImageFromImage:(UIImage *)image withRadious:(CGFloat)radious {

if(radious == 0.0f)
    return image;
	
if( image != nil) {
    
    CGFloat imageWidth = image.size.width;
    CGFloat imageHeight = image.size.height;

    CGRect rect = CGRectMake(0.0f, 0.0f, imageWidth, imageHeight);
    UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
    const CGFloat scale = window.screen.scale;
    UIGraphicsBeginImageContextWithOptions(rect.size, NO, scale);
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    CGContextBeginPath(context);
    CGContextSaveGState(context);
    CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect));
    CGContextScaleCTM (context, radious, radious);

    CGFloat rectWidth = CGRectGetWidth (rect)/radious;
    CGFloat rectHeight = CGRectGetHeight (rect)/radious;

    CGContextMoveToPoint(context, rectWidth, rectHeight/2.0f);
    CGContextAddArcToPoint(context, rectWidth, rectHeight, rectWidth/2.0f, rectHeight, radious);
    CGContextAddArcToPoint(context, 0.0f, rectHeight, 0.0f, rectHeight/2.0f, radious);
    CGContextAddArcToPoint(context, 0.0f, 0.0f, rectWidth/2.0f, 0.0f, radious);
    CGContextAddArcToPoint(context, rectWidth, 0.0f, rectWidth, rectHeight/2.0f, radious);
    CGContextRestoreGState(context);
	CGContextClosePath(context);
	CGContextClip(context);

    [image drawInRect:CGRectMake(0.0f, 0.0f, imageWidth, imageHeight)];
    
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return newImage;
}

return nil;
}

Cheers !!!

Solution 11 - Iphone

It's very easy to create a rounded image when you make use of the image dimension.

cell.messageImage.layer.cornerRadius = image.size.width / 2
cell.messageImage.layer.masksToBounds = true

Solution 12 - Iphone

Found out the best and simple way of doing it is as follows (no answer did that):

UIImageView *imageView;

imageView.layer.cornerRadius = imageView.frame.size.width/2.0f;
imageView.layer.masksToBounds = TRUE;

Pretty simple and done this right.

Solution 13 - Iphone

I liked the answer of @samwize, however it caused me nasty memory leaks when used with collectionView. To fix it I found that UIGraphicsEndImageContext() was missing

extension UIImage {
    /**
     Rounds corners of UIImage
     - Parameter proportion: Proportion to minimum paramter (width or height)
                             in order to have the same look of corner radius independetly
                             from aspect ratio and actual size
     */
    func roundCorners(proportion: CGFloat) -> UIImage {
        let minValue = min(self.size.width, self.size.height)
        let radius = minValue/proportion
        
        let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: self.size)
        UIGraphicsBeginImageContextWithOptions(self.size, false, 1)
        UIBezierPath(roundedRect: rect, cornerRadius: radius).addClip()
        self.draw(in: rect)
        let image = UIGraphicsGetImageFromCurrentImageContext() ?? self
        UIGraphicsEndImageContext()
        return image
    }
}

Feel free to just pass the radius instead of proportion. proportion is used because I have collectionView scroll and images have different sizes, therefore when using constant radius it actually looks different in terms of proprtions (example: two images, one is 1000x1000 and another 2000x2000, corner radius of 30 will look different on each one of them)

So if you do image.roundCorners(proportion: 20) all the pictures look like the have the same corner radius.

This answer is also an updated version.

Solution 14 - Iphone

[See here...][1] [1]: https://stackoverflow.com/questions/205431/rounded-corners-on-uiimage#205643

IMO unless you absolutely need to do it in code, just overlay an image on top.

Something along the lines of...

- (void)drawRect:(CGRect)rect 
{
    // Drawing code
	[backgroundImage drawInRect:rect];
	[buttonOverlay drawInRect:rect];	
}

Solution 15 - Iphone

For Creating a Round Corner image we can use quartzcore.

First How to add QuartzCore framework?

Click  project -Targets
    ->project
       ->BuildPhase
           ->Link Binary with Libraries
             ->Then click + symbol finally select from list and add it

or else

Click  project -Targets
    ->Targets
      ->general
        ->Linked Frameworks and Libraries
          ->Then click + symbol finally select from list and add the QuartzCore framework

Now import

#import <QuartzCore/QuartzCore.h> 

in your ViewController

Then in viewDidLoad method

self.yourImageView.layer.cornerRadius = 5.0;
self.yourImageView.layer.borderWidth = 1.0f;
self.yourImageView.layer.borderColor = [UIColor blackColor].CGColor;
self.yourImageView.layer.masksToBounds = YES;

Solution 16 - Iphone

I was struggling to round the corners of a UIImage box in my storyboard. I had a IBOutlet for my UIImage called image. After reading a bunch of posts on here, I simply added 3 lines and that worked perfectly.

import UIKit

Then in viewDidLoad:

image.layer.cornerRadius = 20.0

image.layer.masksToBounds = true

This is for iOS 11.1 in Xcode 9.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncatlanView Question on Stackoverflow
Solution 1 - IphonejessecurryView Answer on Stackoverflow
Solution 2 - IphoneepatelView Answer on Stackoverflow
Solution 3 - IphoneBesiView Answer on Stackoverflow
Solution 4 - IphonecatlanView Answer on Stackoverflow
Solution 5 - IphonesamwizeView Answer on Stackoverflow
Solution 6 - IphonewisequarkView Answer on Stackoverflow
Solution 7 - IphoneVoda IonView Answer on Stackoverflow
Solution 8 - Iphonescrat84View Answer on Stackoverflow
Solution 9 - IphonesangView Answer on Stackoverflow
Solution 10 - IphoneAugustine P AView Answer on Stackoverflow
Solution 11 - IphonebartosssView Answer on Stackoverflow
Solution 12 - IphoneIdanView Answer on Stackoverflow
Solution 13 - Iphonemaks_bView Answer on Stackoverflow
Solution 14 - IphoneLoungesView Answer on Stackoverflow
Solution 15 - Iphoneuser3182143View Answer on Stackoverflow
Solution 16 - IphoneDonsbView Answer on Stackoverflow