views:

231

answers:

2

How can I create a "person photo" button like the one in contact info or in the Facebook app? (grey and rounded border with a small radius and an image that is cropped inside it)

Edit:

It must obviously work for all photos, not just one that I prerender in Photoshop.

I guess I could do it manually using masks etc., but Facebook app does it exactly like the contacts app, so I suspect there is some way to do it in the SDK.

+1  A: 

Create it as an image (like "person.png"), then load it up like this:

UIImage *personImage = [UIImage imageNamed:@"person.png"];
[[myButton imageView] setImage:personImage];
//where myButton is a UIButton of type UIButtonTypeCustom
Dave DeLong
+2  A: 

Here you (I :P) go:

+ (UIImage *)imageWithBorderForImage:(UIImage *)image
{
    CGFloat radius = 5;
    CGSize size = image.size;

    radius = MIN(radius, .5 * MIN(size.width, size.height));
    CGRect interiorRect = CGRectInset(CGRectMake(0, 0, size.width, size.height), radius, radius);

    UIGraphicsBeginImageContext(size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);

    CGMutablePathRef borderPath = CGPathCreateMutable();
    CGPathAddArc(borderPath, NULL, CGRectGetMinX(interiorRect), CGRectGetMinY(interiorRect), radius, 1.0*M_PI, 1.5*M_PI, NO);
    CGPathAddArc(borderPath, NULL, CGRectGetMaxX(interiorRect), CGRectGetMinY(interiorRect), radius, 1.5*M_PI, 0.0*M_PI, NO);
    CGPathAddArc(borderPath, NULL, CGRectGetMaxX(interiorRect), CGRectGetMaxY(interiorRect), radius, 0.0*M_PI, 0.5*M_PI, NO);
    CGPathAddArc(borderPath, NULL, CGRectGetMinX(interiorRect), CGRectGetMaxY(interiorRect), radius, 0.5*M_PI, 1.0*M_PI, NO);

    CGContextBeginPath(context);
    CGContextAddPath(context, borderPath);
    CGContextClosePath(context);
    CGContextClip(context);

    [image drawAtPoint:CGPointMake(0,0)];

    CGContextBeginPath(context);
    CGContextAddPath(context, borderPath);
    CGContextClosePath(context);

    CGContextSetRGBStrokeColor(context, 0.5, 0.5, 0.5, 1.0);
    CGContextSetLineWidth(context, 1.0);
    CGContextStrokePath(context);

    CGPathRelease(borderPath);

    UIImage *borderedImage = UIGraphicsGetImageFromCurrentImageContext();
    CGContextRestoreGState(context);
    UIGraphicsEndImageContext();

    return borderedImage;
}

Based largely on this question.

One problem is that the border is actually 2px wide (although 1px falls outside of the clip area) because of anti-aliasing. Ideally the border would have ~0.5 alpha, but since the antialiasing gives each of the 2 pixels some alpha, I set it to 1 and it comes out just about right. If I disable antialiasing, then the corners aren't rounded all the same :/

Jaka Jančar