@@ -86,6 +86,7 @@ @implementation SDWebPCoderFrame
86
86
@implementation SDImageWebPCoder {
87
87
WebPIDecoder *_idec;
88
88
WebPDemuxer *_demux;
89
+ WebPData *_webpdata; // Copied for progressive animation demuxer
89
90
NSData *_imageData;
90
91
CGFloat _scale;
91
92
NSUInteger _loopCount;
@@ -113,6 +114,10 @@ - (void)dealloc {
113
114
WebPDemuxDelete (_demux);
114
115
_demux = NULL ;
115
116
}
117
+ if (_webpdata) {
118
+ WebPDataClear (_webpdata);
119
+ _webpdata = NULL ;
120
+ }
116
121
if (_canvas) {
117
122
CGContextRelease (_canvas);
118
123
_canvas = NULL ;
@@ -290,6 +295,8 @@ - (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)optio
290
295
preserveAspectRatio = preserveAspectRatioValue.boolValue ;
291
296
}
292
297
_preserveAspectRatio = preserveAspectRatio;
298
+ _currentBlendIndex = NSNotFound ;
299
+ _lock = dispatch_semaphore_create (1 );
293
300
}
294
301
return self;
295
302
}
@@ -300,16 +307,54 @@ - (void)updateIncrementalData:(NSData *)data finished:(BOOL)finished {
300
307
}
301
308
_imageData = data;
302
309
_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];
306
344
}
307
- // libwebp current does not support progressive decoding for animated image, so no need to scan and update the frame information
308
345
}
309
346
310
347
- (UIImage *)incrementalDecodedImageWithOptions : (SDImageCoderOptions *)options {
311
348
UIImage *image;
312
349
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
313
358
int width = 0 ;
314
359
int height = 0 ;
315
360
int last_y = 0 ;
@@ -832,6 +877,10 @@ - (BOOL)scanAndCheckFramesValidWithDemuxer:(WebPDemuxer *)demuxer {
832
877
833
878
// We should loop all the frames and scan each frames' blendFromIndex for later decoding, this can also ensure all frames is valid
834
879
do {
880
+ if (!iter.complete ) {
881
+ // Skip partial frame
882
+ continue ;
883
+ }
835
884
SDWebPCoderFrame *frame = [[SDWebPCoderFrame alloc ] init ];
836
885
frame.index = iterIndex;
837
886
frame.duration = [self sd_frameDurationWithIterator: iter];
0 commit comments