@@ -86,6 +86,7 @@ @implementation SDWebPCoderFrame
8686@implementation SDImageWebPCoder {
8787 WebPIDecoder *_idec;
8888 WebPDemuxer *_demux;
89+ WebPData *_webpdata; // Copied for progressive animation demuxer
8990 NSData *_imageData;
9091 CGFloat _scale;
9192 NSUInteger _loopCount;
@@ -113,6 +114,10 @@ - (void)dealloc {
113114 WebPDemuxDelete (_demux);
114115 _demux = NULL ;
115116 }
117+ if (_webpdata) {
118+ WebPDataClear (_webpdata);
119+ _webpdata = NULL ;
120+ }
116121 if (_canvas) {
117122 CGContextRelease (_canvas);
118123 _canvas = NULL ;
@@ -290,6 +295,8 @@ - (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)optio
290295 preserveAspectRatio = preserveAspectRatioValue.boolValue ;
291296 }
292297 _preserveAspectRatio = preserveAspectRatio;
298+ _currentBlendIndex = NSNotFound ;
299+ _lock = dispatch_semaphore_create (1 );
293300 }
294301 return self;
295302}
@@ -300,16 +307,54 @@ - (void)updateIncrementalData:(NSData *)data finished:(BOOL)finished {
300307 }
301308 _imageData = data;
302309 _finished = finished;
303- VP8StatusCode status = WebPIUpdate (_idec, data.bytes , data.length );
304- if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) {
305- return ;
310+ if (!_demux) {
311+ VP8StatusCode status = WebPIUpdate (_idec, data.bytes , data.length );
312+ if (status == VP8_STATUS_OK || status == VP8_STATUS_SUSPENDED) {
313+ return ;
314+ }
315+ // This case may be Animated WebP progressive decode
316+ if (status == VP8_STATUS_UNSUPPORTED_FEATURE) {
317+ WebPDemuxState state;
318+ WebPData tmpData;
319+ WebPDataInit (&tmpData);
320+ tmpData.bytes = data.bytes ;
321+ tmpData.size = data.length ;
322+ // Copy to avoid the NSData dealloc and VP8 internal retain the pointer
323+ _webpdata = malloc (sizeof (WebPData));
324+ WebPDataCopy (&tmpData, _webpdata);
325+ _demux = WebPDemuxPartial (_webpdata, &state);
326+ }
327+ } else {
328+ // libwebp current have no API to update demuxer, so we always delete and recreate demuxer
329+ WebPDemuxDelete (_demux);
330+ _demux = NULL ;
331+ WebPDemuxState state;
332+ WebPData tmpData;
333+ WebPDataInit (&tmpData);
334+ tmpData.bytes = data.bytes ;
335+ tmpData.size = data.length ;
336+ // Copy to avoid the NSData dealloc and VP8 internal retain the pointer
337+ WebPDataClear (_webpdata);
338+ WebPDataCopy (&tmpData, _webpdata);
339+ _demux = WebPDemuxPartial (_webpdata, &state);
340+ }
341+
342+ if (_demux) {
343+ [self scanAndCheckFramesValidWithDemuxer: _demux];
306344 }
307- // libwebp current does not support progressive decoding for animated image, so no need to scan and update the frame information
308345}
309346
310347- (UIImage *)incrementalDecodedImageWithOptions : (SDImageCoderOptions *)options {
311348 UIImage *image;
312349
350+ // For Animated WebP Images, progressive decoding only return the first frame.
351+ // If you want progressive animation, use the SDAniamtedCoder protocol method instead.
352+ if (_demux) {
353+ SD_LOCK (_lock);
354+ image = [self safeStaticImageFrame ];
355+ SD_UNLOCK (_lock);
356+ }
357+ // For Static WebP images
313358 int width = 0 ;
314359 int height = 0 ;
315360 int last_y = 0 ;
@@ -832,6 +877,10 @@ - (BOOL)scanAndCheckFramesValidWithDemuxer:(WebPDemuxer *)demuxer {
832877
833878 // We should loop all the frames and scan each frames' blendFromIndex for later decoding, this can also ensure all frames is valid
834879 do {
880+ if (!iter.complete ) {
881+ // Skip partial frame
882+ continue ;
883+ }
835884 SDWebPCoderFrame *frame = [[SDWebPCoderFrame alloc ] init ];
836885 frame.index = iterIndex;
837886 frame.duration = [self sd_frameDurationWithIterator: iter];
0 commit comments