Skip to content

Commit 72d1968

Browse files
committed
Fix the animated canvas again, this time should work
1 parent e3ba3ab commit 72d1968

File tree

1 file changed

+42
-28
lines changed

1 file changed

+42
-28
lines changed

SDWebImageWebPCoder/Classes/SDImageWebPCoder.m

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ @implementation SDImageWebPCoder {
9696
BOOL _hasAnimation;
9797
BOOL _hasAlpha;
9898
BOOL _finished;
99+
CGFloat _canvasWidth; // Full Size without thumbnail scale
100+
CGFloat _canvasHeight; // Full Size without thumbnail scale
99101
dispatch_semaphore_t _lock;
100102
NSUInteger _currentBlendIndex;
101103
BOOL _preserveAspectRatio;
@@ -207,7 +209,15 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
207209
return firstFrameImage;
208210
}
209211

210-
CGContextRef canvas = [self sd_createCanvasWithDemuxer:demuxer colorSpace:colorSpace preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize];
212+
int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH);
213+
int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT);
214+
BOOL hasAlpha = flags & ALPHA_FLAG;
215+
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
216+
bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
217+
218+
CGSize canvasFullSize = CGSizeMake(canvasWidth, canvasHeight);
219+
CGSize canvasSize = SDCalculateThumbnailSize(canvasFullSize, preserveAspectRatio, thumbnailSize);
220+
CGContextRef canvas = CGBitmapContextCreate(NULL, canvasSize.width, canvasSize.height, 8, 0, [SDImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo);
211221
if (!canvas) {
212222
WebPDemuxDelete(demuxer);
213223
CGColorSpaceRelease(colorSpace);
@@ -219,7 +229,7 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
219229

220230
do {
221231
@autoreleasepool {
222-
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:canvas iterator:iter colorSpace:colorSpace preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize];
232+
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:canvas iterator:iter colorSpace:colorSpace preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize canvasFullSize:canvasFullSize];
223233
if (!imageRef) {
224234
continue;
225235
}
@@ -330,7 +340,7 @@ - (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options {
330340
return nil;
331341
}
332342

333-
CGContextRef canvas = [self sd_createCanvasWithDemuxer:_demux colorSpace:colorSpaceRef preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize];
343+
CGContextRef canvas = CGBitmapContextCreate(NULL, width, height, 8, 0, [SDImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo);
334344
if (!canvas) {
335345
CGImageRelease(imageRef);
336346
return nil;
@@ -367,11 +377,17 @@ - (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options {
367377
return image;
368378
}
369379

370-
- (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize {
380+
- (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize canvasFullSize:(CGSize)canvasFullSize {
381+
size_t canvasWidth = CGBitmapContextGetWidth(canvas);
371382
size_t canvasHeight = CGBitmapContextGetHeight(canvas);
372-
CGFloat tmpX = iter.x_offset;
373-
CGFloat tmpY = canvasHeight - iter.height - iter.y_offset;
374-
CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height);
383+
CGFloat xScale = canvasWidth / canvasFullSize.width;
384+
CGFloat yScale = canvasHeight / canvasFullSize.height;
385+
386+
CGFloat tmpX = iter.x_offset * xScale;
387+
CGFloat tmpY = (canvasFullSize.height - iter.height - iter.y_offset) * yScale;
388+
CGFloat tmpWidth = iter.width * xScale;
389+
CGFloat tmpHeight = iter.height * yScale;
390+
CGRect imageRect = CGRectMake(tmpX, tmpY, tmpWidth, tmpHeight);
375391

376392
if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
377393
CGContextClearRect(canvas, imageRect);
@@ -390,16 +406,22 @@ - (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)
390406
}
391407
}
392408

393-
- (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize CF_RETURNS_RETAINED {
409+
- (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize canvasFullSize:(CGSize)canvasFullSize CF_RETURNS_RETAINED {
394410
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpaceRef preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize];
395411
if (!imageRef) {
396412
return nil;
397413
}
398414

415+
size_t canvasWidth = CGBitmapContextGetWidth(canvas);
399416
size_t canvasHeight = CGBitmapContextGetHeight(canvas);
400-
CGFloat tmpX = iter.x_offset;
401-
CGFloat tmpY = canvasHeight - iter.height - iter.y_offset;
402-
CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height);
417+
CGFloat xScale = canvasWidth / canvasFullSize.width;
418+
CGFloat yScale = canvasHeight / canvasFullSize.height;
419+
420+
CGFloat tmpX = iter.x_offset * xScale;
421+
CGFloat tmpY = (canvasFullSize.height - iter.height - iter.y_offset) * yScale;
422+
CGFloat tmpWidth = iter.width * xScale;
423+
CGFloat tmpHeight = iter.height * yScale;
424+
CGRect imageRect = CGRectMake(tmpX, tmpY, tmpWidth, tmpHeight);
403425
BOOL shouldBlend = iter.blend_method == WEBP_MUX_BLEND;
404426

405427
// If not blend, cover the target image rect. (firstly clear then draw)
@@ -520,20 +542,6 @@ - (nonnull CGColorSpaceRef)sd_createColorSpaceWithDemuxer:(nonnull WebPDemuxer *
520542
return colorSpaceRef;
521543
}
522544

523-
- (CGContextRef)sd_createCanvasWithDemuxer:(nonnull WebPDemuxer *)demuxer colorSpace:(nonnull CGColorSpaceRef)colorSpace preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize CF_RETURNS_RETAINED {
524-
uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS);
525-
int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH);
526-
int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT);
527-
BOOL hasAlpha = flags & ALPHA_FLAG;
528-
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
529-
bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
530-
531-
CGSize canvasSize = SDCalculateThumbnailSize(CGSizeMake(canvasWidth, canvasHeight), preserveAspectRatio, thumbnailSize);
532-
CGContextRef canvas = CGBitmapContextCreate(NULL, canvasSize.width, canvasSize.height, 8, 0, colorSpace, bitmapInfo);
533-
534-
return canvas;
535-
}
536-
537545
#pragma mark - Encode
538546
- (BOOL)canEncodeToFormat:(SDImageFormat)format {
539547
return (format == SDImageFormatWebP);
@@ -810,6 +818,8 @@ - (BOOL)scanAndCheckFramesValidWithDemuxer:(WebPDemuxer *)demuxer {
810818

811819
_hasAnimation = hasAnimation;
812820
_hasAlpha = hasAlpha;
821+
_canvasWidth = canvasWidth;
822+
_canvasHeight = canvasHeight;
813823
_frameCount = frameCount;
814824
_loopCount = loopCount;
815825

@@ -925,8 +935,12 @@ - (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index {
925935
if (!_colorSpace) {
926936
_colorSpace = [self sd_createColorSpaceWithDemuxer:_demux];
927937
}
938+
CGSize canvasFullSize = CGSizeMake(_canvasWidth, _canvasHeight);
928939
if (!_canvas) {
929-
CGContextRef canvas = [self sd_createCanvasWithDemuxer:_demux colorSpace:_colorSpace preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize];
940+
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
941+
bitmapInfo |= _hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
942+
CGSize canvasSize = SDCalculateThumbnailSize(canvasFullSize, _preserveAspectRatio, _thumbnailSize);
943+
CGContextRef canvas = CGBitmapContextCreate(NULL, canvasSize.width, canvasSize.height, 8, 0, [SDImageCoderHelper colorSpaceGetDeviceRGB], bitmapInfo);
930944
if (!canvas) {
931945
return nil;
932946
}
@@ -967,7 +981,7 @@ - (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index {
967981
if (endIndex > startIndex) {
968982
do {
969983
@autoreleasepool {
970-
[self sd_blendWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize];
984+
[self sd_blendWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize canvasFullSize:canvasFullSize];
971985
}
972986
} while ((size_t)iter.frame_num < endIndex && WebPDemuxNextFrame(&iter));
973987
}
@@ -980,7 +994,7 @@ - (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index {
980994
_currentBlendIndex = index;
981995

982996
// Now the canvas is ready, which respects of dispose method behavior. Just do normal decoding and produce image.
983-
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize];
997+
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize canvasFullSize:canvasFullSize];
984998
if (!imageRef) {
985999
return nil;
9861000
}

0 commit comments

Comments
 (0)