WebPCoder now supports the thumbnail decoding
This commit is contained in:
parent
a936bdb6d1
commit
9db3358eb0
2
Cartfile
2
Cartfile
|
@ -1,2 +1,2 @@
|
||||||
github "SDWebImage/SDWebImage" ~> 5.0
|
github "SDWebImage/SDWebImage" ~> 5.5
|
||||||
github "SDWebImage/libwebp-Xcode" ~> 1.0
|
github "SDWebImage/libwebp-Xcode" ~> 1.0
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
github "SDWebImage/SDWebImage" "5.0.0"
|
github "SDWebImage/SDWebImage" "5.5.0"
|
||||||
github "SDWebImage/libwebp-Xcode" "1.0.0"
|
github "SDWebImage/libwebp-Xcode" "1.1.0"
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
NSURL *staticWebPURL = [NSURL URLWithString:@"https://www.gstatic.com/webp/gallery/2.webp"];
|
NSURL *staticWebPURL = [NSURL URLWithString:@"https://www.gstatic.com/webp/gallery/2.webp"];
|
||||||
NSURL *animatedWebPURL = [NSURL URLWithString:@"http://littlesvr.ca/apng/images/world-cup-2014-42.webp"];
|
NSURL *animatedWebPURL = [NSURL URLWithString:@"http://littlesvr.ca/apng/images/world-cup-2014-42.webp"];
|
||||||
|
|
||||||
[self.imageView1 sd_setImageWithURL:staticWebPURL completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
[self.imageView1 sd_setImageWithURL:staticWebPURL placeholderImage:nil options:0 context:@{SDWebImageContextImageThumbnailPixelSize : @(CGSizeMake(300, 300))} progress:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||||
if (image) {
|
if (image) {
|
||||||
NSLog(@"%@", @"Static WebP load success");
|
NSLog(@"%@", @"Static WebP load success");
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ This is a SDWebImage coder plugin to support WebP image.
|
||||||
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SD_WEBP=1 WEBP_USE_INTRINSICS=1',
|
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SD_WEBP=1 WEBP_USE_INTRINSICS=1',
|
||||||
'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src'
|
'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src'
|
||||||
}
|
}
|
||||||
s.dependency 'SDWebImage/Core', '~> 5.0'
|
s.dependency 'SDWebImage/Core', '~> 5.5'
|
||||||
s.dependency 'libwebp', '~> 1.0'
|
s.dependency 'libwebp', '~> 1.0'
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -68,6 +68,8 @@
|
||||||
CGFloat _canvasHeight;
|
CGFloat _canvasHeight;
|
||||||
dispatch_semaphore_t _lock;
|
dispatch_semaphore_t _lock;
|
||||||
NSUInteger _currentBlendIndex;
|
NSUInteger _currentBlendIndex;
|
||||||
|
BOOL _preserveAspectRatio;
|
||||||
|
CGSize _thumbnailSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
|
@ -133,6 +135,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CGSize thumbnailSize = CGSizeZero;
|
||||||
|
NSValue *thumbnailSizeValue = options[SDImageCoderDecodeThumbnailPixelSize];
|
||||||
|
if (thumbnailSizeValue != nil) {
|
||||||
|
#if SD_MAC
|
||||||
|
thumbnailSize = thumbnailSizeValue.sizeValue;
|
||||||
|
#else
|
||||||
|
thumbnailSize = thumbnailSizeValue.CGSizeValue;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL preserveAspectRatio = YES;
|
||||||
|
NSNumber *preserveAspectRatioValue = options[SDImageCoderDecodePreserveAspectRatio];
|
||||||
|
if (preserveAspectRatioValue != nil) {
|
||||||
|
preserveAspectRatio = preserveAspectRatioValue.boolValue;
|
||||||
|
}
|
||||||
|
|
||||||
// for animated webp image
|
// for animated webp image
|
||||||
WebPIterator iter;
|
WebPIterator iter;
|
||||||
// libwebp's index start with 1
|
// libwebp's index start with 1
|
||||||
|
@ -145,7 +163,7 @@
|
||||||
|
|
||||||
if (!hasAnimation || decodeFirstFrame) {
|
if (!hasAnimation || decodeFirstFrame) {
|
||||||
// first frame for animated webp image
|
// first frame for animated webp image
|
||||||
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpace];
|
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpace preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize];
|
||||||
CGColorSpaceRelease(colorSpace);
|
CGColorSpaceRelease(colorSpace);
|
||||||
#if SD_UIKIT || SD_WATCH
|
#if SD_UIKIT || SD_WATCH
|
||||||
UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
|
UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
|
||||||
|
@ -176,7 +194,7 @@
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:canvas iterator:iter colorSpace:colorSpace];
|
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:canvas iterator:iter colorSpace:colorSpace preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize];
|
||||||
if (!imageRef) {
|
if (!imageRef) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -221,6 +239,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_scale = scale;
|
_scale = scale;
|
||||||
|
CGSize thumbnailSize = CGSizeZero;
|
||||||
|
NSValue *thumbnailSizeValue = options[SDImageCoderDecodeThumbnailPixelSize];
|
||||||
|
if (thumbnailSizeValue != nil) {
|
||||||
|
#if SD_MAC
|
||||||
|
thumbnailSize = thumbnailSizeValue.sizeValue;
|
||||||
|
#else
|
||||||
|
thumbnailSize = thumbnailSizeValue.CGSizeValue;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
_thumbnailSize = thumbnailSize;
|
||||||
|
BOOL preserveAspectRatio = YES;
|
||||||
|
NSNumber *preserveAspectRatioValue = options[SDImageCoderDecodePreserveAspectRatio];
|
||||||
|
if (preserveAspectRatioValue != nil) {
|
||||||
|
preserveAspectRatio = preserveAspectRatioValue.boolValue;
|
||||||
|
}
|
||||||
|
_preserveAspectRatio = preserveAspectRatio;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -308,7 +342,7 @@
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef {
|
- (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize {
|
||||||
size_t canvasHeight = CGBitmapContextGetHeight(canvas);
|
size_t canvasHeight = CGBitmapContextGetHeight(canvas);
|
||||||
CGFloat tmpX = iter.x_offset;
|
CGFloat tmpX = iter.x_offset;
|
||||||
CGFloat tmpY = canvasHeight - iter.height - iter.y_offset;
|
CGFloat tmpY = canvasHeight - iter.height - iter.y_offset;
|
||||||
|
@ -317,7 +351,7 @@
|
||||||
if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
|
if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
|
||||||
CGContextClearRect(canvas, imageRect);
|
CGContextClearRect(canvas, imageRect);
|
||||||
} else {
|
} else {
|
||||||
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpaceRef];
|
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpaceRef preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize];
|
||||||
if (!imageRef) {
|
if (!imageRef) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -331,8 +365,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef CF_RETURNS_RETAINED {
|
- (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize CF_RETURNS_RETAINED {
|
||||||
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpaceRef];
|
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpaceRef preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize];
|
||||||
if (!imageRef) {
|
if (!imageRef) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -359,7 +393,7 @@
|
||||||
return newImageRef;
|
return newImageRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (nullable CGImageRef)sd_createWebpImageWithData:(WebPData)webpData colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef CF_RETURNS_RETAINED {
|
- (nullable CGImageRef)sd_createWebpImageWithData:(WebPData)webpData colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize CF_RETURNS_RETAINED {
|
||||||
WebPDecoderConfig config;
|
WebPDecoderConfig config;
|
||||||
if (!WebPInitDecoderConfig(&config)) {
|
if (!WebPInitDecoderConfig(&config)) {
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -377,13 +411,34 @@
|
||||||
config.options.use_threads = 1;
|
config.options.use_threads = 1;
|
||||||
config.output.colorspace = MODE_bgrA;
|
config.output.colorspace = MODE_bgrA;
|
||||||
|
|
||||||
|
int width = config.input.width;
|
||||||
|
int height = config.input.height;
|
||||||
|
if (width == 0 || height == 0 || thumbnailSize.width == 0 || thumbnailSize.height == 0 || (width <= thumbnailSize.width && height <= thumbnailSize.height)) {
|
||||||
|
// Full Pixel
|
||||||
|
} else {
|
||||||
|
// Thumbnail
|
||||||
|
config.options.use_scaling = 1;
|
||||||
|
if (preserveAspectRatio) {
|
||||||
|
CGFloat pixelRatio = (CGFloat)width / (CGFloat)height;
|
||||||
|
CGFloat thumbnailRatio = thumbnailSize.width / thumbnailSize.height;
|
||||||
|
if (pixelRatio > thumbnailRatio) {
|
||||||
|
config.options.scaled_width = thumbnailSize.width;
|
||||||
|
config.options.scaled_height = thumbnailSize.width / pixelRatio;
|
||||||
|
} else {
|
||||||
|
config.options.scaled_height = thumbnailSize.height;
|
||||||
|
config.options.scaled_width = thumbnailSize.height * pixelRatio;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config.options.scaled_width = thumbnailSize.width;
|
||||||
|
config.options.scaled_height = thumbnailSize.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Decode the WebP image data into a RGBA value array
|
// Decode the WebP image data into a RGBA value array
|
||||||
if (WebPDecode(webpData.bytes, webpData.size, &config) != VP8_STATUS_OK) {
|
if (WebPDecode(webpData.bytes, webpData.size, &config) != VP8_STATUS_OK) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
int width = config.input.width;
|
|
||||||
int height = config.input.height;
|
|
||||||
if (config.options.use_scaling) {
|
if (config.options.use_scaling) {
|
||||||
width = config.options.scaled_width;
|
width = config.options.scaled_width;
|
||||||
height = config.options.scaled_height;
|
height = config.options.scaled_height;
|
||||||
|
@ -681,6 +736,22 @@ static void FreeImageData(void *info, const void *data, size_t size) {
|
||||||
scale = 1;
|
scale = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CGSize thumbnailSize = CGSizeZero;
|
||||||
|
NSValue *thumbnailSizeValue = options[SDImageCoderDecodeThumbnailPixelSize];
|
||||||
|
if (thumbnailSizeValue != nil) {
|
||||||
|
#if SD_MAC
|
||||||
|
thumbnailSize = thumbnailSizeValue.sizeValue;
|
||||||
|
#else
|
||||||
|
thumbnailSize = thumbnailSizeValue.CGSizeValue;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
_thumbnailSize = thumbnailSize;
|
||||||
|
BOOL preserveAspectRatio = YES;
|
||||||
|
NSNumber *preserveAspectRatioValue = options[SDImageCoderDecodePreserveAspectRatio];
|
||||||
|
if (preserveAspectRatioValue != nil) {
|
||||||
|
preserveAspectRatio = preserveAspectRatioValue.boolValue;
|
||||||
|
}
|
||||||
|
_preserveAspectRatio = preserveAspectRatio;
|
||||||
_scale = scale;
|
_scale = scale;
|
||||||
_demux = demuxer;
|
_demux = demuxer;
|
||||||
_imageData = data;
|
_imageData = data;
|
||||||
|
@ -812,7 +883,7 @@ static void FreeImageData(void *info, const void *data, size_t size) {
|
||||||
WebPDemuxReleaseIterator(&iter);
|
WebPDemuxReleaseIterator(&iter);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:_colorSpace];
|
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:_colorSpace preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize];
|
||||||
if (!imageRef) {
|
if (!imageRef) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -874,7 +945,7 @@ static void FreeImageData(void *info, const void *data, size_t size) {
|
||||||
if (endIndex > startIndex) {
|
if (endIndex > startIndex) {
|
||||||
do {
|
do {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
[self sd_blendWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace];
|
[self sd_blendWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize];
|
||||||
}
|
}
|
||||||
} while ((size_t)iter.frame_num < endIndex && WebPDemuxNextFrame(&iter));
|
} while ((size_t)iter.frame_num < endIndex && WebPDemuxNextFrame(&iter));
|
||||||
}
|
}
|
||||||
|
@ -887,7 +958,7 @@ static void FreeImageData(void *info, const void *data, size_t size) {
|
||||||
_currentBlendIndex = index;
|
_currentBlendIndex = index;
|
||||||
|
|
||||||
// Now the canvas is ready, which respects of dispose method behavior. Just do normal decoding and produce image.
|
// Now the canvas is ready, which respects of dispose method behavior. Just do normal decoding and produce image.
|
||||||
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace];
|
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize];
|
||||||
if (!imageRef) {
|
if (!imageRef) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue