forked from mbcharbonneau/UIImage-Categories
-
Notifications
You must be signed in to change notification settings - Fork 0
/
UIImage+Alpha.m
144 lines (110 loc) · 6.12 KB
/
UIImage+Alpha.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// 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"
@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;
}
- (UIImage *)imageByApplyingAlpha:(CGFloat)alpha {
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect area = CGRectMake(0, 0, self.size.width, self.size.height);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -area.size.height);
CGContextSetBlendMode(ctx, kCGBlendModeMultiply);
CGContextSetAlpha(ctx, alpha);
CGContextDrawImage(ctx, area, self.CGImage);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
#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