Merge pull request #3678 from dreampiggy/bugfix/16bit-png-workaround-bug
Fix the issue that iOS 17 indexed PNG workaround breaks the 16bit RGBA PNG
This commit is contained in:
commit
9953745d94
|
@ -99,12 +99,24 @@ jobs:
|
|||
DEVELOPER_DIR: /Applications/Xcode_15.2.app
|
||||
WORKSPACE_NAME: SDWebImage.xcworkspace
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
iosDestination: platform=iOS Simulator,name=iPhone 15 Pro
|
||||
macOSDestination: platform=macOS,arch=x86_64
|
||||
macCatalystDestination: platform=macOS,arch=x86_64,variant=Mac Catalyst
|
||||
tvOSDestination: platform=tvOS Simulator,name=Apple TV 4K (3rd generation)
|
||||
watchOSDestination: platform=watchOS Simulator,name=Apple Watch Series 9 (45mm)
|
||||
visionOSDestination: platform=visionOS Simulator,name=Apple Vision Pro
|
||||
# use matrix to generate jobs for each platform
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [iOS, macOS, tvOS, visionOS]
|
||||
include:
|
||||
- platform: iOS
|
||||
destination: platform=iOS Simulator,name=iPhone 15 Pro
|
||||
scheme: iOS
|
||||
- platform: macOS
|
||||
destination: platform=macOS,arch=x86_64
|
||||
scheme: Mac
|
||||
- platform: tvOS
|
||||
destination: platform=tvOS Simulator,name=Apple TV 4K (3rd generation)
|
||||
scheme: TV
|
||||
- platform: visionOS
|
||||
destination: platform=visionOS Simulator,name=Apple Vision Pro
|
||||
scheme: Vision
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
@ -126,39 +138,18 @@ jobs:
|
|||
rm -rf ~/Library/Developer/Xcode/DerivedData/
|
||||
mkdir DerivedData
|
||||
|
||||
- name: Test for iOS
|
||||
- name: Run test
|
||||
run: |
|
||||
set -o pipefail
|
||||
xcodebuild test -workspace "${{ env.WORKSPACE_NAME }}" -scheme "Tests iOS" -destination "${{ env.iosDestination }}" -configuration Debug CODE_SIGNING_ALLOWED=NO
|
||||
mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/iOS
|
||||
|
||||
- name: Test for macOS
|
||||
run: |
|
||||
set -o pipefail
|
||||
xcodebuild test -workspace "${{ env.WORKSPACE_NAME }}" -scheme "Tests Mac" -destination "${{ env.macOSDestination }}" -configuration Debug CODE_SIGNING_ALLOWED=NO
|
||||
mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/macOS
|
||||
|
||||
- name: Test for tvOS
|
||||
run: |
|
||||
set -o pipefail
|
||||
xcodebuild test -workspace "${{ env.WORKSPACE_NAME }}" -scheme "Tests TV" -destination "${{ env.tvOSDestination }}" -configuration Debug CODE_SIGNING_ALLOWED=NO
|
||||
mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/tvOS
|
||||
|
||||
- name: Test for visionOS
|
||||
run: |
|
||||
set -o pipefail
|
||||
xcodebuild test -workspace "${{ env.WORKSPACE_NAME }}" -scheme "Tests Vision" -destination "${{ env.visionOSDestination }}" -configuration Debug CODE_SIGNING_ALLOWED=NO
|
||||
mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/visionOS
|
||||
xcodebuild test -workspace "${{ env.WORKSPACE_NAME }}" -scheme "Tests ${{ matrix.scheme }}" -destination "${{ matrix.destination }}" -configuration Debug CODE_SIGNING_ALLOWED=NO
|
||||
mv ~/Library/Developer/Xcode/DerivedData/ "./DerivedData/{{ matrix.platform }}"
|
||||
|
||||
- name: Code Coverage
|
||||
run: |
|
||||
set -o pipefail
|
||||
export PATH="/usr/local/opt/curl/bin:$PATH"
|
||||
curl --version
|
||||
bash <(curl -s https://codecov.io/bash) -v -D './DerivedData/macOS' -J '^SDWebImage$' -c -X gcov -F macos
|
||||
bash <(curl -s https://codecov.io/bash) -v -D './DerivedData/iOS' -J '^SDWebImage$' -c -X gcov -F ios
|
||||
bash <(curl -s https://codecov.io/bash) -v -D './DerivedData/tvOS' -J '^SDWebImage$' -c -X gcov -F tvos
|
||||
bash <(curl -s https://codecov.io/bash) -v -D './DerivedData/visionOS' -J '^SDWebImage$' -c -X gcov -F visionos
|
||||
bash <(curl -s https://codecov.io/bash) -v -D "./DerivedData/{{ matrix.platform }}" -J '^SDWebImage$' -c -X gcov -F "{{ matrix.platform }}"
|
||||
|
||||
Build:
|
||||
name: Build Library
|
||||
|
|
|
@ -316,14 +316,14 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
|
|||
cgImage = SDImageGetNonAlphaDummyImage().CGImage;
|
||||
}
|
||||
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(cgImage);
|
||||
size_t bitsPerPixel = 8;
|
||||
size_t bitsPerComponent = 8;
|
||||
if (SD_OPTIONS_CONTAINS(bitmapInfo, kCGBitmapFloatComponents)) {
|
||||
bitsPerPixel = 16;
|
||||
bitsPerComponent = 16;
|
||||
}
|
||||
size_t components = 4; // Hardcode now
|
||||
// https://github.com/path/FastImageCache#byte-alignment
|
||||
// A properly aligned bytes-per-row value must be a multiple of 8 pixels × bytes per pixel.
|
||||
size_t alignment = (bitsPerPixel / 8) * components * 8;
|
||||
size_t alignment = (bitsPerComponent / 8) * components * 8;
|
||||
SDImagePixelFormat pixelFormat = {
|
||||
.bitmapInfo = bitmapInfo,
|
||||
.alignment = alignment
|
||||
|
|
|
@ -48,6 +48,10 @@ static CGImageRef __nullable SDCGImageCreateMutableCopy(CGImageRef cg_nullable i
|
|||
return newImage;
|
||||
}
|
||||
|
||||
static inline BOOL SDCGImageIs8Bit(CGImageRef cg_nullable image) {
|
||||
return CGImageGetBitsPerComponent(image) == 8;
|
||||
}
|
||||
|
||||
static inline CGImageRef __nullable SDCGImageCreateCopy(CGImageRef cg_nullable image) {
|
||||
if (!image) return nil;
|
||||
return SDCGImageCreateMutableCopy(image, CGImageGetBitmapInfo(image));
|
||||
|
@ -209,6 +213,7 @@ static BOOL SDImageIOPNGPluginBuggyNeedWorkaround(void) {
|
|||
// See: #3605 FB13322459
|
||||
// ImageIO on iOS 17 (17.0~17.2), there is one serious problem on ImageIO PNG plugin. The decode result for indexed color PNG use the wrong CGImageAlphaInfo
|
||||
// The returned CGImageAlphaInfo is alpha last, but the actual bitmap data is premultiplied alpha last, which cause many runtime render bug.
|
||||
// The bug only exists on 8-bits indexed color, not about 16-bits
|
||||
// So, we do a hack workaround:
|
||||
// 1. Decode a indexed color PNG in runtime
|
||||
// 2. If the bitmap is premultiplied alpha, then assume it's buggy
|
||||
|
@ -527,7 +532,7 @@ static BOOL SDImageIOPNGPluginBuggyNeedWorkaround(void) {
|
|||
// :)
|
||||
CFStringRef uttype = CGImageSourceGetType(source);
|
||||
SDImageFormat imageFormat = [NSData sd_imageFormatFromUTType:uttype];
|
||||
if (imageFormat == SDImageFormatPNG && SDImageIOPNGPluginBuggyNeedWorkaround()) {
|
||||
if (imageFormat == SDImageFormatPNG && SDCGImageIs8Bit(imageRef) && SDImageIOPNGPluginBuggyNeedWorkaround()) {
|
||||
CGImageRef newImageRef = SDImageIOPNGPluginBuggyCreateWorkaround(imageRef);
|
||||
CGImageRelease(imageRef);
|
||||
imageRef = newImageRef;
|
||||
|
|
|
@ -141,6 +141,10 @@
|
|||
32B99EAC203B36650017FD66 /* SDWebImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C51E819B46E370092B5E6 /* SDWebImageDownloaderTests.m */; };
|
||||
32B99EAD203B36690017FD66 /* SDWebImagePrefetcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C1D01D97F80F007E863A /* SDWebImagePrefetcherTests.m */; };
|
||||
32B99EAE203B366C0017FD66 /* SDWebCacheCategoriesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4369C2731D9804B1007E863A /* SDWebCacheCategoriesTests.m */; };
|
||||
32C268282B888A4100CA29AE /* RGBA16PNG.png in Resources */ = {isa = PBXBuildFile; fileRef = 32C268272B888A4100CA29AE /* RGBA16PNG.png */; };
|
||||
32C268292B888A4100CA29AE /* RGBA16PNG.png in Resources */ = {isa = PBXBuildFile; fileRef = 32C268272B888A4100CA29AE /* RGBA16PNG.png */; };
|
||||
32C2682A2B888A4100CA29AE /* RGBA16PNG.png in Resources */ = {isa = PBXBuildFile; fileRef = 32C268272B888A4100CA29AE /* RGBA16PNG.png */; };
|
||||
32C2682B2B888A4100CA29AE /* RGBA16PNG.png in Resources */ = {isa = PBXBuildFile; fileRef = 32C268272B888A4100CA29AE /* RGBA16PNG.png */; };
|
||||
32E6F0321F3A1B4700A945E6 /* SDWebImageTestCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 32E6F0311F3A1B4700A945E6 /* SDWebImageTestCoder.m */; };
|
||||
32F788A3290D252200B57A1C /* TestImage.nef in Resources */ = {isa = PBXBuildFile; fileRef = 32F788A2290D252200B57A1C /* TestImage.nef */; };
|
||||
32F788A4290D252200B57A1C /* TestImage.nef in Resources */ = {isa = PBXBuildFile; fileRef = 32F788A2290D252200B57A1C /* TestImage.nef */; };
|
||||
|
@ -207,6 +211,7 @@
|
|||
32B99E8A203AF8690017FD66 /* SDCategoriesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDCategoriesTests.m; sourceTree = "<group>"; };
|
||||
32B99E92203B2DF90017FD66 /* Tests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
32B99E96203B2DF90017FD66 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
32C268272B888A4100CA29AE /* RGBA16PNG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = RGBA16PNG.png; sourceTree = "<group>"; };
|
||||
32E6F0301F3A1B4700A945E6 /* SDWebImageTestCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestCoder.h; sourceTree = "<group>"; };
|
||||
32E6F0311F3A1B4700A945E6 /* SDWebImageTestCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestCoder.m; sourceTree = "<group>"; };
|
||||
32F788A2290D252200B57A1C /* TestImage.nef */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImage.nef; sourceTree = "<group>"; };
|
||||
|
@ -331,6 +336,7 @@
|
|||
children = (
|
||||
32648066250232F7004FA0FC /* 1@2x.gif */,
|
||||
3278F5E12B04C1AC0004A6EE /* IndexedPNG.png */,
|
||||
32C268272B888A4100CA29AE /* RGBA16PNG.png */,
|
||||
433BBBBA1D7EFA8B0086B6E9 /* MonochromeTestImage.jpg */,
|
||||
324047432271956F007C53E1 /* TestEXIF.png */,
|
||||
3264CD162AAB1E23001E338B /* TestJFIF.jpg */,
|
||||
|
@ -580,6 +586,7 @@
|
|||
32464AA22B7B1833006BE70E /* TestImageLarge.jpg in Resources */,
|
||||
32464A912B7B1833006BE70E /* TestImage.nef in Resources */,
|
||||
32464A942B7B1833006BE70E /* TestJFIF.jpg in Resources */,
|
||||
32C2682B2B888A4100CA29AE /* RGBA16PNG.png in Resources */,
|
||||
32464A9B2B7B1833006BE70E /* TestAnimatedImageMemory.webp in Resources */,
|
||||
32464A992B7B1833006BE70E /* TestEXIF.png in Resources */,
|
||||
32464A922B7B1833006BE70E /* TestImage.heic in Resources */,
|
||||
|
@ -608,6 +615,7 @@
|
|||
6BC1C210270F073A003FFAB1 /* TestAnimatedImageMemory.webp in Resources */,
|
||||
3264CD192AAB1E23001E338B /* TestJFIF.jpg in Resources */,
|
||||
3299228D2365DC6C00EAFD97 /* TestImageAnimated.apng in Resources */,
|
||||
32C2682A2B888A4100CA29AE /* RGBA16PNG.png in Resources */,
|
||||
3299228B2365DC6C00EAFD97 /* TestImage.heic in Resources */,
|
||||
329922872365DC6C00EAFD97 /* TestLoopCount.gif in Resources */,
|
||||
3299228C2365DC6C00EAFD97 /* TestImage.heif in Resources */,
|
||||
|
@ -636,6 +644,7 @@
|
|||
6BC1C20F270F0193003FFAB1 /* TestAnimatedImageMemory.webp in Resources */,
|
||||
3264CD182AAB1E23001E338B /* TestJFIF.jpg in Resources */,
|
||||
327054E3206CEFF3006EA328 /* TestImageAnimated.apng in Resources */,
|
||||
32C268292B888A4100CA29AE /* RGBA16PNG.png in Resources */,
|
||||
32B99EA3203B31360017FD66 /* TestImage.gif in Resources */,
|
||||
324047452271956F007C53E1 /* TestEXIF.png in Resources */,
|
||||
32B99EA4203B31360017FD66 /* TestImage.jpg in Resources */,
|
||||
|
@ -664,6 +673,7 @@
|
|||
327A418C211D660600495442 /* TestImage.heic in Resources */,
|
||||
3264CD172AAB1E23001E338B /* TestJFIF.jpg in Resources */,
|
||||
6B181A1B265757ED00BD06B3 /* TestAnimatedImageMemory.webp in Resources */,
|
||||
32C268282B888A4100CA29AE /* RGBA16PNG.png in Resources */,
|
||||
5F7F38AD1AE2A77A00B0E330 /* TestImage.jpg in Resources */,
|
||||
32905E64211D786E00460FCF /* TestImage.heif in Resources */,
|
||||
43828A451DA67F9900000E62 /* TestImageLarge.jpg in Resources */,
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
|
@ -764,6 +764,7 @@ static BOOL _isCalled;
|
|||
[self waitForExpectationsWithTimeout:15 handler:nil];
|
||||
}
|
||||
|
||||
#if !SD_TV
|
||||
- (void)test36AnimatedImageMemoryCost {
|
||||
if (@available(iOS 14, tvOS 14, macOS 11, watchOS 7, *)) {
|
||||
[[SDImageCodersManager sharedManager] addCoder:[SDImageAWebPCoder sharedCoder]];
|
||||
|
@ -783,6 +784,7 @@ static BOOL _isCalled;
|
|||
[[SDImageCodersManager sharedManager] removeCoder:[SDImageAWebPCoder sharedCoder]];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark - Helper
|
||||
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
|
||||
#import "SDTestCase.h"
|
||||
#import "UIColor+SDHexString.h"
|
||||
#if __has_include(<SDWebImageWebPCoder/SDWebImageWebPCoder.h>)
|
||||
#import <SDWebImageWebPCoder/SDWebImageWebPCoder.h>
|
||||
#endif
|
||||
|
||||
@interface SDWebImageDecoderTests : SDTestCase
|
||||
|
||||
|
@ -269,15 +266,11 @@
|
|||
isVectorImage:YES];
|
||||
}
|
||||
|
||||
#if !SD_TV
|
||||
- (void)test18ThatStaticWebPWorks {
|
||||
if (@available(iOS 14, tvOS 14, macOS 11, *)) {
|
||||
NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageStatic" withExtension:@"webp"];
|
||||
#if SD_TV
|
||||
/// TV OS does not support ImageIO's webp.
|
||||
[self verifyCoder:[SDImageWebPCoder sharedCoder]
|
||||
#else
|
||||
[self verifyCoder:[SDImageAWebPCoder sharedCoder]
|
||||
#endif
|
||||
withLocalImageURL:staticWebPURL
|
||||
supportsEncoding:NO // Currently (iOS 14.0) seems no encoding support
|
||||
encodingFormat:SDImageFormatWebP
|
||||
|
@ -285,16 +278,13 @@
|
|||
isVectorImage:NO];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !SD_TV
|
||||
- (void)test19ThatAnimatedWebPWorks {
|
||||
if (@available(iOS 14, tvOS 14, macOS 11, *)) {
|
||||
NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageAnimated" withExtension:@"webp"];
|
||||
#if SD_TV
|
||||
/// TV OS does not support ImageIO's webp.
|
||||
[self verifyCoder:[SDImageWebPCoder sharedCoder]
|
||||
#else
|
||||
[self verifyCoder:[SDImageAWebPCoder sharedCoder]
|
||||
#endif
|
||||
withLocalImageURL:staticWebPURL
|
||||
supportsEncoding:NO // Currently (iOS 14.0) seems no encoding support
|
||||
encodingFormat:SDImageFormatWebP
|
||||
|
@ -302,6 +292,7 @@
|
|||
isVectorImage:NO];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)test20ThatImageIOAnimatedCoderAbstractClass {
|
||||
SDImageIOAnimatedCoder *coder = [[SDImageIOAnimatedCoder alloc] init];
|
||||
|
@ -573,6 +564,17 @@
|
|||
expect(g1).beCloseToWithin(0.91, 0.01);
|
||||
expect(b1).beCloseToWithin(0.91, 0.01);
|
||||
expect(a1).beCloseToWithin(0.20, 0.01);
|
||||
|
||||
// RGBA 16 bits PNG should not workaround
|
||||
url = [[NSBundle bundleForClass:[self class]] URLForResource:@"RGBA16PNG" withExtension:@"png"];
|
||||
data = [NSData dataWithContentsOfURL:url];
|
||||
decodedImage = [SDImageIOCoder.sharedCoder decodedImageWithData:data options:nil];
|
||||
testColor1 = [decodedImage sd_colorAtPoint:CGPointMake(100, 1)];
|
||||
[testColor1 getRed:&r1 green:&g1 blue:&b1 alpha:&a1];
|
||||
expect(r1).beCloseToWithin(0.60, 0.01);
|
||||
expect(g1).beCloseToWithin(0.60, 0.01);
|
||||
expect(b1).beCloseToWithin(0.33, 0.01);
|
||||
expect(a1).beCloseToWithin(0.33, 0.01);
|
||||
}
|
||||
|
||||
#pragma mark - Utils
|
||||
|
|
|
@ -39,7 +39,9 @@ NSString *const kTestAPNGPURL = @"https://upload.wikimedia.org/wikipedia/commons
|
|||
CGRect screenFrame = mainScreen.bounds;
|
||||
#endif
|
||||
_window = [[UIWindow alloc] initWithFrame:screenFrame];
|
||||
#else
|
||||
#endif // UIKit
|
||||
#if SD_MAC
|
||||
UIScreen *mainScreen = [UIScreen mainScreen];
|
||||
_window = [[NSWindow alloc] initWithContentRect:mainScreen.frame styleMask:0 backing:NSBackingStoreBuffered defer:NO screen:mainScreen];
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -10,9 +10,6 @@
|
|||
#import "SDWebImageTestTransformer.h"
|
||||
#import "SDWebImageTestCache.h"
|
||||
#import "SDWebImageTestLoader.h"
|
||||
#if __has_include(<SDWebImageWebPCoder/SDWebImageWebPCoder.h>)
|
||||
#import <SDWebImageWebPCoder/SDWebImageWebPCoder.h>
|
||||
#endif
|
||||
|
||||
// Keep strong references for object
|
||||
@interface SDObjectContainer<ObjectType> : NSObject
|
||||
|
@ -646,23 +643,6 @@
|
|||
[self waitForExpectationsWithCommonTimeout];
|
||||
}
|
||||
|
||||
#if __has_include(<SDWebImageWebPCoder/SDWebImageWebPCoder.h>)
|
||||
- (void)test22ThatForceDecodePolicyAlways {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Always policy with WebP image (libwebp) should force-decode"];
|
||||
NSURL *url = [NSURL URLWithString:@"https://www.gstatic.com/webp/gallery/4.webp"];
|
||||
[SDWebImageManager.sharedManager loadImageWithURL:url options:SDWebImageFromLoaderOnly context:@{SDWebImageContextImageCoder : SDImageWebPCoder.sharedCoder, SDWebImageContextImageForceDecodePolicy : @(SDImageForceDecodePolicyAlways)} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
|
||||
expect(image).notTo.beNil();
|
||||
expect(image.sd_isDecoded).beTruthy();
|
||||
CGImageRef cgImage = image.CGImage;
|
||||
CGColorSpaceRef colorspace = CGImageGetColorSpace(cgImage);
|
||||
expect(colorspace).equal([SDImageCoderHelper colorSpaceGetDeviceRGB]);
|
||||
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithCommonTimeout];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (NSString *)testJPEGPath {
|
||||
NSBundle *testBundle = [NSBundle bundleForClass:[self class]];
|
||||
return [testBundle pathForResource:@"TestImage" ofType:@"jpg"];
|
||||
|
|
Loading…
Reference in New Issue