@@ -68,6 +68,8 @@ @implementation SDImageWebPCoder {
68
68
CGFloat _canvasHeight;
69
69
dispatch_semaphore_t _lock;
70
70
NSUInteger _currentBlendIndex;
71
+ BOOL _preserveAspectRatio;
72
+ CGSize _thumbnailSize;
71
73
}
72
74
73
75
- (void )dealloc {
@@ -133,6 +135,22 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
133
135
}
134
136
}
135
137
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
+
136
154
// for animated webp image
137
155
WebPIterator iter;
138
156
// libwebp's index start with 1
@@ -145,7 +163,7 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
145
163
146
164
if (!hasAnimation || decodeFirstFrame) {
147
165
// 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 ];
149
167
CGColorSpaceRelease (colorSpace);
150
168
#if SD_UIKIT || SD_WATCH
151
169
UIImage *firstFrameImage = [[UIImage alloc ] initWithCGImage: imageRef scale: scale orientation: UIImageOrientationUp];
@@ -176,7 +194,7 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
176
194
177
195
do {
178
196
@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 ];
180
198
if (!imageRef) {
181
199
continue ;
182
200
}
@@ -221,6 +239,22 @@ - (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)optio
221
239
}
222
240
}
223
241
_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;
224
258
}
225
259
return self;
226
260
}
@@ -308,7 +342,7 @@ - (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options {
308
342
return image;
309
343
}
310
344
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 {
312
346
size_t canvasHeight = CGBitmapContextGetHeight (canvas);
313
347
CGFloat tmpX = iter.x_offset ;
314
348
CGFloat tmpY = canvasHeight - iter.height - iter.y_offset ;
@@ -317,7 +351,7 @@ - (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)
317
351
if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
318
352
CGContextClearRect (canvas, imageRect);
319
353
} 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 ];
321
355
if (!imageRef) {
322
356
return ;
323
357
}
@@ -331,8 +365,8 @@ - (void)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)
331
365
}
332
366
}
333
367
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 ];
336
370
if (!imageRef) {
337
371
return nil ;
338
372
}
@@ -359,7 +393,7 @@ - (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator
359
393
return newImageRef;
360
394
}
361
395
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 {
363
397
WebPDecoderConfig config;
364
398
if (!WebPInitDecoderConfig (&config)) {
365
399
return nil ;
@@ -377,13 +411,34 @@ - (nullable CGImageRef)sd_createWebpImageWithData:(WebPData)webpData colorSpace:
377
411
config.options .use_threads = 1 ;
378
412
config.output .colorspace = MODE_bgrA;
379
413
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
+
380
437
// Decode the WebP image data into a RGBA value array
381
438
if (WebPDecode (webpData.bytes , webpData.size , &config) != VP8_STATUS_OK) {
382
439
return nil ;
383
440
}
384
441
385
- int width = config.input .width ;
386
- int height = config.input .height ;
387
442
if (config.options .use_scaling ) {
388
443
width = config.options .scaled_width ;
389
444
height = config.options .scaled_height ;
@@ -681,6 +736,22 @@ - (instancetype)initWithAnimatedImageData:(NSData *)data options:(nullable SDIma
681
736
scale = 1 ;
682
737
}
683
738
}
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;
684
755
_scale = scale;
685
756
_demux = demuxer;
686
757
_imageData = data;
@@ -812,7 +883,7 @@ - (UIImage *)safeStaticImageFrame {
812
883
WebPDemuxReleaseIterator (&iter);
813
884
return nil ;
814
885
}
815
- CGImageRef imageRef = [self sd_createWebpImageWithData: iter.fragment colorSpace: _colorSpace];
886
+ CGImageRef imageRef = [self sd_createWebpImageWithData: iter.fragment colorSpace: _colorSpace preserveAspectRatio: _preserveAspectRatio thumbnailSize: _thumbnailSize ];
816
887
if (!imageRef) {
817
888
return nil ;
818
889
}
@@ -874,7 +945,7 @@ - (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index {
874
945
if (endIndex > startIndex) {
875
946
do {
876
947
@autoreleasepool {
877
- [self sd_blendWebpImageWithCanvas: _canvas iterator: iter colorSpace: _colorSpace];
948
+ [self sd_blendWebpImageWithCanvas: _canvas iterator: iter colorSpace: _colorSpace preserveAspectRatio: _preserveAspectRatio thumbnailSize: _thumbnailSize ];
878
949
}
879
950
} while ((size_t )iter.frame_num < endIndex && WebPDemuxNextFrame (&iter));
880
951
}
@@ -887,7 +958,7 @@ - (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index {
887
958
_currentBlendIndex = index;
888
959
889
960
// 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 ];
891
962
if (!imageRef) {
892
963
return nil ;
893
964
}
0 commit comments