Fix the leak of CIImage based UIImage for `sd_colorAtPoint`

This commit is contained in:
DreamPiggy 2020-01-04 13:46:25 +08:00
parent fafed705d0
commit 375e94f31c
1 changed files with 19 additions and 6 deletions

View File

@ -165,8 +165,8 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma
} }
#if SD_UIKIT || SD_MAC #if SD_UIKIT || SD_MAC
// Core Image Support // Create-Rule, caller should call CGImageRelease
static inline CGImageRef _Nullable SDCGImageFromCIImage(CIImage * _Nonnull ciImage) { static inline CGImageRef _Nullable SDCreateCGImageFromCIImage(CIImage * _Nonnull ciImage) {
CGImageRef imageRef = NULL; CGImageRef imageRef = NULL;
if (@available(iOS 10, macOS 10.12, tvOS 10, *)) { if (@available(iOS 10, macOS 10.12, tvOS 10, *)) {
imageRef = ciImage.CGImage; imageRef = ciImage.CGImage;
@ -174,6 +174,8 @@ static inline CGImageRef _Nullable SDCGImageFromCIImage(CIImage * _Nonnull ciIma
if (!imageRef) { if (!imageRef) {
CIContext *context = [CIContext context]; CIContext *context = [CIContext context];
imageRef = [context createCGImage:ciImage fromRect:ciImage.extent]; imageRef = [context createCGImage:ciImage fromRect:ciImage.extent];
} else {
CGImageRetain(imageRef);
} }
return imageRef; return imageRef;
} }
@ -432,11 +434,12 @@ static inline CGImageRef _Nullable SDCGImageFromCIImage(CIImage * _Nonnull ciIma
// CIImage compatible // CIImage compatible
#if SD_UIKIT || SD_MAC #if SD_UIKIT || SD_MAC
if (self.CIImage) { if (self.CIImage) {
imageRef = SDCGImageFromCIImage(self.CIImage); imageRef = SDCreateCGImageFromCIImage(self.CIImage);
} }
#endif #endif
if (!imageRef) { if (!imageRef) {
imageRef = self.CGImage; imageRef = self.CGImage;
CGImageRetain(imageRef);
} }
if (!imageRef) { if (!imageRef) {
return nil; return nil;
@ -446,34 +449,38 @@ static inline CGImageRef _Nullable SDCGImageFromCIImage(CIImage * _Nonnull ciIma
CGFloat width = CGImageGetWidth(imageRef); CGFloat width = CGImageGetWidth(imageRef);
CGFloat height = CGImageGetHeight(imageRef); CGFloat height = CGImageGetHeight(imageRef);
if (point.x < 0 || point.y < 0 || point.x >= width || point.y >= height) { if (point.x < 0 || point.y < 0 || point.x >= width || point.y >= height) {
CGImageRelease(imageRef);
return nil; return nil;
} }
// Get pixels // Get pixels
CGDataProviderRef provider = CGImageGetDataProvider(imageRef); CGDataProviderRef provider = CGImageGetDataProvider(imageRef);
if (!provider) { if (!provider) {
CGImageRelease(imageRef);
return nil; return nil;
} }
CFDataRef data = CGDataProviderCopyData(provider); CFDataRef data = CGDataProviderCopyData(provider);
if (!data) { if (!data) {
CGImageRelease(imageRef);
return nil; return nil;
} }
// Get pixel at point // Get pixel at point
size_t bytesPerRow = CGImageGetBytesPerRow(imageRef); size_t bytesPerRow = CGImageGetBytesPerRow(imageRef);
size_t components = CGImageGetBitsPerPixel(imageRef) / CGImageGetBitsPerComponent(imageRef); size_t components = CGImageGetBitsPerPixel(imageRef) / CGImageGetBitsPerComponent(imageRef);
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
CFRange range = CFRangeMake(bytesPerRow * point.y + components * point.x, 4); CFRange range = CFRangeMake(bytesPerRow * point.y + components * point.x, 4);
if (CFDataGetLength(data) < range.location + range.length) { if (CFDataGetLength(data) < range.location + range.length) {
CFRelease(data); CFRelease(data);
CGImageRelease(imageRef);
return nil; return nil;
} }
Pixel_8888 pixel = {0}; Pixel_8888 pixel = {0};
CFDataGetBytes(data, range, pixel); CFDataGetBytes(data, range, pixel);
CFRelease(data); CFRelease(data);
CGImageRelease(imageRef);
// Convert to color // Convert to color
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
return SDGetColorFromPixel(pixel, bitmapInfo); return SDGetColorFromPixel(pixel, bitmapInfo);
} }
@ -482,11 +489,12 @@ static inline CGImageRef _Nullable SDCGImageFromCIImage(CIImage * _Nonnull ciIma
// CIImage compatible // CIImage compatible
#if SD_UIKIT || SD_MAC #if SD_UIKIT || SD_MAC
if (self.CIImage) { if (self.CIImage) {
imageRef = SDCGImageFromCIImage(self.CIImage); imageRef = SDCreateCGImageFromCIImage(self.CIImage);
} }
#endif #endif
if (!imageRef) { if (!imageRef) {
imageRef = self.CGImage; imageRef = self.CGImage;
CGImageRetain(imageRef);
} }
if (!imageRef) { if (!imageRef) {
return nil; return nil;
@ -496,16 +504,19 @@ static inline CGImageRef _Nullable SDCGImageFromCIImage(CIImage * _Nonnull ciIma
CGFloat width = CGImageGetWidth(imageRef); CGFloat width = CGImageGetWidth(imageRef);
CGFloat height = CGImageGetHeight(imageRef); CGFloat height = CGImageGetHeight(imageRef);
if (CGRectGetWidth(rect) <= 0 || CGRectGetHeight(rect) <= 0 || CGRectGetMinX(rect) < 0 || CGRectGetMinY(rect) < 0 || CGRectGetMaxX(rect) > width || CGRectGetMaxY(rect) > height) { if (CGRectGetWidth(rect) <= 0 || CGRectGetHeight(rect) <= 0 || CGRectGetMinX(rect) < 0 || CGRectGetMinY(rect) < 0 || CGRectGetMaxX(rect) > width || CGRectGetMaxY(rect) > height) {
CGImageRelease(imageRef);
return nil; return nil;
} }
// Get pixels // Get pixels
CGDataProviderRef provider = CGImageGetDataProvider(imageRef); CGDataProviderRef provider = CGImageGetDataProvider(imageRef);
if (!provider) { if (!provider) {
CGImageRelease(imageRef);
return nil; return nil;
} }
CFDataRef data = CGDataProviderCopyData(provider); CFDataRef data = CGDataProviderCopyData(provider);
if (!data) { if (!data) {
CGImageRelease(imageRef);
return nil; return nil;
} }
@ -517,6 +528,7 @@ static inline CGImageRef _Nullable SDCGImageFromCIImage(CIImage * _Nonnull ciIma
size_t end = bytesPerRow * (CGRectGetMaxY(rect) - 1) + components * CGRectGetMaxX(rect); size_t end = bytesPerRow * (CGRectGetMaxY(rect) - 1) + components * CGRectGetMaxX(rect);
if (CFDataGetLength(data) < (CFIndex)end) { if (CFDataGetLength(data) < (CFIndex)end) {
CFRelease(data); CFRelease(data);
CGImageRelease(imageRef);
return nil; return nil;
} }
@ -540,6 +552,7 @@ static inline CGImageRef _Nullable SDCGImageFromCIImage(CIImage * _Nonnull ciIma
[colors addObject:color]; [colors addObject:color];
} }
CFRelease(data); CFRelease(data);
CGImageRelease(imageRef);
return [colors copy]; return [colors copy];
} }