@@ -194,11 +194,11 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
194
194
CGColorSpaceRef colorSpace = [self sd_createColorSpaceWithDemuxer: demuxer];
195
195
int canvasWidth = WebPDemuxGetI (demuxer, WEBP_FF_CANVAS_WIDTH);
196
196
int canvasHeight = WebPDemuxGetI (demuxer, WEBP_FF_CANVAS_HEIGHT);
197
+ // Check whether we need to use thumbnail
198
+ CGSize scaledSize = SDCalculateThumbnailSize (CGSizeMake (canvasWidth, canvasHeight), preserveAspectRatio, thumbnailSize);
197
199
198
200
if (!hasAnimation || decodeFirstFrame) {
199
201
// first frame for animated webp image
200
- CGSize scaledSize = SDCalculateThumbnailSize (CGSizeMake (canvasWidth, canvasHeight), preserveAspectRatio, thumbnailSize);
201
- // Create thumbnail if need
202
202
CGImageRef imageRef = [self sd_createWebpImageWithData: iter.fragment colorSpace: colorSpace scaledSize: scaledSize];
203
203
CGColorSpaceRelease (colorSpace);
204
204
#if SD_UIKIT || SD_WATCH
@@ -228,10 +228,11 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
228
228
229
229
do {
230
230
@autoreleasepool {
231
- CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas: canvas iterator: iter colorSpace: colorSpace];
231
+ CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas: canvas iterator: iter colorSpace: colorSpace scaledSize: scaledSize ];
232
232
if (!imageRef) {
233
233
continue ;
234
234
}
235
+
235
236
#if SD_UIKIT || SD_WATCH
236
237
UIImage *image = [[UIImage alloc ] initWithCGImage: imageRef scale: scale orientation: UIImageOrientationUp];
237
238
#else
@@ -399,12 +400,13 @@ - (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)
399
400
}
400
401
}
401
402
402
- - (nullable CGImageRef)sd_drawnWebpImageWithCanvas : (CGContextRef)canvas iterator : (WebPIterator)iter colorSpace : (nonnull CGColorSpaceRef)colorSpaceRef CF_RETURNS_RETAINED {
403
+ - (nullable CGImageRef)sd_drawnWebpImageWithCanvas : (CGContextRef)canvas iterator : (WebPIterator)iter colorSpace : (nonnull CGColorSpaceRef)colorSpaceRef scaledSize : (CGSize) scaledSize CF_RETURNS_RETAINED {
403
404
CGImageRef imageRef = [self sd_createWebpImageWithData: iter.fragment colorSpace: colorSpaceRef scaledSize: CGSizeZero];
404
405
if (!imageRef) {
405
406
return nil ;
406
407
}
407
408
409
+ size_t canvasWidth = CGBitmapContextGetWidth (canvas);
408
410
size_t canvasHeight = CGBitmapContextGetHeight (canvas);
409
411
CGFloat tmpX = iter.x_offset ;
410
412
CGFloat tmpY = canvasHeight - iter.height - iter.y_offset ;
@@ -425,6 +427,17 @@ - (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator
425
427
CGContextClearRect (canvas, imageRect);
426
428
}
427
429
430
+ // Check whether we need to use thumbnail
431
+ if (!CGSizeEqualToSize (CGSizeMake (canvasWidth, canvasHeight), scaledSize)) {
432
+ // Important: For Animated WebP thumbnail generation, we can not just use a scaled small canvas and draw each thumbnail frame
433
+ // This works **On Theory**. However, image scale down loss details. Animated WebP use the partial pixels with blend mode / dispose method with offset, to cover previous canvas status
434
+ // Because of this reason, even each frame contains small zigzag, the final animation contains visible glitch, this is not we want.
435
+ // So, always create the full pixels canvas (even though this consume more RAM), after drawn on the canvas, re-scale again with the final size
436
+ CGImageRef scaledImageRef = [SDImageCoderHelper CGImageCreateScaled: newImageRef size: scaledSize];
437
+ CGImageRelease (newImageRef);
438
+ newImageRef = scaledImageRef;
439
+ }
440
+
428
441
return newImageRef;
429
442
}
430
443
@@ -899,6 +912,7 @@ - (UIImage *)safeStaticImageFrame {
899
912
WebPDemuxReleaseIterator (&iter);
900
913
return nil ;
901
914
}
915
+ // Check whether we need to use thumbnail
902
916
CGSize scaledSize = SDCalculateThumbnailSize (CGSizeMake (_canvasWidth, _canvasHeight), _preserveAspectRatio, _thumbnailSize);
903
917
CGImageRef imageRef = [self sd_createWebpImageWithData: iter.fragment colorSpace: _colorSpace scaledSize: scaledSize];
904
918
if (!imageRef) {
@@ -915,9 +929,6 @@ - (UIImage *)safeStaticImageFrame {
915
929
}
916
930
917
931
- (UIImage *)safeAnimatedImageFrameAtIndex : (NSUInteger )index {
918
- if (!_colorSpace) {
919
- _colorSpace = [self sd_createColorSpaceWithDemuxer: _demux];
920
- }
921
932
if (!_canvas) {
922
933
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host ;
923
934
bitmapInfo |= _hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst ;
@@ -927,6 +938,9 @@ - (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index {
927
938
}
928
939
_canvas = canvas;
929
940
}
941
+ if (!_colorSpace) {
942
+ _colorSpace = [self sd_createColorSpaceWithDemuxer: _demux];
943
+ }
930
944
931
945
SDWebPCoderFrame *frame = _frames[index];
932
946
UIImage *image;
@@ -946,7 +960,7 @@ - (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index {
946
960
} else {
947
961
// Else, this can happen when one image set to different imageViews or one loop end. So we should clear the canvas. Then draw until the canvas is ready.
948
962
if (_currentBlendIndex != NSNotFound ) {
949
- CGContextClearRect (_canvas, CGRectMake (0 , 0 , CGBitmapContextGetWidth (_canvas), CGBitmapContextGetHeight (_canvas) ));
963
+ CGContextClearRect (_canvas, CGRectMake (0 , 0 , _canvasWidth, _canvasHeight ));
950
964
}
951
965
952
966
// Then, loop from the blend from index, draw each of previous frames on the canvas.
@@ -975,7 +989,9 @@ - (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index {
975
989
_currentBlendIndex = index;
976
990
977
991
// Now the canvas is ready, which respects of dispose method behavior. Just do normal decoding and produce image.
978
- CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas: _canvas iterator: iter colorSpace: _colorSpace];
992
+ // Check whether we need to use thumbnail
993
+ CGSize scaledSize = SDCalculateThumbnailSize (CGSizeMake (_canvasWidth, _canvasHeight), _preserveAspectRatio, _thumbnailSize);
994
+ CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas: _canvas iterator: iter colorSpace: _colorSpace scaledSize: scaledSize];
979
995
if (!imageRef) {
980
996
return nil ;
981
997
}
0 commit comments