@@ -67,7 +67,10 @@ @implementation SDImageAVIFCoder {
6767 CGFloat _scale;
6868 NSUInteger _loopCount;
6969 NSUInteger _frameCount;
70+ BOOL _hasAnimation;
7071 SD_LOCK_DECLARE (_lock);
72+ BOOL _preserveAspectRatio;
73+ CGSize _thumbnailSize;
7174}
7275
7376- (void )dealloc {
@@ -93,14 +96,32 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(SDImageCoderOptions *)
9396 if (!data) {
9497 return nil ;
9598 }
99+ BOOL decodeFirstFrame = [options[SDImageCoderDecodeFirstFrameOnly] boolValue ];
96100 CGFloat scale = 1 ;
97- if ([options valueForKey: SDImageCoderDecodeScaleFactor]) {
98- scale = [[options valueForKey: SDImageCoderDecodeScaleFactor] doubleValue ];
101+ NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor];
102+ if (scaleFactor != nil ) {
103+ scale = [scaleFactor doubleValue ];
99104 if (scale < 1 ) {
100105 scale = 1 ;
101106 }
102107 }
103108
109+ CGSize thumbnailSize = CGSizeZero;
110+ NSValue *thumbnailSizeValue = options[SDImageCoderDecodeThumbnailPixelSize];
111+ if (thumbnailSizeValue != nil ) {
112+ #if SD_MAC
113+ thumbnailSize = thumbnailSizeValue.sizeValue ;
114+ #else
115+ thumbnailSize = thumbnailSizeValue.CGSizeValue ;
116+ #endif
117+ }
118+
119+ BOOL preserveAspectRatio = YES ;
120+ NSNumber *preserveAspectRatioValue = options[SDImageCoderDecodePreserveAspectRatio];
121+ if (preserveAspectRatioValue != nil ) {
122+ preserveAspectRatio = preserveAspectRatioValue.boolValue ;
123+ }
124+
104125 // Decode it
105126 avifDecoder * decoder = avifDecoderCreate ();
106127 avifDecoderSetIOMemory (decoder, data.bytes , data.length );
@@ -113,15 +134,27 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(SDImageCoderOptions *)
113134 return nil ;
114135 }
115136
137+ BOOL hasAnimation = decoder->imageCount > 1 ;
138+ uint32_t width = decoder->image ->width ;
139+ uint32_t height = decoder->image ->height ;
140+ CGSize scaledSize = [SDImageCoderHelper scaledSizeWithImageSize: CGSizeMake (width, height) scaleSize: thumbnailSize preserveAspectRatio: preserveAspectRatio shouldScaleUp: NO ];
141+
116142 // Static image
117- if (decoder-> imageCount <= 1 ) {
143+ if (!hasAnimation || decodeFirstFrame ) {
118144 avifResult nextImageResult = avifDecoderNextImage (decoder);
119145 if (nextImageResult != AVIF_RESULT_OK) {
120146 NSLog (@" Failed to decode image: %s " , avifResultToString (nextImageResult));
121147 avifDecoderDestroy (decoder);
122148 return nil ;
123149 }
124- CGImageRef imageRef = SDCreateCGImageFromAVIF (decoder->image );
150+ CGImageRef originImageRef = SDCreateCGImageFromAVIF (decoder->image );
151+ if (!originImageRef) {
152+ avifDecoderDestroy (decoder);
153+ return nil ;
154+ }
155+ // TODO: optimization using vImageScale directly during transform
156+ CGImageRef imageRef = [SDImageCoderHelper CGImageCreateScaled: originImageRef size: scaledSize];
157+ CGImageRelease (originImageRef);
125158 if (!imageRef) {
126159 avifDecoderDestroy (decoder);
127160 return nil ;
@@ -140,7 +173,13 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(SDImageCoderOptions *)
140173 NSMutableArray <SDImageFrame *> *frames = [NSMutableArray array ];
141174 while (avifDecoderNextImage (decoder) == AVIF_RESULT_OK) {
142175 @autoreleasepool {
143- CGImageRef imageRef = SDCreateCGImageFromAVIF (decoder->image );
176+ CGImageRef originImageRef = SDCreateCGImageFromAVIF (decoder->image );
177+ if (!originImageRef) {
178+ continue ;
179+ }
180+ // TODO: optimization using vImageScale directly during transform
181+ CGImageRef imageRef = [SDImageCoderHelper CGImageCreateScaled: originImageRef size: scaledSize];
182+ CGImageRelease (originImageRef);
144183 if (!imageRef) {
145184 continue ;
146185 }
@@ -263,6 +302,8 @@ - (nullable NSData *)encodedDataWithImage:(nullable UIImage *)image format:(SDIm
263302 avifEncoder *encoder = avifEncoderCreate ();
264303 encoder->minQuantizer = rescaledQuality;
265304 encoder->maxQuantizer = rescaledQuality;
305+ encoder->minQuantizerAlpha = rescaledQuality;
306+ encoder->maxQuantizerAlpha = rescaledQuality;
266307 encoder->maxThreads = 2 ;
267308 avifResult result = avifEncoderWrite (encoder, avif, &raw);
268309
@@ -296,6 +337,7 @@ - (instancetype)initWithAnimatedImageData:(NSData *)data options:(SDImageCoderOp
296337 // TODO: Optimize the performance like WebPCoder (frame meta cache, etc)
297338 _frameCount = decoder->imageCount ;
298339 _loopCount = 0 ;
340+ _hasAnimation = decoder->imageCount > 1 ;
299341 CGFloat scale = 1 ;
300342 NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor];
301343 if (scaleFactor != nil ) {
@@ -305,6 +347,22 @@ - (instancetype)initWithAnimatedImageData:(NSData *)data options:(SDImageCoderOp
305347 }
306348 }
307349 _scale = scale;
350+ CGSize thumbnailSize = CGSizeZero;
351+ NSValue *thumbnailSizeValue = options[SDImageCoderDecodeThumbnailPixelSize];
352+ if (thumbnailSizeValue != nil ) {
353+ #if SD_MAC
354+ thumbnailSize = thumbnailSizeValue.sizeValue ;
355+ #else
356+ thumbnailSize = thumbnailSizeValue.CGSizeValue ;
357+ #endif
358+ }
359+ _thumbnailSize = thumbnailSize;
360+ BOOL preserveAspectRatio = YES ;
361+ NSNumber *preserveAspectRatioValue = options[SDImageCoderDecodePreserveAspectRatio];
362+ if (preserveAspectRatioValue != nil ) {
363+ preserveAspectRatio = preserveAspectRatioValue.boolValue ;
364+ }
365+ _preserveAspectRatio = preserveAspectRatio;
308366 _decoder = decoder;
309367 _imageData = data;
310368 SD_LOCK_INIT (_lock);
@@ -345,14 +403,25 @@ - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index {
345403 if (index >= _frameCount) {
346404 return nil ;
347405 }
406+ uint32_t width = 0 ;
407+ uint32_t height = 0 ;
348408 SD_LOCK (_lock);
349409 avifResult decodeResult = avifDecoderNthImage (_decoder, (uint32_t )index);
350410 if (decodeResult != AVIF_RESULT_OK) {
351411 SD_UNLOCK (_lock);
352412 return nil ;
353413 }
354- CGImageRef imageRef = SDCreateCGImageFromAVIF (_decoder->image );
414+ width = _decoder->image ->width ;
415+ height = _decoder->image ->height ;
416+ CGImageRef originImageRef = SDCreateCGImageFromAVIF (_decoder->image );
355417 SD_UNLOCK (_lock);
418+ if (!originImageRef) {
419+ return nil ;
420+ }
421+ CGSize scaledSize = [SDImageCoderHelper scaledSizeWithImageSize: CGSizeMake (width, height) scaleSize: _thumbnailSize preserveAspectRatio: _preserveAspectRatio shouldScaleUp: NO ];
422+ // TODO: optimization using vImageScale directly during transform
423+ CGImageRef imageRef = [SDImageCoderHelper CGImageCreateScaled: originImageRef size: scaledSize];
424+ CGImageRelease (originImageRef);
356425 if (!imageRef) {
357426 return nil ;
358427 }
0 commit comments