9

I was wondering if anyone knows how to take an Image using CoreGraphics and add a gloss effect like you see on iOS. Specifically I want to take an image that gets downloaded from the web and style it like this. I've searched high and low and all I found was examples of how to do it in PhotoShop and not in code. Any code snippets or pointers to resources that can help I would appreciate.

laveur
  • 191
  • 1
  • 6
  • Maybe make an image of the glossy part, place it over the other image with alpha ~0.3? – Bemmu Apr 04 '11 at 16:40
  • Bemmu: Sure I could do that, but it wouldn't be as efficient and would cause me great headache trying to get it to line up right. Also it wouldn't look as natural as the glossy image I placed over it wouldn't pick up any of the colors underneath. – laveur Apr 04 '11 at 16:56

2 Answers2

10

I figured it out on my own after wasting a few hours trying to figure this out... Here's my code:

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

static void addGlossPath(CGContextRef context, CGRect rect) {
    CGFloat quarterHeight = CGRectGetMidY(rect) / 2;
    CGContextSaveGState(context);
    CGContextBeginPath(context);
    CGContextMoveToPoint(context, -20, 0);

    CGContextAddLineToPoint(context, -20, quarterHeight);
    CGContextAddQuadCurveToPoint(context, CGRectGetMidX(rect), quarterHeight * 3, CGRectGetMaxX(rect) + 20, quarterHeight);
    CGContextAddLineToPoint(context, CGRectGetMaxX(rect) + 20, 0);

    CGContextClosePath(context);
    CGContextRestoreGState(context);
}

UIImage *applyIconHighlightToImage(UIImage *icon) {
    UIImage *newImage;
    CGContextRef context;
    CGGradientRef glossGradient;
    CGColorSpaceRef rgbColorspace;
    CGRect currentBounds = CGRectMake(0, 0, icon.size.width, icon.size.height);
    CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
    CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));

    CGFloat locations[2] = {0.0, 1.0};
    CGFloat components[8] = {1.0, 1.0, 1.0, 0.75, 1.0, 1.0, 1.0, 0.2};

    UIGraphicsBeginImageContext(icon.size);
    context = UIGraphicsGetCurrentContext();
    UIGraphicsPushContext(context);

    addRoundedRectToPath(context, currentBounds, 10, 10);
    CGContextClosePath(context);
    CGContextClip(context);
    [icon drawInRect:currentBounds];

    addGlossPath(context, currentBounds);
    CGContextClip(context);

    rgbColorspace = CGColorSpaceCreateDeviceRGB();
    glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, 2);

    CGContextDrawLinearGradient(context, glossGradient, topCenter, midCenter, 0);

    UIGraphicsPopContext();

    newImage = UIGraphicsGetImageFromCurrentImageContext();
    CGGradientRelease(glossGradient);
    CGColorSpaceRelease(rgbColorspace);
    UIGraphicsEndImageContext();

    return newImage;
}

Edit: Wanted to make sure I gave credit where credit is due. Thanks to Brad Larson for the code on adding a glossy gradient.

laveur
  • 191
  • 1
  • 6
2

I provide code to draw a glossy gradient using Core Graphics in my answer here.

If all that you wish to do is overlay a gloss effect on your image, it may be more performant to generate this using a CAGradientLayer, as decribed by Mirko in his answer there.

Community
  • 1
  • 1
Brad Larson
  • 170,088
  • 45
  • 397
  • 571