Merge pull request #33 from SDWebImage/feature_progressive_animated_webp

Feature - Supports Progressive Animated WebP (Important)
This commit is contained in:
DreamPiggy 2020-01-18 19:11:07 +08:00 committed by GitHub
commit e4af4b805e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 5 deletions

View File

@ -22,6 +22,8 @@
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[SDImageCache.sharedImageCache clearDiskOnCompletion:nil];
[[SDImageCodersManager sharedManager] addCoder:[SDImageWebPCoder sharedCoder]];
self.imageView1 = [UIImageView new];
@ -46,7 +48,7 @@
}
});
}];
[self.imageView2 sd_setImageWithURL:animatedWebPURL completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
[self.imageView2 sd_setImageWithURL:animatedWebPURL placeholderImage:nil options:SDWebImageProgressiveLoad completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
if (image) {
NSLog(@"%@", @"Animated WebP load success");
}

View File

@ -86,6 +86,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
@implementation SDImageWebPCoder {
WebPIDecoder *_idec;
WebPDemuxer *_demux;
WebPData *_webpdata; // Copied for progressive animation demuxer
NSData *_imageData;
CGFloat _scale;
NSUInteger _loopCount;
@ -113,6 +114,10 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
WebPDemuxDelete(_demux);
_demux = NULL;
}
if (_webpdata) {
WebPDataClear(_webpdata);
_webpdata = NULL;
}
if (_canvas) {
CGContextRelease(_canvas);
_canvas = NULL;
@ -290,6 +295,8 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
preserveAspectRatio = preserveAspectRatioValue.boolValue;
}
_preserveAspectRatio = preserveAspectRatio;
_currentBlendIndex = NSNotFound;
_lock = dispatch_semaphore_create(1);
}
return self;
}
@ -300,16 +307,54 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
}
_imageData = data;
_finished = finished;
VP8StatusCode status = WebPIUpdate(_idec, data.bytes, data.length);
if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) {
return;
if (!_demux) {
VP8StatusCode status = WebPIUpdate(_idec, data.bytes, data.length);
if (status == VP8_STATUS_OK || status == VP8_STATUS_SUSPENDED) {
return;
}
// This case may be Animated WebP progressive decode
if (status == VP8_STATUS_UNSUPPORTED_FEATURE) {
WebPDemuxState state;
WebPData tmpData;
WebPDataInit(&tmpData);
tmpData.bytes = data.bytes;
tmpData.size = data.length;
// Copy to avoid the NSData dealloc and VP8 internal retain the pointer
_webpdata = malloc(sizeof(WebPData));
WebPDataCopy(&tmpData, _webpdata);
_demux = WebPDemuxPartial(_webpdata, &state);
}
} else {
// libwebp current have no API to update demuxer, so we always delete and recreate demuxer
WebPDemuxDelete(_demux);
_demux = NULL;
WebPDemuxState state;
WebPData tmpData;
WebPDataInit(&tmpData);
tmpData.bytes = data.bytes;
tmpData.size = data.length;
// Copy to avoid the NSData dealloc and VP8 internal retain the pointer
WebPDataClear(_webpdata);
WebPDataCopy(&tmpData, _webpdata);
_demux = WebPDemuxPartial(_webpdata, &state);
}
if (_demux) {
[self scanAndCheckFramesValidWithDemuxer:_demux];
}
// libwebp current does not support progressive decoding for animated image, so no need to scan and update the frame information
}
- (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options {
UIImage *image;
// For Animated WebP Images, progressive decoding only return the first frame.
// If you want progressive animation, use the SDAniamtedCoder protocol method instead.
if (_demux) {
SD_LOCK(_lock);
image = [self safeStaticImageFrame];
SD_UNLOCK(_lock);
}
// For Static WebP images
int width = 0;
int height = 0;
int last_y = 0;
@ -832,6 +877,10 @@ static void FreeImageData(void *info, const void *data, size_t size) {
// We should loop all the frames and scan each frames' blendFromIndex for later decoding, this can also ensure all frames is valid
do {
if (!iter.complete) {
// Skip partial frame
continue;
}
SDWebPCoderFrame *frame = [[SDWebPCoderFrame alloc] init];
frame.index = iterIndex;
frame.duration = [self sd_frameDurationWithIterator:iter];