From 1b0fdd8cb65fd71e86a773a541dcee546625bff4 Mon Sep 17 00:00:00 2001 From: lizhuoli Date: Thu, 3 Mar 2022 20:49:57 +0800 Subject: [PATCH] Fix the iOS 15+ draw image blank because that CoreGraphics may not transcode on BGRX8888 pixel format context --- SDWebImage/Core/SDImageCoderHelper.m | 53 ++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/SDWebImage/Core/SDImageCoderHelper.m b/SDWebImage/Core/SDImageCoderHelper.m index 95a95000..030cf8c1 100644 --- a/SDWebImage/Core/SDImageCoderHelper.m +++ b/SDWebImage/Core/SDImageCoderHelper.m @@ -255,9 +255,19 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over // iOS prefer BGRA8888 (premultiplied) or BGRX8888 bitmapInfo for screen rendering, which is same as `UIGraphicsBeginImageContext()` or `- [CALayer drawInContext:]` // Though you can use any supported bitmapInfo (see: https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB ) and let Core Graphics reorder it when you call `CGContextDrawImage` // But since our build-in coders use this bitmapInfo, this can have a little performance benefit - CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; - bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; - CGContextRef context = CGBitmapContextCreate(NULL, newWidth, newHeight, 8, 0, [self colorSpaceGetDeviceRGB], bitmapInfo); + CGBitmapInfo bitmapInfo; + CGContextRef context = NULL; + if (@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)) { + // Update for iOS 15: CoreGraphics's draw image will fail to transcode and draw some special CGImage on BGRX8888 + // We prefer to use the input CGImaage's bitmap firstly, then fallback to BGRA. See #3330 + bitmapInfo = CGImageGetBitmapInfo(cgImage); + context = CGBitmapContextCreate(NULL, newWidth, newHeight, 8, 0, [self colorSpaceGetDeviceRGB], bitmapInfo); + } + if (!context) { + bitmapInfo = kCGBitmapByteOrder32Host; + bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; + context = CGBitmapContextCreate(NULL, newWidth, newHeight, 8, 0, [self colorSpaceGetDeviceRGB], bitmapInfo); + } if (!context) { return NULL; } @@ -358,7 +368,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over } destTotalPixels = bytes / kBytesPerPixel; tileTotalPixels = destTotalPixels / 3; - CGContextRef destContext; + CGContextRef destContext = NULL; // autorelease the bitmap context and all vars to help system to free memory when there are memory warning. // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory]; @@ -380,20 +390,35 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over // device color space CGColorSpaceRef colorspaceRef = [self colorSpaceGetDeviceRGB]; BOOL hasAlpha = [self CGImageContainsAlpha:sourceImageRef]; - // iOS display alpha info (BGRA8888/BGRX8888) - CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; - bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; // kCGImageAlphaNone is not supported in CGBitmapContextCreate. // Since the original image here has no alpha info, use kCGImageAlphaNoneSkipFirst // to create bitmap graphics contexts without alpha info. - destContext = CGBitmapContextCreate(NULL, - destResolution.width, - destResolution.height, - kBitsPerComponent, - 0, - colorspaceRef, - bitmapInfo); + CGBitmapInfo bitmapInfo; + if (@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)) { + // Update for iOS 15: CoreGraphics's draw image will fail to transcode and draw some special CGImage on BGRX8888 + // We prefer to use the input CGImaage's bitmap firstly, then fallback to BGRA. See #3330 + bitmapInfo = CGImageGetBitmapInfo(sourceImageRef); + destContext = CGBitmapContextCreate(NULL, + destResolution.width, + destResolution.height, + kBitsPerComponent, + 0, + colorspaceRef, + bitmapInfo); + } + if (!destContext) { + // iOS display alpha info (BGRA8888/BGRX8888) + bitmapInfo = kCGBitmapByteOrder32Host; + bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; + destContext = CGBitmapContextCreate(NULL, + destResolution.width, + destResolution.height, + kBitsPerComponent, + 0, + colorspaceRef, + bitmapInfo); + } if (destContext == NULL) { return image;