« Rails with spotsAdvertising to the wrong crowd »

Drawing reflections using Cocoa

Apple recently made a big deal out of putting reflections on images. It looks great and it’s a nice little something-something but now everyone wants it and developers have to deliver. I haven’t seen a complete, end-to-end example in using pure Cocoa to put a reflection on an image so I figured I’d put something together.

NSImage *img = [[NSImage imageNamed:@"NSApplicationIcon"] copy]; // 1
NSSize s = [img size];

NSImage *final = [[NSImage alloc] initWithSize:NSMakeSize(s.width, s.height*2+1)]; // 2
[final lockFocus];
[img dissolveToPoint:NSMakePoint(0, s.height+1) fraction:1.0]; // 3
[[NSBezierPath bezierPathWithRect:NSMakeRect(0, 0, s.width, s.height)] fillGradientWithStartColor:[NSColor redColor] endColor:[NSColor clearColor]]; // 4
NSAffineTransform *t = [NSAffineTransform transform]; // 5
[t scaleXBy:1 yBy:-1];
[t concat];
[img drawAtPoint:NSMakePoint(0, -s.height) fromRect:NSZeroRect operation:NSCompositeSourceIn fraction:1.0]; // 6
[final unlockFocus];

[imageView setImage:final]; // 7
  1. First, get your image. Here, I’m just grabbing the application’s icon. Note that I’m leaking memory in this example because, frankly, I just don’t care. It’s an example. Be sure to exercise good memory management when doing this in a real application.

  2. Now we’re going to put our images together. Since were doing a full reflection, this image needs to be twice the height of the original.

  3. Draw the original image in the top half of the image. The standard seems to have a one pixel span between original and reflection so that’s where that stray 1 comes from.

  4. Get a simple color to clear gradient. Here, I’m using my own custom NSBezierPath category but there are numerous ones out there on the internet. Find something that produces a simple gradient and go with it. This will be the basis of the fade effect of the reflection.

  5. For most original images, you can just call setFlipped: instead of using a transform. This, however, won’t work for generated images. At least it didn’t work when I tried to draw a simple image in code. NSAffineTransform works for whatever I threw at it so I’m sticking with it.

  6. Use a draw function to pick up the affine transform (my favorite, dissolveToPoint: won’t work right here). I’m also using NSCompositeSourceIn because it appears to work right.

  7. Now do something with your new image.

Leave a Reply