Skip to content

Commit 3060843

Browse files
authored
Merge pull request #7 from SDWebImage/bugfix_webp_animtion_render_logic
Fix the Animated WebP render logic used by SDAnimatedImageView.
2 parents 3f256df + 02595bc commit 3060843

File tree

1 file changed

+28
-29
lines changed

1 file changed

+28
-29
lines changed

SDWebImageWebPCoder/Classes/SDImageWebPCoder.m

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -795,58 +795,57 @@ - (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index {
795795
SDWebPCoderFrame *frame = _frames[index];
796796
UIImage *image;
797797
WebPIterator iter;
798+
799+
// Because Animated WebP supports dispose method, which means frames can based on previous canvas context. However, if we clear canvas and loop from the 0 index until the request index, it's harm for performance.
800+
// But when one frame's dispose method is `WEBP_MUX_DISPOSE_BACKGROUND`, the canvas is cleared after the frame decoded. And subsequent frames are not effected by that frame.
801+
// So, we calculate each frame's `blendFromIndex`. Then directly draw canvas from that index, instead of always from 0 index.
802+
798803
if (_currentBlendIndex + 1 == index) {
799-
// If current blend index is equal to request index, normal serial process
804+
// If the request index is subsequence of current blend index, it does not matter what dispose method is. The canvas is always ready.
800805
_currentBlendIndex = index;
806+
NSUInteger startIndex = index;
801807
// libwebp's index start with 1
802-
if (!WebPDemuxGetFrame(_demux, (int)(index + 1), &iter)) {
808+
if (!WebPDemuxGetFrame(_demux, (int)(startIndex + 1), &iter)) {
803809
WebPDemuxReleaseIterator(&iter);
804810
return nil;
805811
}
806-
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace];
807-
if (!imageRef) {
808-
return nil;
809-
}
810-
#if SD_UIKIT || SD_WATCH
811-
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp];
812-
#else
813-
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:kCGImagePropertyOrientationUp];
814-
#endif
815-
CGImageRelease(imageRef);
816812
} else {
817-
// Else, this can happen when one image set to different imageViews or one loop end. So we should clear the shared cavans.
813+
// 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.
818814
if (_currentBlendIndex != NSNotFound) {
819815
CGContextClearRect(_canvas, CGRectMake(0, 0, _canvasWidth, _canvasHeight));
820816
}
821817
_currentBlendIndex = index;
822818

823819
// Then, loop from the blend from index, draw each of previous frames on the canvas.
824-
// We use do while loop to call `WebPDemuxNextFrame`(fast), only (startIndex == endIndex) need to create image instance
820+
// We use do while loop to call `WebPDemuxNextFrame`(fast), until the endIndex meet.
825821
size_t startIndex = frame.blendFromIndex;
826822
size_t endIndex = frame.index;
823+
// libwebp's index start with 1
827824
if (!WebPDemuxGetFrame(_demux, (int)(startIndex + 1), &iter)) {
828825
WebPDemuxReleaseIterator(&iter);
829826
return nil;
830827
}
831-
do {
832-
@autoreleasepool {
833-
if ((size_t)iter.frame_num == endIndex) {
828+
// Draw from range: [startIndex, endIndex)
829+
if (endIndex > startIndex) {
830+
do {
831+
@autoreleasepool {
834832
[self sd_blendWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace];
835-
} else {
836-
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace];
837-
if (!imageRef) {
838-
return nil;
839-
}
833+
}
834+
} while ((size_t)iter.frame_num < (endIndex + 1) && WebPDemuxNextFrame(&iter));
835+
}
836+
}
837+
838+
// Now the canvas is ready, which respects of dispose method behavior. Just do normal decoding and produce image.
839+
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace];
840+
if (!imageRef) {
841+
return nil;
842+
}
840843
#if SD_UIKIT || SD_WATCH
841-
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp];
844+
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp];
842845
#else
843-
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:kCGImagePropertyOrientationUp];
846+
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:kCGImagePropertyOrientationUp];
844847
#endif
845-
CGImageRelease(imageRef);
846-
}
847-
}
848-
} while ((size_t)iter.frame_num < (endIndex + 1) && WebPDemuxNextFrame(&iter));
849-
}
848+
CGImageRelease(imageRef);
850849

851850
WebPDemuxReleaseIterator(&iter);
852851
return image;

0 commit comments

Comments
 (0)