Skip to content

Commit 9db3358

Browse files
committed
WebPCoder now supports the thumbnail decoding
1 parent a936bdb commit 9db3358

File tree

5 files changed

+88
-17
lines changed

5 files changed

+88
-17
lines changed

Cartfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
github "SDWebImage/SDWebImage" ~> 5.0
1+
github "SDWebImage/SDWebImage" ~> 5.5
22
github "SDWebImage/libwebp-Xcode" ~> 1.0

Cartfile.resolved

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
github "SDWebImage/SDWebImage" "5.0.0"
2-
github "SDWebImage/libwebp-Xcode" "1.0.0"
1+
github "SDWebImage/SDWebImage" "5.5.0"
2+
github "SDWebImage/libwebp-Xcode" "1.1.0"

Example/SDWebImageWebPCoderExample/ViewController.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ - (void)viewDidLoad {
3535
NSURL *staticWebPURL = [NSURL URLWithString:@"https://www.gstatic.com/webp/gallery/2.webp"];
3636
NSURL *animatedWebPURL = [NSURL URLWithString:@"http://littlesvr.ca/apng/images/world-cup-2014-42.webp"];
3737

38-
[self.imageView1 sd_setImageWithURL:staticWebPURL completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
38+
[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) {
3939
if (image) {
4040
NSLog(@"%@", @"Static WebP load success");
4141
}

SDWebImageWebPCoder.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ This is a SDWebImage coder plugin to support WebP image.
2727
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SD_WEBP=1 WEBP_USE_INTRINSICS=1',
2828
'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src'
2929
}
30-
s.dependency 'SDWebImage/Core', '~> 5.0'
30+
s.dependency 'SDWebImage/Core', '~> 5.5'
3131
s.dependency 'libwebp', '~> 1.0'
3232

3333
end

SDWebImageWebPCoder/Classes/SDImageWebPCoder.m

Lines changed: 83 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ @implementation SDImageWebPCoder {
6868
CGFloat _canvasHeight;
6969
dispatch_semaphore_t _lock;
7070
NSUInteger _currentBlendIndex;
71+
BOOL _preserveAspectRatio;
72+
CGSize _thumbnailSize;
7173
}
7274

7375
- (void)dealloc {
@@ -133,6 +135,22 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
133135
}
134136
}
135137

138+
CGSize thumbnailSize = CGSizeZero;
139+
NSValue *thumbnailSizeValue = options[SDImageCoderDecodeThumbnailPixelSize];
140+
if (thumbnailSizeValue != nil) {
141+
#if SD_MAC
142+
thumbnailSize = thumbnailSizeValue.sizeValue;
143+
#else
144+
thumbnailSize = thumbnailSizeValue.CGSizeValue;
145+
#endif
146+
}
147+
148+
BOOL preserveAspectRatio = YES;
149+
NSNumber *preserveAspectRatioValue = options[SDImageCoderDecodePreserveAspectRatio];
150+
if (preserveAspectRatioValue != nil) {
151+
preserveAspectRatio = preserveAspectRatioValue.boolValue;
152+
}
153+
136154
// for animated webp image
137155
WebPIterator iter;
138156
// libwebp's index start with 1
@@ -145,7 +163,7 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
145163

146164
if (!hasAnimation || decodeFirstFrame) {
147165
// first frame for animated webp image
148-
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpace];
166+
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpace preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize];
149167
CGColorSpaceRelease(colorSpace);
150168
#if SD_UIKIT || SD_WATCH
151169
UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
@@ -176,7 +194,7 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
176194

