Merge pull request #14 from SDWebImage/bugfix_webp_blend_canvas

Fix the logic for Animated WebP images which contains a subsequence blend from the first frame, impact the `SDAnimatedImage`
This commit is contained in:
Kinarobin 2019-05-15 13:07:31 +08:00 committed by GitHub
commit 0713611138
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 72 additions and 10 deletions

View File

@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
0EF5B6264833B7BC20894578 /* Pods_SDWebImageWebPCoderTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 46F21AD7D1692EBAC4D0FF33 /* Pods_SDWebImageWebPCoderTests.framework */; }; 0EF5B6264833B7BC20894578 /* Pods_SDWebImageWebPCoderTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 46F21AD7D1692EBAC4D0FF33 /* Pods_SDWebImageWebPCoderTests.framework */; };
3219F3B2228B0453003822A6 /* TestImageBlendAnimated.webp in Resources */ = {isa = PBXBuildFile; fileRef = 3219F3B1228B0453003822A6 /* TestImageBlendAnimated.webp */; };
806E77B32136A2E900A316D2 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 806E77AA2136A2E900A316D2 /* UIImage+WebP.m */; }; 806E77B32136A2E900A316D2 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 806E77AA2136A2E900A316D2 /* UIImage+WebP.m */; };
806E77B42136A2E900A316D2 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 806E77AB2136A2E900A316D2 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 806E77B42136A2E900A316D2 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 806E77AB2136A2E900A316D2 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; };
806E77B62136A2E900A316D2 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 806E77AD2136A2E900A316D2 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 806E77B62136A2E900A316D2 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 806E77AD2136A2E900A316D2 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -44,6 +45,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
28D8AA3D3015E075692FD3E3 /* Pods-SDWebImageWebPCoderTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImageWebPCoderTests.debug.xcconfig"; path = "SDWebImageWebPCoderTests/Pods/Target Support Files/Pods-SDWebImageWebPCoderTests/Pods-SDWebImageWebPCoderTests.debug.xcconfig"; sourceTree = "<group>"; }; 28D8AA3D3015E075692FD3E3 /* Pods-SDWebImageWebPCoderTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImageWebPCoderTests.debug.xcconfig"; path = "SDWebImageWebPCoderTests/Pods/Target Support Files/Pods-SDWebImageWebPCoderTests/Pods-SDWebImageWebPCoderTests.debug.xcconfig"; sourceTree = "<group>"; };
3217BE7B220547EB003D0310 /* SDWebImageWebPCoder.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = SDWebImageWebPCoder.modulemap; sourceTree = "<group>"; }; 3217BE7B220547EB003D0310 /* SDWebImageWebPCoder.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = SDWebImageWebPCoder.modulemap; sourceTree = "<group>"; };
3219F3B1228B0453003822A6 /* TestImageBlendAnimated.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestImageBlendAnimated.webp; sourceTree = "<group>"; };
46F21AD7D1692EBAC4D0FF33 /* Pods_SDWebImageWebPCoderTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImageWebPCoderTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 46F21AD7D1692EBAC4D0FF33 /* Pods_SDWebImageWebPCoderTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImageWebPCoderTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
806E779D2136A1C000A316D2 /* SDWebImageWebPCoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageWebPCoder.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 806E779D2136A1C000A316D2 /* SDWebImageWebPCoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageWebPCoder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
806E77AA2136A2E900A316D2 /* UIImage+WebP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+WebP.m"; sourceTree = "<group>"; }; 806E77AA2136A2E900A316D2 /* UIImage+WebP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+WebP.m"; sourceTree = "<group>"; };
@ -205,6 +207,7 @@
children = ( children = (
808C919A213FD2B2004B0F7C /* TestImageStatic.webp */, 808C919A213FD2B2004B0F7C /* TestImageStatic.webp */,
808C919B213FD2B2004B0F7C /* TestImageAnimated.webp */, 808C919B213FD2B2004B0F7C /* TestImageAnimated.webp */,
3219F3B1228B0453003822A6 /* TestImageBlendAnimated.webp */,
); );
path = Images; path = Images;
sourceTree = "<group>"; sourceTree = "<group>";
@ -453,6 +456,7 @@
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
3219F3B2228B0453003822A6 /* TestImageBlendAnimated.webp in Resources */,
808C919D213FD2B2004B0F7C /* TestImageAnimated.webp in Resources */, 808C919D213FD2B2004B0F7C /* TestImageAnimated.webp in Resources */,
808C919C213FD2B2004B0F7C /* TestImageStatic.webp in Resources */, 808C919C213FD2B2004B0F7C /* TestImageStatic.webp in Resources */,
); );
@ -620,8 +624,14 @@
"DEBUG=1", "DEBUG=1",
"$(inherited)", "$(inherited)",
); );
"GCC_PREPROCESSOR_DEFINITIONS[sdk=watchos*]" = "WEBP_USE_INTRINSICS=1 $(inherited)"; "GCC_PREPROCESSOR_DEFINITIONS[sdk=watchos*]" = (
"GCC_PREPROCESSOR_DEFINITIONS[sdk=watchsimulator*]" = "WEBP_USE_INTRINSICS=1 $(inherited)"; "WEBP_USE_INTRINSICS=1",
"$(inherited)",
);
"GCC_PREPROCESSOR_DEFINITIONS[sdk=watchsimulator*]" = (
"WEBP_USE_INTRINSICS=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;
@ -689,8 +699,14 @@
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
"GCC_PREPROCESSOR_DEFINITIONS[sdk=watchos*]" = "WEBP_USE_INTRINSICS=1 $(inherited)"; "GCC_PREPROCESSOR_DEFINITIONS[sdk=watchos*]" = (
"GCC_PREPROCESSOR_DEFINITIONS[sdk=watchsimulator*]" = "WEBP_USE_INTRINSICS=1 $(inherited)"; "WEBP_USE_INTRINSICS=1",
"$(inherited)",
);
"GCC_PREPROCESSOR_DEFINITIONS[sdk=watchsimulator*]" = (
"WEBP_USE_INTRINSICS=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;

View File

@ -46,8 +46,8 @@
@property (nonatomic, assign) NSUInteger offsetY; // Frame origin.y in canvas (left-bottom based) @property (nonatomic, assign) NSUInteger offsetY; // Frame origin.y in canvas (left-bottom based)
@property (nonatomic, assign) BOOL hasAlpha; // Whether frame contains alpha @property (nonatomic, assign) BOOL hasAlpha; // Whether frame contains alpha
@property (nonatomic, assign) BOOL isFullSize; // Whether frame size is equal to canvas size @property (nonatomic, assign) BOOL isFullSize; // Whether frame size is equal to canvas size
@property (nonatomic, assign) WebPMuxAnimBlend blend; // Frame dispose method @property (nonatomic, assign) BOOL shouldBlend; // Frame dispose method
@property (nonatomic, assign) WebPMuxAnimDispose dispose; // Frame blend operation @property (nonatomic, assign) BOOL shouldDispose; // Frame blend operation
@property (nonatomic, assign) NSUInteger blendFromIndex; // The nearest previous frame index which blend mode is WEBP_MUX_BLEND @property (nonatomic, assign) NSUInteger blendFromIndex; // The nearest previous frame index which blend mode is WEBP_MUX_BLEND
@end @end
@ -719,8 +719,8 @@ static void FreeImageData(void *info, const void *data, size_t size) {
frame.width = iter.width; frame.width = iter.width;
frame.height = iter.height; frame.height = iter.height;
frame.hasAlpha = iter.has_alpha; frame.hasAlpha = iter.has_alpha;
frame.dispose = iter.dispose_method; frame.shouldDispose = iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND;
frame.blend = iter.blend_method; frame.shouldBlend = iter.blend_method == WEBP_MUX_BLEND;
frame.offsetX = iter.x_offset; frame.offsetX = iter.x_offset;
frame.offsetY = canvasHeight - iter.y_offset - iter.height; frame.offsetY = canvasHeight - iter.y_offset - iter.height;
@ -728,11 +728,11 @@ static void FreeImageData(void *info, const void *data, size_t size) {
BOOL offsetIsZero = (iter.x_offset == 0 && iter.y_offset == 0); BOOL offsetIsZero = (iter.x_offset == 0 && iter.y_offset == 0);
frame.isFullSize = (sizeEqualsToCanvas && offsetIsZero); frame.isFullSize = (sizeEqualsToCanvas && offsetIsZero);
if ((!frame.blend || !frame.hasAlpha) && frame.isFullSize) { if ((!frame.shouldBlend || !frame.hasAlpha) && frame.isFullSize) {
lastBlendIndex = iterIndex; lastBlendIndex = iterIndex;
frame.blendFromIndex = iterIndex; frame.blendFromIndex = iterIndex;
} else { } else {
if (frame.dispose && frame.isFullSize) { if (frame.shouldDispose && frame.isFullSize) {
frame.blendFromIndex = lastBlendIndex; frame.blendFromIndex = lastBlendIndex;
lastBlendIndex = iterIndex + 1; lastBlendIndex = iterIndex + 1;
} else { } else {

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -28,6 +28,11 @@ const int64_t kAsyncTestTimeout = 5;
@property (nonatomic, assign) BOOL isProgressive; @property (nonatomic, assign) BOOL isProgressive;
@end @end
@interface SDWebPCoderFrame : NSObject
@property (nonatomic, assign) NSUInteger index; // Frame index (zero based)
@property (nonatomic, assign) NSUInteger blendFromIndex; // The nearest previous frame index which blend mode is WEBP_MUX_BLEND
@end
@implementation SDWebImageWebPCoderTests @implementation SDWebImageWebPCoderTests
+ (void)setUp { + (void)setUp {
@ -126,6 +131,47 @@ const int64_t kAsyncTestTimeout = 5;
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil]; [self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
} }
- (void)test33AnimatedImageBlendMethod {
// Test the optimization for blend and disposal method works without problem
NSURL *animatedWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageBlendAnimated" withExtension:@"webp"];
NSData *data = [NSData dataWithContentsOfURL:animatedWebPURL];
SDImageWebPCoder *coder = [[SDImageWebPCoder alloc] initWithAnimatedImageData:data options:nil];
XCTAssertNotNil(coder);
/**
This WebP image frames info is below:
Canvas size: 400 x 400
Features present: animation transparency
Background color : 0xFF000000 Loop Count : 0
Number of frames: 12
No.: width height alpha x_offset y_offset duration dispose blend image_size compression
1: 400 400 no 0 0 70 none no 5178 lossless
2: 400 400 yes 0 0 70 none yes 1386 lossless
3: 400 400 yes 0 0 70 none yes 1472 lossless
4: 400 394 yes 0 6 70 none yes 3212 lossless
5: 371 394 yes 0 6 70 none yes 1888 lossless
6: 394 382 yes 6 6 70 none yes 3346 lossless
7: 400 388 yes 0 0 70 none yes 3786 lossless
8: 394 383 yes 0 0 70 none yes 1858 lossless
9: 394 394 yes 0 6 70 none yes 3794 lossless
10: 372 394 yes 22 6 70 none yes 3458 lossless
11: 400 400 no 0 0 70 none no 5270 lossless
12: 320 382 yes 0 6 70 none yes 2506 lossless
*/
NSArray<SDWebPCoderFrame *> *frames = [coder valueForKey:@"_frames"];
XCTAssertEqual(frames.count, 12);
for (SDWebPCoderFrame *frame in frames) {
switch (frame.index) {
// frame: 11 blend == no, means clear the canvas
case 10:
case 11:
XCTAssertEqual(frame.blendFromIndex, 10);
break;
default:
XCTAssertEqual(frame.blendFromIndex, 0);
break;
}
}
}
@end @end