Skip to content

Commit 3ec8edc

Browse files
committed
UIImage (QMUI): 1、增加方法 - (BOOL)qmui_opaque 用于判断当前图片是否存在透明通道;2、修复 qmui_averageColor 对半透明图片计算错误的 bug;3、修复 qmui_grayImage 对半透明图片做置灰操作时没考虑半透明的 bug;4、修复若干处理图片的方法处理前后图片的 alpha 通道不一致的问题
1 parent 8f94a96 commit 3ec8edc

2 files changed

Lines changed: 58 additions & 51 deletions

File tree

QMUIKit/UIKitExtensions/UIImage+QMUI.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ typedef NS_OPTIONS(NSInteger, QMUIImageBorderPosition) {
6060
*/
6161
- (UIImage *)qmui_imageWithAlpha:(CGFloat)alpha;
6262

63+
/**
64+
* 判断一张图是否不存在 alpha 通道,注意 “不存在 alpha 通道” 不等价于 “不透明”。一张不透明的图有可能是存在 alpha 通道但 alpha 值为 1。
65+
*/
66+
- (BOOL)qmui_opaque;
67+
6368
/**
6469
* 保持当前图片的形状不变,使用指定的颜色去重新渲染它,生成一张新图片并返回
6570
*

QMUIKit/UIKitExtensions/UIImage+QMUI.m

Lines changed: 53 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#import "QMUIConfiguration.h"
1212
#import "QMUIHelper.h"
1313
#import "UIBezierPath+QMUI.h"
14+
#import "UIColor+QMUI.h"
1415
#import <Accelerate/Accelerate.h>
1516

1617
CG_INLINE CGSize
@@ -57,44 +58,41 @@ - (UIImage *)qmui_grayImage {
5758
NSInteger width = self.size.width * self.scale;
5859
NSInteger height = self.size.height * self.scale;
5960
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
60-
CGContextRef context = CGBitmapContextCreate(nil, width, height, 8, 0, colorSpace, kCGBitmapByteOrderDefault);
61+
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, colorSpace, kCGBitmapByteOrderDefault);
6162
CGContextInspectContext(context);
6263
CGColorSpaceRelease(colorSpace);
6364
if (context == NULL) {
6465
return nil;
6566
}
66-
67-
CGContextDrawImage(context,CGRectMake(0, 0, width, height), self.CGImage);
68-
CGImageRef grayImageRef = CGBitmapContextCreateImage(context);
69-
CGContextRelease(context);
70-
71-
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(self.CGImage);
72-
BOOL opaque = (alphaInfo == kCGImageAlphaNoneSkipLast) ||
73-
(alphaInfo == kCGImageAlphaNoneSkipFirst) ||
74-
(alphaInfo == kCGImageAlphaNone);
75-
76-
if (opaque) {
77-
UIImage *qmui_grayImage = [UIImage imageWithCGImage:grayImageRef scale:self.scale orientation:self.imageOrientation];
78-
CGImageRelease(grayImageRef);
79-
return qmui_grayImage;
80-
}
81-
82-
context = CGBitmapContextCreate(NULL, width, height, 8, 0, NULL, kCGImageAlphaOnly);
83-
CGContextDrawImage(context, CGRectMake(0, 0, width, height), self.CGImage);
84-
CGImageRef maskImageRef = CGBitmapContextCreateImage(context);
85-
CGImageRef maskedGrayImageRef = CGImageCreateWithMask(grayImageRef, maskImageRef);
86-
87-
CGContextRelease(context);
88-
CGImageRelease(grayImageRef);
89-
CGImageRelease(maskImageRef);
90-
91-
UIImage *maskedGrayImage = [UIImage imageWithCGImage:maskedGrayImageRef scale:self.scale orientation:self.imageOrientation];
92-
CGImageRelease(maskedGrayImageRef);
93-
return maskedGrayImage;
67+
CGRect imageRect = CGRectMake(0, 0, width, height);
68+
CGContextDrawImage(context, imageRect, self.CGImage);
69+
70+
UIImage *grayImage = nil;
71+
CGImageRef imageRef = CGBitmapContextCreateImage(context);
72+
if (self.qmui_opaque) {
73+
grayImage = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
74+
} else {
75+
CGContextRef alphaContext = CGBitmapContextCreate(NULL, width, height, 8, 0, nil, kCGImageAlphaOnly);
76+
CGContextDrawImage(alphaContext, imageRect, self.CGImage);
77+
CGImageRef mask = CGBitmapContextCreateImage(alphaContext);
78+
grayImage = [UIImage imageWithCGImage:CGImageCreateWithMask(imageRef, mask) scale:self.scale orientation:self.imageOrientation];
79+
CGImageRelease(mask);
80+
CGContextRelease(alphaContext);
81+
82+
// 用 CGBitmapContextCreateImage 方式创建出来的图片,CGImageAlphaInfo 总是为 CGImageAlphaInfoNone,导致 qmui_opaque 与原图不一致,所以这里再做多一步
83+
UIGraphicsBeginImageContextWithOptions(grayImage.size, NO, grayImage.scale);
84+
[grayImage drawInRect:imageRect];
85+
grayImage = UIGraphicsGetImageFromCurrentImageContext();
86+
UIGraphicsEndImageContext();
87+
}
88+
89+
CGContextRelease(context);
90+
CGImageRelease(imageRef);
91+
return grayImage;
9492
}
9593

9694
- (UIImage *)qmui_imageWithAlpha:(CGFloat)alpha {
97-
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
95+
UIGraphicsBeginImageContextWithOptions(self.size, self.qmui_opaque, self.scale);
9896
CGContextRef context = UIGraphicsGetCurrentContext();
9997
CGContextInspectContext(context);
10098
CGRect drawingRect = CGRectMake(0, 0, self.size.width, self.size.height);
@@ -104,10 +102,18 @@ - (UIImage *)qmui_imageWithAlpha:(CGFloat)alpha {
104102
return imageOut;
105103
}
106104

105+
- (BOOL)qmui_opaque {
106+
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(self.CGImage);
107+
BOOL opaque = alphaInfo == kCGImageAlphaNoneSkipLast
108+
|| alphaInfo == kCGImageAlphaNoneSkipFirst
109+
|| alphaInfo == kCGImageAlphaNone;
110+
return opaque;
111+
}
112+
107113
- (UIImage *)qmui_imageWithTintColor:(UIColor *)tintColor {
108114
UIImage *imageIn = self;
109115
CGRect rect = CGRectMake(0, 0, imageIn.size.width, imageIn.size.height);
110-
UIGraphicsBeginImageContextWithOptions(imageIn.size, NO, imageIn.scale);
116+
UIGraphicsBeginImageContextWithOptions(imageIn.size, self.qmui_opaque, imageIn.scale);
111117
CGContextRef context = UIGraphicsGetCurrentContext();
112118
CGContextInspectContext(context);
113119
CGContextTranslateCTM(context, 0, imageIn.size.height);
@@ -124,7 +130,7 @@ - (UIImage *)qmui_imageWithTintColor:(UIColor *)tintColor {
124130
- (UIImage *)qmui_imageWithImageAbove:(UIImage *)image atPoint:(CGPoint)point {
125131
UIImage *imageIn = self;
126132
UIImage *imageOut = nil;
127-
UIGraphicsBeginImageContextWithOptions(imageIn.size, NO, imageIn.scale);
133+
UIGraphicsBeginImageContextWithOptions(imageIn.size, self.qmui_opaque, imageIn.scale);
128134
[imageIn drawInRect:CGRectMakeWithSize(imageIn.size)];
129135
[image drawAtPoint:point];
130136
imageOut = UIGraphicsGetImageFromCurrentImageContext();
@@ -134,7 +140,7 @@ - (UIImage *)qmui_imageWithImageAbove:(UIImage *)image atPoint:(CGPoint)point {
134140

135141
- (UIImage *)qmui_imageWithSpacingExtensionInsets:(UIEdgeInsets)extension {
136142
CGSize contextSize = CGSizeMake(self.size.width + UIEdgeInsetsGetHorizontalValue(extension), self.size.height + UIEdgeInsetsGetVerticalValue(extension));
137-
UIGraphicsBeginImageContextWithOptions(contextSize, NO, self.scale);
143+
UIGraphicsBeginImageContextWithOptions(contextSize, self.qmui_opaque, self.scale);
138144
[self drawAtPoint:CGPointMake(extension.left, extension.top)];
139145
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
140146
UIGraphicsEndImageContext();
@@ -143,10 +149,15 @@ - (UIImage *)qmui_imageWithSpacingExtensionInsets:(UIEdgeInsets)extension {
143149

144150
- (UIImage *)qmui_imageWithClippedRect:(CGRect)rect {
145151
CGContextInspectSize(rect.size);
152+
CGRect imageRect = CGRectMakeWithSize(self.size);
153+
if (CGRectContainsRect(rect, imageRect)) {
154+
// 要裁剪的区域比自身大,所以不用裁剪直接返回自身即可
155+
return self;
156+
}
146157
// 由于CGImage是以pixel为单位来计算的,而UIImage是以point为单位,所以这里需要将传进来的point转换为pixel
147158
CGRect scaledRect = CGRectApplyScale(rect, self.scale);
148159
CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, scaledRect);
149-
UIImage *imageOut = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:UIImageOrientationUp];
160+
UIImage *imageOut = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
150161
CGImageRelease(imageRef);
151162
return imageOut;
152163
}
@@ -158,9 +169,12 @@ - (UIImage *)qmui_imageWithScaleToSize:(CGSize)size contentMode:(UIViewContentMo
158169
- (UIImage *)qmui_imageWithScaleToSize:(CGSize)size contentMode:(UIViewContentMode)contentMode scale:(CGFloat)scale {
159170
size = CGSizeFlatSpecificScale(size, scale);
160171
CGContextInspectSize(size);
172+
UIGraphicsBeginImageContextWithOptions(size, self.qmui_opaque, scale);
173+
CGContextRef context = UIGraphicsGetCurrentContext();
174+
CGContextInspectContext(context);
161175
CGSize imageSize = self.size;
162176
CGRect drawingRect = CGRectZero;
163-
177+
164178
if (contentMode == UIViewContentModeScaleToFill) {
165179
drawingRect = CGRectMakeWithSize(size);
166180
} else {
@@ -177,16 +191,7 @@ - (UIImage *)qmui_imageWithScaleToSize:(CGSize)size contentMode:(UIViewContentMo
177191
drawingRect.size.height = flatfSpecificScale(imageSize.height * ratio, scale);
178192
drawingRect = CGRectSetXY(drawingRect, flatfSpecificScale((size.width - CGRectGetWidth(drawingRect)) / 2.0, scale), flatfSpecificScale((size.height - CGRectGetHeight(drawingRect)) / 2, scale));
179193
}
180-
181-
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(self.CGImage);
182-
BOOL opaque = (alphaInfo == kCGImageAlphaNoneSkipLast) ||
183-
(alphaInfo == kCGImageAlphaNoneSkipFirst) ||
184-
(alphaInfo == kCGImageAlphaNone);
185-
opaque = (opaque && CGRectContainsRect(drawingRect, CGRectMakeWithSize(size)));
186-
187-
UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
188-
CGContextRef context = UIGraphicsGetCurrentContext();
189-
CGContextInspectContext(context);
194+
190195
[self drawInRect:drawingRect];
191196
UIImage *imageOut = UIGraphicsGetImageFromCurrentImageContext();
192197
UIGraphicsEndImageContext();
@@ -259,7 +264,7 @@ - (UIImage *)qmui_imageWithBorderColor:(UIColor *)borderColor path:(UIBezierPath
259264
UIImage *oldImage = self;
260265
UIImage *resultImage;
261266
CGRect rect = CGRectMake(0, 0, oldImage.size.width, oldImage.size.height);
262-
UIGraphicsBeginImageContextWithOptions(oldImage.size, NO, oldImage.scale);
267+
UIGraphicsBeginImageContextWithOptions(oldImage.size, self.qmui_opaque, oldImage.scale);
263268
CGContextRef context = UIGraphicsGetCurrentContext();
264269
CGContextInspectContext(context);
265270
[oldImage drawInRect:rect];
@@ -323,10 +328,6 @@ - (UIImage *)qmui_imageWithBorderColor:(UIColor *)borderColor borderWidth:(CGFlo
323328
return self;
324329
}
325330

326-
void dataProviderReleaseCallback (void *info, const void *data, size_t size) {
327-
free((void *)data);
328-
}
329-
330331
- (UIImage *)qmui_imageWithMaskImage:(UIImage *)maskImage usingMaskImageMode:(BOOL)usingMaskImageMode {
331332
CGImageRef maskRef = [maskImage CGImage];
332333
CGImageRef mask;
@@ -423,7 +424,8 @@ + (UIImage *)qmui_imageWithColor:(UIColor *)color size:(CGSize)size cornerRadius
423424
UIImage *resultImage = nil;
424425
color = color ? color : UIColorClear;
425426

426-
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
427+
BOOL opaque = [color qmui_alpha] == 1.0;// 颜色本身不带透明,就不用创建带透明通道的 image 了
428+
UIGraphicsBeginImageContextWithOptions(size, opaque, 0);
427429
CGContextRef context = UIGraphicsGetCurrentContext();
428430
CGContextSetFillColorWithColor(context, color.CGColor);
429431

0 commit comments

Comments
 (0)