Merge pull request #3332 from dreampiggy/workaround_prefer_input_cgimage_bitmap_info
Workaround the iOS 15+ Force Decode may return black image because of CoreGraphics
This commit is contained in:
commit
ba66c41fd6
|
@ -13,7 +13,7 @@ jobs:
|
|||
name: Cocoapods Lint
|
||||
runs-on: macos-11
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_13.0.app
|
||||
DEVELOPER_DIR: /Applications/Xcode_13.2.1.app
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
@ -39,7 +39,7 @@ jobs:
|
|||
name: Run Demo
|
||||
runs-on: macos-11
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_13.0.app
|
||||
DEVELOPER_DIR: /Applications/Xcode_13.2.1.app
|
||||
WORKSPACE_NAME: SDWebImage.xcworkspace
|
||||
OSXSCHEME: SDWebImage OSX Demo
|
||||
iOSSCHEME: SDWebImage iOS Demo
|
||||
|
@ -92,7 +92,7 @@ jobs:
|
|||
name: Unit Test
|
||||
runs-on: macos-11
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_13.0.app
|
||||
DEVELOPER_DIR: /Applications/Xcode_13.2.1.app
|
||||
WORKSPACE_NAME: SDWebImage.xcworkspace
|
||||
strategy:
|
||||
matrix:
|
||||
|
@ -151,7 +151,7 @@ jobs:
|
|||
name: Build Library
|
||||
runs-on: macos-11
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_13.0.app
|
||||
DEVELOPER_DIR: /Applications/Xcode_13.2.1.app
|
||||
PROJECT_NAME: SDWebImage.xcodeproj
|
||||
SCHEME_NAME: SDWebImage
|
||||
steps:
|
||||
|
|
|
@ -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 CGImage's bitmap firstly, then fallback to BGRAX8888. 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 some special CGImage on BGRX8888
|
||||
// We prefer to use the input CGImage's bitmap firstly, then fallback to BGRAX8888. 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;
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
320224F82440C39B00E5B29D /* TestImageLarge.png in Resources */ = {isa = PBXBuildFile; fileRef = 320224F62440C39B00E5B29D /* TestImageLarge.png */; };
|
||||
320224F92440C39B00E5B29D /* TestImageLarge.png in Resources */ = {isa = PBXBuildFile; fileRef = 320224F62440C39B00E5B29D /* TestImageLarge.png */; };
|
||||
320630412085A37C006E0FA4 /* SDAnimatedImageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A571552037DB2D002EDAAE /* SDAnimatedImageTest.m */; };
|
||||
321F310E27D0DC490042B274 /* TestImage.bmp in Resources */ = {isa = PBXBuildFile; fileRef = 321F310D27D0DC490042B274 /* TestImage.bmp */; };
|
||||
321F310F27D0DC490042B274 /* TestImage.bmp in Resources */ = {isa = PBXBuildFile; fileRef = 321F310D27D0DC490042B274 /* TestImage.bmp */; };
|
||||
321F311027D0DC490042B274 /* TestImage.bmp in Resources */ = {isa = PBXBuildFile; fileRef = 321F310D27D0DC490042B274 /* TestImage.bmp */; };
|
||||
3222417F2272F808002429DB /* SDUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3222417E2272F808002429DB /* SDUtilsTests.m */; };
|
||||
322241802272F808002429DB /* SDUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3222417E2272F808002429DB /* SDUtilsTests.m */; };
|
||||
3226ECBB20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */; };
|
||||
|
@ -123,6 +126,7 @@
|
|||
2D7AF05E1F329763000083C2 /* SDTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDTestCase.h; sourceTree = "<group>"; };
|
||||
2D7AF05F1F329763000083C2 /* SDTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDTestCase.m; sourceTree = "<group>"; };
|
||||
320224F62440C39B00E5B29D /* TestImageLarge.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TestImageLarge.png; sourceTree = "<group>"; };
|
||||
321F310D27D0DC490042B274 /* TestImage.bmp */ = {isa = PBXFileReference; lastKnownFileType = image.bmp; path = TestImage.bmp; sourceTree = "<group>"; };
|
||||
3222417E2272F808002429DB /* SDUtilsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDUtilsTests.m; sourceTree = "<group>"; };
|
||||
3226ECB920754F7700FAFACF /* SDWebImageTestDownloadOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestDownloadOperation.h; sourceTree = "<group>"; };
|
||||
3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestDownloadOperation.m; sourceTree = "<group>"; };
|
||||
|
@ -256,6 +260,7 @@
|
|||
32648066250232F7004FA0FC /* 1@2x.gif */,
|
||||
433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */,
|
||||
324047432271956F007C53E1 /* TestEXIF.png */,
|
||||
321F310D27D0DC490042B274 /* TestImage.bmp */,
|
||||
433BBBB61D7EF8200086B6E9 /* TestImage.gif */,
|
||||
326E69462334C0C200B7252C /* TestLoopCount.gif */,
|
||||
5F7F38AC1AE2A77A00B0E330 /* TestImage.jpg */,
|
||||
|
@ -476,6 +481,7 @@
|
|||
3299228C2365DC6C00EAFD97 /* TestImage.heif in Resources */,
|
||||
3234306423E2BAC800C290C8 /* TestImage.pdf in Resources */,
|
||||
320224F92440C39B00E5B29D /* TestImageLarge.png in Resources */,
|
||||
321F311027D0DC490042B274 /* TestImage.bmp in Resources */,
|
||||
329922892365DC6C00EAFD97 /* TestImageLarge.jpg in Resources */,
|
||||
32648069250232F7004FA0FC /* 1@2x.gif in Resources */,
|
||||
3299228A2365DC6C00EAFD97 /* TestImage.png in Resources */,
|
||||
|
@ -500,6 +506,7 @@
|
|||
32B99EA4203B31360017FD66 /* TestImage.jpg in Resources */,
|
||||
3234306323E2BAC800C290C8 /* TestImage.pdf in Resources */,
|
||||
320224F82440C39B00E5B29D /* TestImageLarge.png in Resources */,
|
||||
321F310F27D0DC490042B274 /* TestImage.bmp in Resources */,
|
||||
32B99EA6203B31360017FD66 /* TestImage.png in Resources */,
|
||||
32648068250232F7004FA0FC /* 1@2x.gif in Resources */,
|
||||
3297A0A023374D1700814590 /* TestImageAnimated.heic in Resources */,
|
||||
|
@ -524,6 +531,7 @@
|
|||
43828A451DA67F9900000E62 /* TestImageLarge.jpg in Resources */,
|
||||
3234306223E2BAC800C290C8 /* TestImage.pdf in Resources */,
|
||||
320224F72440C39B00E5B29D /* TestImageLarge.png in Resources */,
|
||||
321F310E27D0DC490042B274 /* TestImage.bmp in Resources */,
|
||||
433BBBB71D7EF8200086B6E9 /* TestImage.gif in Resources */,
|
||||
32648067250232F7004FA0FC /* 1@2x.gif in Resources */,
|
||||
433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */,
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.4 MiB |
|
@ -154,10 +154,10 @@
|
|||
expect(CGSizeEqualToSize(tintedImage.size, testImage.size)).beTruthy();
|
||||
// Check center color, should keep clear
|
||||
UIColor *centerColor = [tintedImage sd_colorAtPoint:CGPointMake(150, 150)];
|
||||
expect([centerColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]);
|
||||
expect([centerColor.sd_hexString isEqualToString:[UIColor clearColor].sd_hexString]).beTruthy();
|
||||
// Check left color, should be tinted
|
||||
UIColor *leftColor = [tintedImage sd_colorAtPoint:CGPointMake(80, 150)];
|
||||
expect([leftColor.sd_hexString isEqualToString:tintColor.sd_hexString]);
|
||||
expect([leftColor.sd_hexString isEqualToString:tintColor.sd_hexString]).beTruthy();
|
||||
// Check rounded corner operation not inversion the image
|
||||
UIColor *topCenterColor = [tintedImage sd_colorAtPoint:CGPointMake(150, 20)];
|
||||
expect([topCenterColor.sd_hexString isEqualToString:[UIColor blackColor].sd_hexString]).beTruthy();
|
||||
|
@ -177,9 +177,17 @@
|
|||
expect(CGSizeEqualToSize(blurredImage.size, testImage.size)).beTruthy();
|
||||
// Check left color, should be blurred
|
||||
UIColor *leftColor = [blurredImage sd_colorAtPoint:CGPointMake(80, 150)];
|
||||
// Hard-code from the output
|
||||
UIColor *expectedColor = [UIColor colorWithRed:0.431373 green:0.101961 blue:0.0901961 alpha:0.729412];
|
||||
expect([leftColor.sd_hexString isEqualToString:expectedColor.sd_hexString]);
|
||||
// Hard-code from the output, allows a little deviation because of blur diffs between OS versions :)
|
||||
// rgba(114, 27, 23, 0.75)
|
||||
UIColor *expectedColor = [UIColor colorWithRed:114.0/255.0 green:27.0/255.0 blue:23.0/255.0 alpha:0.75];
|
||||
CGFloat r1, g1, b1, a1;
|
||||
CGFloat r2, g2, b2, a2;
|
||||
[leftColor getRed:&r1 green:&g1 blue:&b1 alpha:&a1];
|
||||
[expectedColor getRed:&r2 green:&g2 blue:&b2 alpha:&a2];
|
||||
expect(r1).beCloseToWithin(r2, 2.0/255.0);
|
||||
expect(g1).beCloseToWithin(g2, 2.0/255.0);
|
||||
expect(b1).beCloseToWithin(b2, 2.0/255.0);
|
||||
expect(a1).beCloseToWithin(a2, 2.0/255.0);
|
||||
// Check rounded corner operation not inversion the image
|
||||
UIColor *topCenterColor = [blurredImage sd_colorAtPoint:CGPointMake(150, 20)];
|
||||
UIColor *bottomCenterColor = [blurredImage sd_colorAtPoint:CGPointMake(150, 280)];
|
||||
|
@ -203,7 +211,7 @@
|
|||
UIColor *leftColor = [filteredImage sd_colorAtPoint:CGPointMake(80, 150)];
|
||||
// Hard-code from the output
|
||||
UIColor *expectedColor = [UIColor colorWithRed:0.85098 green:0.992157 blue:0.992157 alpha:1];
|
||||
expect([leftColor.sd_hexString isEqualToString:expectedColor.sd_hexString]);
|
||||
expect([leftColor.sd_hexString isEqualToString:expectedColor.sd_hexString]).beTruthy();
|
||||
// Check rounded corner operation not inversion the image
|
||||
UIColor *topCenterColor = [filteredImage sd_colorAtPoint:CGPointMake(150, 20)];
|
||||
expect([topCenterColor.sd_hexString isEqualToString:[UIColor whiteColor].sd_hexString]).beTruthy();
|
||||
|
@ -398,6 +406,17 @@
|
|||
CGImageRelease(leftCGImage);
|
||||
}
|
||||
|
||||
- (void)test21BMPImageCreateDecodedShouldNotBlank {
|
||||
UIImage *testImage = [[UIImage alloc] initWithContentsOfFile:[self testBMPPathForName:@"TestImage"]];
|
||||
CGImageRef cgImage = testImage.CGImage;
|
||||
expect(cgImage).notTo.beNil();
|
||||
UIImage *decodedImage = [SDImageCoderHelper decodedImageWithImage:testImage];
|
||||
expect(decodedImage).notTo.beNil();
|
||||
UIColor *testColor = [decodedImage sd_colorAtPoint:CGPointMake(100, 100)];
|
||||
// Should not be black color
|
||||
expect([[testColor sd_hexString] isEqualToString:UIColor.blackColor.sd_hexString]).beFalsy();
|
||||
}
|
||||
|
||||
#pragma mark - Helper
|
||||
|
||||
- (UIImage *)testImageCG {
|
||||
|
@ -424,4 +443,9 @@
|
|||
return [testBundle pathForResource:name ofType:@"png"];
|
||||
}
|
||||
|
||||
- (NSString *)testBMPPathForName:(NSString *)name {
|
||||
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
|
||||
return [testBundle pathForResource:name ofType:@"bmp"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Loading…
Reference in New Issue