177195
do {
178196
@autoreleasepool {
179-
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:canvas iterator:iter colorSpace:colorSpace];
197+
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:canvas iterator:iter colorSpace:colorSpace preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize];
180198
if (!imageRef) {
181199
continue;
182200
}
@@ -221,6 +239,22 @@ - (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)optio
221239
}
222240
}
223241
_scale = scale;
242+
CGSize thumbnailSize = CGSizeZero;
243+
NSValue *thumbnailSizeValue = options[SDImageCoderDecodeThumbnailPixelSize];
244+
if (thumbnailSizeValue != nil) {
245+
#if SD_MAC
246+
thumbnailSize = thumbnailSizeValue.sizeValue;
247+
#else
248+
thumbnailSize = thumbnailSizeValue.CGSizeValue;
249+
#endif
250+
}
251+
_thumbnailSize = thumbnailSize;
252+
BOOL preserveAspectRatio = YES;
253+
NSNumber *preserveAspectRatioValue = options[SDImageCoderDecodePreserveAspectRatio];
254+
if (preserveAspectRatioValue != nil) {
255+
preserveAspectRatio = preserveAspectRatioValue.boolValue;
256+
}
257+
_preserveAspectRatio = preserveAspectRatio;
224258
}
225259
return self;
226260
}
@@ -308,7 +342,7 @@ - (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options {
308342
return image;
309343
}
310344

311-
- (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef {
345+
- (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize {
312346
size_t canvasHeight = CGBitmapContextGetHeight(canvas);
313347
CGFloat tmpX = iter.x_offset;
314348
CGFloat tmpY = canvasHeight - iter.height - iter.y_offset;
@@ -317,7 +351,7 @@ - (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)
317351
if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
318352
CGContextClearRect(canvas, imageRect);
319353
} else {
320-
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpaceRef];
354+
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpaceRef preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize];
321355
if (!imageRef) {
322356
return;
323357
}
@@ -331,8 +365,8 @@ - (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)
331365
}
332366
}
333367

334-
- (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef CF_RETURNS_RETAINED {
335-
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpaceRef];
368+
- (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize CF_RETURNS_RETAINED {
369+
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:colorSpaceRef preserveAspectRatio:preserveAspectRatio thumbnailSize:thumbnailSize];
336370
if (!imageRef) {
337371
return nil;
338372
}
@@ -359,7 +393,7 @@ - (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator
359393
return newImageRef;
360394
}
361395

362-
- (nullable CGImageRef)sd_createWebpImageWithData:(WebPData)webpData colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef CF_RETURNS_RETAINED {
396+
- (nullable CGImageRef)sd_createWebpImageWithData:(WebPData)webpData colorSpace:(nonnull CGColorSpaceRef)colorSpaceRef preserveAspectRatio:(BOOL)preserveAspectRatio thumbnailSize:(CGSize)thumbnailSize CF_RETURNS_RETAINED {
363397
WebPDecoderConfig config;
364398
if (!WebPInitDecoderConfig(&config)) {
365399
return nil;
@@ -377,13 +411,34 @@ - (nullable CGImageRef)sd_createWebpImageWithData:(WebPData)webpData colorSpace:
377411
config.options.use_threads = 1;
378412
config.output.colorspace = MODE_bgrA;
379413

414+
int width = config.input.width;
415+
int height = config.input.height;
416+
if (width == 0 || height == 0 || thumbnailSize.width == 0 || thumbnailSize.height == 0 || (width <= thumbnailSize.width && height <= thumbnailSize.height)) {
417+
// Full Pixel
418+
} else {
419+
// Thumbnail
420+
config.options.use_scaling = 1;
421+
if (preserveAspectRatio) {
422+
CGFloat pixelRatio = (CGFloat)width / (CGFloat)height;
423+
CGFloat thumbnailRatio = thumbnailSize.width / thumbnailSize.height;
424+
if (pixelRatio > thumbnailRatio) {
425+
config.options.scaled_width = thumbnailSize.width;
426+
config.options.scaled_height = thumbnailSize.width / pixelRatio;
427+
} else {
428+
config.options.scaled_height = thumbnailSize.height;
429+
config.options.scaled_width = thumbnailSize.height * pixelRatio;
430+
}
431+
} else {
432+
config.options.scaled_width = thumbnailSize.width;
433+
config.options.scaled_height = thumbnailSize.height;
434+
}
435+
}
436+
380437
// Decode the WebP image data into a RGBA value array
381438
if (WebPDecode(webpData.bytes, webpData.size, &config) != VP8_STATUS_OK) {
382439
return nil;
383440
}
384441

385-
int width = config.input.width;
386-
int height = config.input.height;
387442
if (config.options.use_scaling) {
388443
width = config.options.scaled_width;
389444
height = config.options.scaled_height;
@@ -681,6 +736,22 @@ - (instancetype)initWithAnimatedImageData:(NSData *)data options:(nullable SDIma
681736
scale = 1;
682737
}
683738
}
739+
CGSize thumbnailSize = CGSizeZero;
740+
NSValue *thumbnailSizeValue = options[SDImageCoderDecodeThumbnailPixelSize];
741+
if (thumbnailSizeValue != nil) {
742+
#if SD_MAC
743+
thumbnailSize = thumbnailSizeValue.sizeValue;
744+
#else
745+
thumbnailSize = thumbnailSizeValue.CGSizeValue;
746+
#endif
747+
}
748+
_thumbnailSize = thumbnailSize;
749+
BOOL preserveAspectRatio = YES;
750+
NSNumber *preserveAspectRatioValue = options[SDImageCoderDecodePreserveAspectRatio];
751+
if (preserveAspectRatioValue != nil) {
752+
preserveAspectRatio = preserveAspectRatioValue.boolValue;
753+
}
754+
_preserveAspectRatio = preserveAspectRatio;
684755
_scale = scale;
685756
_demux = demuxer;
686757
_imageData = data;
@@ -812,7 +883,7 @@ - (UIImage *)safeStaticImageFrame {
812883
WebPDemuxReleaseIterator(&iter);
813884
return nil;
814885
}
815-
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:_colorSpace];
886+
CGImageRef imageRef = [self sd_createWebpImageWithData:iter.fragment colorSpace:_colorSpace preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize];
816887
if (!imageRef) {
817888
return nil;
818889
}
@@ -874,7 +945,7 @@ - (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index {
874945
if (endIndex > startIndex) {
875946
do {
876947
@autoreleasepool {
877-
[self sd_blendWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace];
948+
[self sd_blendWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize];
878949
}
879950
} while ((size_t)iter.frame_num < endIndex && WebPDemuxNextFrame(&iter));
880951
}
@@ -887,7 +958,7 @@ - (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index {
887958
_currentBlendIndex = index;
888959

889960
// Now the canvas is ready, which respects of dispose method behavior. Just do normal decoding and produce image.
890-
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace];
961+
CGImageRef imageRef = [self sd_drawnWebpImageWithCanvas:_canvas iterator:iter colorSpace:_colorSpace preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize];
891962
if (!imageRef) {
892963
return nil;
893964
}

0 commit comments

Comments
 (0)