Mustafa
Mustafa

Reputation: 20564

UIImage with transparent rounded corners

I'm using following code to add rounded corners to my UIImage, but the problem is that the rounded corners are showing "white" area instead of transparent or "clear". What am i doing wrong here:

- (UIImage *)makeRoundCornerImageWithCornerWidth:(int)cornerWidth cornerHeight:(int)cornerHeight {
    UIImage * newImage = nil;

    if (self != nil)    {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
        int w = self.size.width;
        int h = self.size.height;

        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);

        CGContextBeginPath(context);
        CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
        [self addRoundedRectToPath:context rect:rect width:cornerWidth height:cornerHeight];

        CGContextClosePath(context);
        CGContextClip(context);

        CGContextDrawImage(context, CGRectMake(0, 0, w, h), self.CGImage);
        CGImageRef imageMasked = CGBitmapContextCreateImage(context);
        CGContextRelease(context);
        CGColorSpaceRelease(colorSpace);

        newImage = [[UIImage imageWithCGImage:imageMasked] retain];
        CGImageRelease(imageMasked);

        [pool release];
    }

    return [newImage autorelease];
}


- (void)addRoundedRectToPath:(CGContextRef)context rect:(CGRect)rect width:(float)ovalWidth height:(float)ovalHeight {
    float fw, fh;

    // If the width or height of the corner oval is zero, then it reduces to a right angle,
    // so instead of a rounded rectangle we have an ordinary one.
    if (ovalWidth == 0 || ovalHeight == 0) {
        CGContextAddRect(context, rect);
        return;
    }

    //  Save the context's state so that the translate and scale can be undone with a call
    //  to CGContextRestoreGState.
    CGContextSaveGState(context);

    //  Translate the origin of the contex to the lower left corner of the rectangle.
    CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect));

    //Normalize the scale of the context so that the width and height of the arcs are 1.0
    CGContextScaleCTM (context, ovalWidth, ovalHeight);

    // Calculate the width and height of the rectangle in the new coordinate system.
    fw = CGRectGetWidth (rect) / ovalWidth;
    fh = CGRectGetHeight (rect) / ovalHeight;

    // CGContextAddArcToPoint adds an arc of a circle to the context's path (creating the rounded
    // corners).  It also adds a line from the path's last point to the begining of the arc, making
    // the sides of the rectangle.
    CGContextMoveToPoint(context, fw, fh/2);                // Start at lower right corner
    CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);   // Top right corner
    CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);     // Top left corner
    CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);      // Lower left corner
    CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);    // Back to lower right

    // Close the path
    CGContextClosePath(context);

    // Restore the context's state. This removes the translation and scaling
    // but leaves the path, since the path is not part of the graphics state.
    CGContextRestoreGState(context);
}

Upvotes: 5

Views: 3264

Answers (5)

pkc
pkc

Reputation: 8504

profileImageView.layer.cornerRadius = profileImageView.frame.size.height/2;
profileImageView.clipsToBounds = YES;

Upvotes: 1

ActionFactory
ActionFactory

Reputation: 1403

https://github.com/detroit-labs/AmazeKit

sounds like a job for a library

Upvotes: 4

matt
matt

Reputation: 535139

Here's a simpler formulation using UIKit calls:

- (UIImage*) roundCorneredImage: (UIImage*) orig radius:(CGFloat) r {
    UIGraphicsBeginImageContextWithOptions(orig.size, NO, 0);
    [[UIBezierPath bezierPathWithRoundedRect:(CGRect){CGPointZero, orig.size} 
                                cornerRadius:r] addClip];
    [orig drawInRect:(CGRect){CGPointZero, orig.size}];
    UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return result;
}

Notice the NO parameter - this makes the image context transparent, so the clipped-out region is transparent.

Upvotes: 12

Ned
Ned

Reputation: 6270

lukya's comment below your question is what you probably want to do.

Make sure you import QuartzCore:

#import <QuartzCore/QuartzCore.h>

Then, if you have a UIImageView of your image that you want to have rounded corners, just call (assuming imageView is a property and cornerRadius is the desired corner radius):

self.imageView.layer.cornerRadius = cornerRadius;
self.imageView.clipsToBounds = YES;

Since you already have self.CGImage, you could do this to create a UIImageView:

UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageWithCGImage:self.CGImage]];

Just make sure to release the imageView after you add it as a subview.

Upvotes: 1

Jeff Argast
Jeff Argast

Reputation: 1251

Right after creating the bitmap context clear it with:

CGContextClearRect (context, CGRectMake(0, 0, w, h));

Upvotes: 1

Related Questions