From 9db3358eb0a9134ca2482457352f0445ab401565 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Thu, 16 Jan 2020 22:12:43 +0800 Subject: [PATCH] WebPCoder now supports the thumbnail decoding --- Cartfile | 2 +- Cartfile.resolved | 4 +- .../ViewController.m | 2 +- SDWebImageWebPCoder.podspec | 2 +- .../Classes/SDImageWebPCoder.m | 95 ++++++++++++++++--- 5 files changed, 88 insertions(+), 17 deletions(-) diff --git a/Cartfile b/Cartfile index 3aec783..156ab0a 100644 --- a/Cartfile +++ b/Cartfile @@ -1,2 +1,2 @@ -github "SDWebImage/SDWebImage" ~> 5.0 +github "SDWebImage/SDWebImage" ~> 5.5 github "SDWebImage/libwebp-Xcode" ~> 1.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index 0956195..76a844b 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,2 +1,2 @@ -github "SDWebImage/SDWebImage" "5.0.0" -github "SDWebImage/libwebp-Xcode" "1.0.0" +github "SDWebImage/SDWebImage" "5.5.0" +github "SDWebImage/libwebp-Xcode" "1.1.0" diff --git a/Example/SDWebImageWebPCoderExample/ViewController.m b/Example/SDWebImageWebPCoderExample/ViewController.m index e358dd0..0d31b16 100644 --- a/Example/SDWebImageWebPCoderExample/ViewController.m +++ b/Example/SDWebImageWebPCoderExample/ViewController.m @@ -35,7 +35,7 @@ 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"]; - [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) { NSLog(@"%@", @"Static WebP load success"); } diff --git a/SDWebImageWebPCoder.podspec b/SDWebImageWebPCoder.podspec index da35dcb..e59c138 100644 --- a/SDWebImageWebPCoder.podspec +++ b/SDWebImageWebPCoder.podspec @@ -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', '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' end diff --git a/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m b/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m index 932eebb..bf6ce09 100644 --- a/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m +++ b/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m @@ -68,6 +68,8 @@ CGFloat _canvasHeight; dispatch_semaphore_t _lock; NSUInteger _currentBlendIndex; + BOOL _preserveAspectRatio; + CGSize _thumbnailSize; } - (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 WebPIterator iter; // libwebp's index start with 1 @@ -145,7 +163,7 @@ if (!hasAnimation || decodeFirstFrame) { // 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); #if SD_UIKIT || SD_WATCH UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; @@ -176,7 +194,7 @@ do { @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) { continue; } @@ -221,6 +239,22 @@ } } _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; } @@ -308,7 +342,7 @@ 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); CGFloat tmpX = iter.x_offset; CGFloat tmpY = canvasHeight - iter.height - iter.y_offset; @@ -317,7 +351,7 @@ if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { CGContextClearRect(canvas, imageRect); } 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) { return; } @@ -331,8 +365,8 @@ } } -- (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef CF_RETURNS_RETAINED { - CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpaceRef]; +- (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 preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize]; if (!imageRef) { return nil; } @@ -359,7 +393,7 @@ 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; if (!WebPInitDecoderConfig(&config)) { return nil; @@ -377,13 +411,34 @@ config.options.use_threads = 1; 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 if (WebPDecode(webpData.bytes, webpData.size, &config) != VP8_STATUS_OK) { return nil; } - int width = config.input.width; - int height = config.input.height; if (config.options.use_scaling) { width = config.options.scaled_width; height = config.options.scaled_height; @@ -681,6 +736,22 @@ static void FreeImageData(void *info, const void *data, size_t size) { 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; _demux = demuxer; _imageData = data; @@ -812,7 +883,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { WebPDemuxReleaseIterator(&iter); 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) { return nil; } @@ -874,7 +945,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { if (endIndex > startIndex) { do { @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)); } @@ -887,7 +958,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { _currentBlendIndex = index; // 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) { return nil; }