add animated webP support

This commit is contained in:
jiangliancheng 2016-01-15 23:47:25 +08:00
parent 6a623cd58f
commit c2173c1e75
2 changed files with 107 additions and 2 deletions

View File

@ -173,6 +173,7 @@
5D5B9145188EE8DD006D06BD /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */; };
5D5B9146188EE8DD006D06BD /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */; };
5D5B9147188EE8DD006D06BD /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */; };
750C1B8E1C494AB000DC00B9 /* demux.c in Sources */ = {isa = PBXBuildFile; fileRef = 750C1B8A1C49491900DC00B9 /* demux.c */; };
A18A6CC7172DC28500419892 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; };
A18A6CC8172DC28500419892 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; };
A18A6CC9172DC28500419892 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = A18A6CC6172DC28500419892 /* UIImage+GIF.m */; };
@ -316,6 +317,7 @@
53FB894814D35E9E0020B787 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
5D5B9140188EE8DD006D06BD /* NSData+ImageContentType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+ImageContentType.h"; sourceTree = "<group>"; };
5D5B9141188EE8DD006D06BD /* NSData+ImageContentType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+ImageContentType.m"; sourceTree = "<group>"; };
750C1B8A1C49491900DC00B9 /* demux.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = demux.c; sourceTree = "<group>"; };
A18A6CC5172DC28500419892 /* UIImage+GIF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+GIF.h"; sourceTree = "<group>"; };
A18A6CC6172DC28500419892 /* UIImage+GIF.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+GIF.m"; sourceTree = "<group>"; };
AB615301192DA24600A2D8E9 /* UIView+WebCacheOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+WebCacheOperation.h"; sourceTree = "<group>"; };
@ -571,6 +573,14 @@
name = Utils;
sourceTree = "<group>";
};
750C1B891C49491900DC00B9 /* demux */ = {
isa = PBXGroup;
children = (
750C1B8A1C49491900DC00B9 /* demux.c */,
);
path = demux;
sourceTree = "<group>";
};
DA577C121998E60B007367ED /* libwebp */ = {
isa = PBXGroup;
children = (
@ -583,6 +593,7 @@
DA577C4F1998E60B007367ED /* src */ = {
isa = PBXGroup;
children = (
750C1B891C49491900DC00B9 /* demux */,
DA577D5A1998E6B2007367ED /* dec */,
DA577C651998E60B007367ED /* dsp */,
DA577CA71998E60B007367ED /* utils */,
@ -1134,6 +1145,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
750C1B8E1C494AB000DC00B9 /* demux.c in Sources */,
DA577D101998E60B007367ED /* upsampling_neon.c in Sources */,
DA577D151998E60B007367ED /* yuv_sse2.c in Sources */,
DA577D111998E60B007367ED /* upsampling_sse2.c in Sources */,

View File

@ -11,8 +11,12 @@
#if !COCOAPODS
#import "webp/decode.h"
#import "webp/mux_types.h"
#import "webp/demux.h"
#else
#import "libwebp/webp/decode.h"
#import "libwebp/webpc/mux_types.h"
#import "libwebp/webp/demux.h"
#endif
// Callback for CGDataProviderRelease
@ -24,12 +28,101 @@ static void FreeImageData(void *info, const void *data, size_t size)
@implementation UIImage (WebP)
+ (UIImage *)sd_imageWithWebPData:(NSData *)data {
if (!data) {
return nil;
}
WebPData webpData;
WebPDataInit(&webpData);
webpData.bytes = data.bytes;
webpData.size = data.length;
WebPDemuxer *demuxer = WebPDemux(&webpData);
if (!demuxer) {
return nil;
}
uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS);
if (!(flags & ANIMATION_FLAG)) {
// for static single webp image
UIImage *staticImage = [self sd_rawWepImageWithData:webpData];
WebPDemuxDelete(demuxer);
return staticImage;
}
WebPIterator iter;
if (!WebPDemuxGetFrame(demuxer, 1, &iter)) {
WebPDemuxReleaseIterator(&iter);
WebPDemuxDelete(demuxer);
return nil;
}
NSMutableArray *images = [NSMutableArray array];
NSTimeInterval duration = 0;
do {
UIImage *image;
if (iter.blend_method == WEBP_MUX_BLEND) {
image = [self sd_blendWebpImageWithOriginImage:[images lastObject] iterator:iter];
} else {
image = [self sd_rawWepImageWithData:iter.fragment];
}
if (!image) {
continue;
}
[images addObject:image];
duration += iter.duration / 1000.0f;
} while (WebPDemuxNextFrame(&iter));
WebPDemuxReleaseIterator(&iter);
WebPDemuxDelete(demuxer);
UIImage *animateImage = [UIImage animatedImageWithImages:images duration:duration];
return animateImage;
}
+ (UIImage *)sd_blendWebpImageWithOriginImage:(UIImage *)originImage iterator:(WebPIterator)iter
{
if (!originImage) {
return nil;
}
CGSize size = originImage.size;
CGFloat tmpX = iter.x_offset;
CGFloat tmpY = size.height - iter.height - iter.y_offset;
CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height);
UIImage *image = [self sd_rawWepImageWithData:iter.fragment];
if (!image) {
return nil;
}
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
uint32_t bitmapInfo = iter.has_alpha ? kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast : 0;
CGContextRef blendCanvas = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, colorSpaceRef, bitmapInfo);
CGContextDrawImage(blendCanvas, CGRectMake(0, 0, size.width, size.height), originImage.CGImage);
CGContextDrawImage(blendCanvas, imageRect, image.CGImage);
CGImageRef newImageRef = CGBitmapContextCreateImage(blendCanvas);
image = [UIImage imageWithCGImage:newImageRef];
CGImageRelease(newImageRef);
CGContextRelease(blendCanvas);
CGColorSpaceRelease(colorSpaceRef);
return image;
}
+ (UIImage *)sd_rawWepImageWithData:(WebPData)webpData
{
WebPDecoderConfig config;
if (!WebPInitDecoderConfig(&config)) {
return nil;
}
if (WebPGetFeatures(data.bytes, data.length, &config.input) != VP8_STATUS_OK) {
if (WebPGetFeatures(webpData.bytes, webpData.size, &config.input) != VP8_STATUS_OK) {
return nil;
}
@ -37,7 +130,7 @@ static void FreeImageData(void *info, const void *data, size_t size)
config.options.use_threads = 1;
// Decode the WebP image data into a RGBA value array.
if (WebPDecode(data.bytes, data.length, &config) != VP8_STATUS_OK) {
if (WebPDecode(webpData.bytes, webpData.size, &config) != VP8_STATUS_OK) {
return nil;
}