UIImage+Alpha.m 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // UIImage+Alpha.m
  2. // Created by Trevor Harmon on 9/20/09.
  3. // Free for personal or commercial use, with or without modification.
  4. // No warranty is expressed or implied.
  5. #import "UIImage+Alpha.h"
  6. // Private helper methods
  7. @interface UIImage (PrivateAlpha)
  8. - (CGImageRef)newBorderMask:(NSUInteger)borderSize size:(CGSize)size;
  9. @end
  10. @implementation UIImage (Alpha)
  11. // Returns true if the image has an alpha layer
  12. - (BOOL)hasAlpha {
  13. CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage);
  14. return (alpha == kCGImageAlphaFirst ||
  15. alpha == kCGImageAlphaLast ||
  16. alpha == kCGImageAlphaPremultipliedFirst ||
  17. alpha == kCGImageAlphaPremultipliedLast);
  18. }
  19. // Returns a copy of the given image, adding an alpha channel if it doesn't already have one
  20. - (UIImage *)imageWithAlpha {
  21. if ([self hasAlpha]) {
  22. return self;
  23. }
  24. CGImageRef imageRef = self.CGImage;
  25. size_t width = CGImageGetWidth(imageRef);
  26. size_t height = CGImageGetHeight(imageRef);
  27. // The bitsPerComponent and bitmapInfo values are hard-coded to prevent an "unsupported parameter combination" error
  28. CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
  29. width,
  30. height,
  31. 8,
  32. 0,
  33. CGImageGetColorSpace(imageRef),
  34. kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
  35. // Draw the image into the context and retrieve the new image, which will now have an alpha layer
  36. CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), imageRef);
  37. CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(offscreenContext);
  38. UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha];
  39. // Clean up
  40. CGContextRelease(offscreenContext);
  41. CGImageRelease(imageRefWithAlpha);
  42. return imageWithAlpha;
  43. }
  44. // Returns a copy of the image with a transparent border of the given size added around its edges.
  45. // If the image has no alpha layer, one will be added to it.
  46. - (UIImage *)transparentBorderImage:(NSUInteger)borderSize {
  47. // If the image does not have an alpha layer, add one
  48. UIImage *image = [self imageWithAlpha];
  49. CGRect newRect = CGRectMake(0, 0, image.size.width + borderSize * 2, image.size.height + borderSize * 2);
  50. // Build a context that's the same dimensions as the new size
  51. CGContextRef bitmap = CGBitmapContextCreate(NULL,
  52. newRect.size.width,
  53. newRect.size.height,
  54. CGImageGetBitsPerComponent(self.CGImage),
  55. 0,
  56. CGImageGetColorSpace(self.CGImage),
  57. CGImageGetBitmapInfo(self.CGImage));
  58. // Draw the image in the center of the context, leaving a gap around the edges
  59. CGRect imageLocation = CGRectMake(borderSize, borderSize, image.size.width, image.size.height);
  60. CGContextDrawImage(bitmap, imageLocation, self.CGImage);
  61. CGImageRef borderImageRef = CGBitmapContextCreateImage(bitmap);
  62. // Create a mask to make the border transparent, and combine it with the image
  63. CGImageRef maskImageRef = [self newBorderMask:borderSize size:newRect.size];
  64. CGImageRef transparentBorderImageRef = CGImageCreateWithMask(borderImageRef, maskImageRef);
  65. UIImage *transparentBorderImage = [UIImage imageWithCGImage:transparentBorderImageRef];
  66. // Clean up
  67. CGContextRelease(bitmap);
  68. CGImageRelease(borderImageRef);
  69. CGImageRelease(maskImageRef);
  70. CGImageRelease(transparentBorderImageRef);
  71. return transparentBorderImage;
  72. }
  73. #pragma mark -
  74. #pragma mark Private helper methods
  75. // Creates a mask that makes the outer edges transparent and everything else opaque
  76. // The size must include the entire mask (opaque part + transparent border)
  77. // The caller is responsible for releasing the returned reference by calling CGImageRelease
  78. - (CGImageRef)newBorderMask:(NSUInteger)borderSize size:(CGSize)size {
  79. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
  80. // Build a context that's the same dimensions as the new size
  81. CGContextRef maskContext = CGBitmapContextCreate(NULL,
  82. size.width,
  83. size.height,
  84. 8, // 8-bit grayscale
  85. 0,
  86. colorSpace,
  87. kCGBitmapByteOrderDefault | kCGImageAlphaNone);
  88. // Start with a mask that's entirely transparent
  89. CGContextSetFillColorWithColor(maskContext, [UIColor blackColor].CGColor);
  90. CGContextFillRect(maskContext, CGRectMake(0, 0, size.width, size.height));
  91. // Make the inner part (within the border) opaque
  92. CGContextSetFillColorWithColor(maskContext, [UIColor whiteColor].CGColor);
  93. CGContextFillRect(maskContext, CGRectMake(borderSize, borderSize, size.width - borderSize * 2, size.height - borderSize * 2));
  94. // Get an image of the context
  95. CGImageRef maskImageRef = CGBitmapContextCreateImage(maskContext);
  96. // Clean up
  97. CGContextRelease(maskContext);
  98. CGColorSpaceRelease(colorSpace);
  99. return maskImageRef;
  100. }
  101. @end