// UIImage+Alpha.m // Created by Trevor Harmon on 9/20/09. // Free for personal or commercial use, with or without modification. // No warranty is expressed or implied. #import "UIImage+Alpha.h" // Private helper methods @interface UIImage (PrivateAlpha) - (CGImageRef)newBorderMask:(NSUInteger)borderSize size:(CGSize)size; @end @implementation UIImage (Alpha) // Returns true if the image has an alpha layer - (BOOL)hasAlpha { CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage); return (alpha == kCGImageAlphaFirst || alpha == kCGImageAlphaLast || alpha == kCGImageAlphaPremultipliedFirst || alpha == kCGImageAlphaPremultipliedLast); } // Returns a copy of the given image, adding an alpha channel if it doesn't already have one - (UIImage *)imageWithAlpha { if ([self hasAlpha]) { return self; } CGImageRef imageRef = self.CGImage; size_t width = CGImageGetWidth(imageRef); size_t height = CGImageGetHeight(imageRef); // The bitsPerComponent and bitmapInfo values are hard-coded to prevent an "unsupported parameter combination" error CGContextRef offscreenContext = CGBitmapContextCreate(NULL, width, height, 8, 0, CGImageGetColorSpace(imageRef), kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); // Draw the image into the context and retrieve the new image, which will now have an alpha layer CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), imageRef); CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(offscreenContext); UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha]; // Clean up CGContextRelease(offscreenContext); CGImageRelease(imageRefWithAlpha); return imageWithAlpha; } // Returns a copy of the image with a transparent border of the given size added around its edges. // If the image has no alpha layer, one will be added to it. - (UIImage *)transparentBorderImage:(NSUInteger)borderSize { // If the image does not have an alpha layer, add one UIImage *image = [self imageWithAlpha]; CGRect newRect = CGRectMake(0, 0, image.size.width + borderSize * 2, image.size.height + borderSize * 2); // Build a context that's the same dimensions as the new size CGContextRef bitmap = CGBitmapContextCreate(NULL, newRect.size.width, newRect.size.height, CGImageGetBitsPerComponent(self.CGImage), 0, CGImageGetColorSpace(self.CGImage), CGImageGetBitmapInfo(self.CGImage)); // Draw the image in the center of the context, leaving a gap around the edges CGRect imageLocation = CGRectMake(borderSize, borderSize, image.size.width, image.size.height); CGContextDrawImage(bitmap, imageLocation, self.CGImage); CGImageRef borderImageRef = CGBitmapContextCreateImage(bitmap); // Create a mask to make the border transparent, and combine it with the image CGImageRef maskImageRef = [self newBorderMask:borderSize size:newRect.size]; CGImageRef transparentBorderImageRef = CGImageCreateWithMask(borderImageRef, maskImageRef); UIImage *transparentBorderImage = [UIImage imageWithCGImage:transparentBorderImageRef]; // Clean up CGContextRelease(bitmap); CGImageRelease(borderImageRef); CGImageRelease(maskImageRef); CGImageRelease(transparentBorderImageRef); return transparentBorderImage; } #pragma mark - #pragma mark Private helper methods // Creates a mask that makes the outer edges transparent and everything else opaque // The size must include the entire mask (opaque part + transparent border) // The caller is responsible for releasing the returned reference by calling CGImageRelease - (CGImageRef)newBorderMask:(NSUInteger)borderSize size:(CGSize)size { CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); // Build a context that's the same dimensions as the new size CGContextRef maskContext = CGBitmapContextCreate(NULL, size.width, size.height, 8, // 8-bit grayscale 0, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaNone); // Start with a mask that's entirely transparent CGContextSetFillColorWithColor(maskContext, [UIColor blackColor].CGColor); CGContextFillRect(maskContext, CGRectMake(0, 0, size.width, size.height)); // Make the inner part (within the border) opaque CGContextSetFillColorWithColor(maskContext, [UIColor whiteColor].CGColor); CGContextFillRect(maskContext, CGRectMake(borderSize, borderSize, size.width - borderSize * 2, size.height - borderSize * 2)); // Get an image of the context CGImageRef maskImageRef = CGBitmapContextCreateImage(maskContext); // Clean up CGContextRelease(maskContext); CGColorSpaceRelease(colorSpace); return maskImageRef; } @end