24
24
25
25
#import < Accelerate/Accelerate.h>
26
26
27
+ // / Calculate the actual thumnail pixel size
28
+ static CGSize SDCalculateThumbnailSize (CGSize fullSize, BOOL preserveAspectRatio, CGSize thumbnailSize) {
29
+ CGFloat width = fullSize.width ;
30
+ CGFloat height = fullSize.height ;
31
+ CGFloat resultWidth;
32
+ CGFloat resultHeight;
33
+
34
+ if (width == 0 || height == 0 || thumbnailSize.width == 0 || thumbnailSize.height == 0 || (width <= thumbnailSize.width && height <= thumbnailSize.height )) {
35
+ // Full Pixel
36
+ resultWidth = width;
37
+ resultHeight = height;
38
+ } else {
39
+ // Thumbnail
40
+ if (preserveAspectRatio) {
41
+ CGFloat pixelRatio = width / height;
42
+ CGFloat thumbnailRatio = thumbnailSize.width / thumbnailSize.height ;
43
+ if (pixelRatio > thumbnailRatio) {
44
+ resultWidth = thumbnailSize.width ;
45
+ resultHeight = ceil (thumbnailSize.width / pixelRatio);
46
+ } else {
47
+ resultHeight = thumbnailSize.height ;
48
+ resultWidth = ceil (thumbnailSize.height * pixelRatio);
49
+ }
50
+ } else {
51
+ resultWidth = thumbnailSize.width ;
52
+ resultHeight = thumbnailSize.height ;
53
+ }
54
+ }
55
+
56
+ return CGSizeMake (resultWidth, resultHeight);
57
+ }
58
+
27
59
#ifndef SD_LOCK
28
60
#define SD_LOCK (lock ) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
29
61
#endif
@@ -64,8 +96,6 @@ @implementation SDImageWebPCoder {
64
96
BOOL _hasAnimation;
65
97
BOOL _hasAlpha;
66
98
BOOL _finished;
67
- CGFloat _canvasWidth;
68
- CGFloat _canvasHeight;
69
99
dispatch_semaphore_t _lock;
70
100
NSUInteger _currentBlendIndex;
71
101
BOOL _preserveAspectRatio;
@@ -159,7 +189,7 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
159
189
WebPDemuxDelete (demuxer);
160
190
return nil ;
161
191
}
162
- CGColorSpaceRef colorSpace = [self sd_colorSpaceWithDemuxer : demuxer];
192
+ CGColorSpaceRef colorSpace = [self sd_createColorSpaceWithDemuxer : demuxer];
163
193
164
194
if (!hasAnimation || decodeFirstFrame) {
165
195
// first frame for animated webp image
@@ -177,19 +207,14 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
177
207
return firstFrameImage;
178
208
}
179
209
180
- int loopCount = WebPDemuxGetI (demuxer, WEBP_FF_LOOP_COUNT);
181
- int canvasWidth = WebPDemuxGetI (demuxer, WEBP_FF_CANVAS_WIDTH);
182
- int canvasHeight = WebPDemuxGetI (demuxer, WEBP_FF_CANVAS_HEIGHT);
183
- BOOL hasAlpha = flags & ALPHA_FLAG;
184
- CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host ;
185
- bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst ;
186
- CGContextRef canvas = CGBitmapContextCreate (NULL , canvasWidth, canvasHeight, 8 , 0 , [SDImageCoderHelper colorSpaceGetDeviceRGB ], bitmapInfo);
210
+ CGContextRef canvas = [self sd_createCanvasWithDemuxer: demuxer colorSpace: colorSpace preserveAspectRatio: preserveAspectRatio thumbnailSize: thumbnailSize];
187
211
if (!canvas) {
188
212
WebPDemuxDelete (demuxer);
189
213
CGColorSpaceRelease (colorSpace);
190
214
return nil ;
191
215
}
192
216
217
+ int loopCount = WebPDemuxGetI (demuxer, WEBP_FF_LOOP_COUNT);
193
218
NSMutableArray <SDImageFrame *> *frames = [NSMutableArray array ];
194
219
195
220
do {
@@ -305,7 +330,7 @@ - (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options {
305
330
return nil ;
306
331
}
307
332
308
- CGContextRef canvas = CGBitmapContextCreate ( NULL , width, height, 8 , 0 , [SDImageCoderHelper colorSpaceGetDeviceRGB ], bitmapInfo) ;
333
+ CGContextRef canvas = [ self sd_createCanvasWithDemuxer: _demux colorSpace: colorSpaceRef preserveAspectRatio: _preserveAspectRatio thumbnailSize: _thumbnailSize] ;
309
334
if (!canvas) {
310
335
CGImageRelease (imageRef);
311
336
return nil ;
@@ -413,25 +438,12 @@ - (nullable CGImageRef)sd_createWebpImageWithData:(WebPData)webpData colorSpace:
413
438
414
439
int width = config.input .width ;
415
440
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
441
+ CGSize resultSize = SDCalculateThumbnailSize (CGSizeMake (width, height), preserveAspectRatio, thumbnailSize);
442
+ if (resultSize.width != width || resultSize.height != height) {
443
+ // Use scaling
420
444
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
- }
445
+ config.options .scaled_width = resultSize.width ;
446
+ config.options .scaled_height = resultSize.height ;
435
447
}
436
448
437
449
// Decode the WebP image data into a RGBA value array
@@ -451,7 +463,7 @@ - (nullable CGImageRef)sd_createWebpImageWithData:(WebPData)webpData colorSpace:
451
463
size_t bitsPerPixel = 32 ;
452
464
size_t bytesPerRow = config.output .u .RGBA .stride ;
453
465
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault ;
454
- CGImageRef imageRef = CGImageCreate (width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL , NO , renderingIntent);
466
+ CGImageRef imageRef = CGImageCreate (resultSize. width , resultSize. height , bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL , NO , renderingIntent);
455
467
456
468
CGDataProviderRelease (provider);
457
469
@@ -469,7 +481,7 @@ - (NSTimeInterval)sd_frameDurationWithIterator:(WebPIterator)iter {
469
481
}
470
482
471
483
// Create and return the correct colorspace by checking the ICC Profile
472
- - (nonnull CGColorSpaceRef)sd_colorSpaceWithDemuxer : (nonnull WebPDemuxer *)demuxer CF_RETURNS_RETAINED {
484
+ - (nonnull CGColorSpaceRef)sd_createColorSpaceWithDemuxer : (nonnull WebPDemuxer *)demuxer CF_RETURNS_RETAINED {
473
485
// WebP contains ICC Profile should use the desired colorspace, instead of default device colorspace
474
486
// See: https://developers.google.com/speed/webp/docs/riff_container#color_profile
475
487
@@ -508,6 +520,20 @@ - (nonnull CGColorSpaceRef)sd_colorSpaceWithDemuxer:(nonnull WebPDemuxer *)demux
508
520
return colorSpaceRef;
509
521
}
510
522
523
+ - (CGContextRef)sd_createCanvasWithDemuxer : (nonnull WebPDemuxer *)demuxer colorSpace : (nonnull CGColorSpaceRef)colorSpace preserveAspectRatio : (BOOL )preserveAspectRatio thumbnailSize : (CGSize)thumbnailSize CF_RETURNS_RETAINED {
524
+ uint32_t flags = WebPDemuxGetI (demuxer, WEBP_FF_FORMAT_FLAGS);
525
+ int canvasWidth = WebPDemuxGetI (demuxer, WEBP_FF_CANVAS_WIDTH);
526
+ int canvasHeight = WebPDemuxGetI (demuxer, WEBP_FF_CANVAS_HEIGHT);
527
+ BOOL hasAlpha = flags & ALPHA_FLAG;
528
+ CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host ;
529
+ bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst ;
530
+
531
+ CGSize canvasSize = SDCalculateThumbnailSize (CGSizeMake (canvasWidth, canvasHeight), preserveAspectRatio, thumbnailSize);
532
+ CGContextRef canvas = CGBitmapContextCreate (NULL , canvasSize.width , canvasSize.height , 8 , 0 , colorSpace, bitmapInfo);
533
+
534
+ return canvas;
535
+ }
536
+
511
537
#pragma mark - Encode
512
538
- (BOOL )canEncodeToFormat : (SDImageFormat)format {
513
539
return (format == SDImageFormatWebP);
@@ -784,8 +810,6 @@ - (BOOL)scanAndCheckFramesValidWithDemuxer:(WebPDemuxer *)demuxer {
784
810
785
811
_hasAnimation = hasAnimation;
786
812
_hasAlpha = hasAlpha;
787
- _canvasWidth = canvasWidth;
788
- _canvasHeight = canvasHeight;
789
813
_frameCount = frameCount;
790
814
_loopCount = loopCount;
791
815
@@ -875,7 +899,7 @@ - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index {
875
899
- (UIImage *)safeStaticImageFrame {
876
900
UIImage *image;
877
901
if (!_colorSpace) {
878
- _colorSpace = [self sd_colorSpaceWithDemuxer : _demux];
902
+ _colorSpace = [self sd_createColorSpaceWithDemuxer : _demux];
879
903
}
880
904
// Static WebP image
881
905
WebPIterator iter;
@@ -898,18 +922,16 @@ - (UIImage *)safeStaticImageFrame {
898
922
}
899
923
900
924
- (UIImage *)safeAnimatedImageFrameAtIndex : (NSUInteger )index {
925
+ if (!_colorSpace) {
926
+ _colorSpace = [self sd_createColorSpaceWithDemuxer: _demux];
927
+ }
901
928
if (!_canvas) {
902
- CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host ;
903
- bitmapInfo |= _hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst ;
904
- CGContextRef canvas = CGBitmapContextCreate (NULL , _canvasWidth, _canvasHeight, 8 , 0 , [SDImageCoderHelper colorSpaceGetDeviceRGB ], bitmapInfo);
929
+ CGContextRef canvas = [self sd_createCanvasWithDemuxer: _demux colorSpace: _colorSpace preserveAspectRatio: _preserveAspectRatio thumbnailSize: _thumbnailSize];
905
930
if (!canvas) {
906
931
return nil ;
907
932
}
908
933
_canvas = canvas;
909
934
}
910
- if (!_colorSpace) {
911
- _colorSpace = [self sd_colorSpaceWithDemuxer: _demux];
912
- }
913
935
914
936
SDWebPCoderFrame *frame = _frames[index];
915
937
UIImage *image;
@@ -929,7 +951,7 @@ - (UIImage *)safeAnimatedImageFrameAtIndex:(NSUInteger)index {
929
951
} else {
930
952
// Else, this can happen when one image set to different imageViews or one loop end. So we should clear the canvas. Then draw until the canvas is ready.
931
953
if (_currentBlendIndex != NSNotFound ) {
932
- CGContextClearRect (_canvas, CGRectMake (0 , 0 , _canvasWidth, _canvasHeight ));
954
+ CGContextClearRect (_canvas, CGRectMake (0 , 0 , CGBitmapContextGetWidth (_canvas), CGBitmapContextGetHeight (_canvas) ));
933
955
}
934
956
935
957
// Then, loop from the blend from index, draw each of previous frames on the canvas.
0 commit comments