@@ -183,12 +183,8 @@ + (NSUInteger)imageLoopCountWithSource:(CGImageSourceRef)source {
183
183
}
184
184
185
185
+ (NSTimeInterval )frameDurationAtIndex : (NSUInteger )index source : (CGImageSourceRef)source {
186
- NSDictionary *options = @{
187
- (__bridge NSString *)kCGImageSourceShouldCacheImmediately : @(YES ),
188
- (__bridge NSString *)kCGImageSourceShouldCache : @(YES ) // Always cache to reduce CPU usage
189
- };
190
186
NSTimeInterval frameDuration = 0.1 ;
191
- CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex (source, index, (__bridge CFDictionaryRef)options );
187
+ CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex (source, index, NULL );
192
188
if (!cfFrameProperties) {
193
189
return frameDuration;
194
190
}
@@ -218,10 +214,24 @@ + (NSTimeInterval)frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRe
218
214
return frameDuration;
219
215
}
220
216
221
- + (UIImage *)createFrameAtIndex : (NSUInteger )index source : (CGImageSourceRef)source scale : (CGFloat)scale preserveAspectRatio : (BOOL )preserveAspectRatio thumbnailSize : (CGSize)thumbnailSize lazyDecode : (BOOL )lazyDecode options : (NSDictionary *)options {
222
- // Some options need to pass to `CGImageSourceCopyPropertiesAtIndex` before `CGImageSourceCreateImageAtIndex`, or ImageIO will ignore them because they parse once :)
217
+ + (UIImage *)createFrameAtIndex : (NSUInteger )index source : (CGImageSourceRef)source scale : (CGFloat)scale preserveAspectRatio : (BOOL )preserveAspectRatio thumbnailSize : (CGSize)thumbnailSize lazyDecode : (BOOL )lazyDecode animatedImage : (BOOL )animatedImage {
218
+ // `animatedImage` means called from `SDAnimatedImageProvider.animatedImageFrameAtIndex`
219
+ NSDictionary *options;
220
+ if (animatedImage) {
221
+ if (!lazyDecode) {
222
+ options = @{
223
+ // image decoding and caching should happen at image creation time.
224
+ (__bridge NSString *)kCGImageSourceShouldCacheImmediately : @(YES ),
225
+ };
226
+ } else {
227
+ options = @{
228
+ // image decoding will happen at rendering time
229
+ (__bridge NSString *)kCGImageSourceShouldCacheImmediately : @(NO ),
230
+ };
231
+ }
232
+ }
223
233
// Parse the image properties
224
- NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex (source, index, (__bridge CFDictionaryRef)options );
234
+ NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex (source, index, NULL );
225
235
CGFloat pixelWidth = [properties[(__bridge NSString *)kCGImagePropertyPixelWidth ] doubleValue ];
226
236
CGFloat pixelHeight = [properties[(__bridge NSString *)kCGImagePropertyPixelHeight ] doubleValue ];
227
237
CGImagePropertyOrientation exifOrientation = (CGImagePropertyOrientation)[properties[(__bridge NSString *)kCGImagePropertyOrientation ] unsignedIntegerValue ];
@@ -287,7 +297,7 @@ + (UIImage *)createFrameAtIndex:(NSUInteger)index source:(CGImageSourceRef)sourc
287
297
isDecoded = YES ;
288
298
}
289
299
}
290
- } else {
300
+ } else if (animatedImage) {
291
301
// iOS 15+, CGImageRef now retains CGImageSourceRef internally. To workaround its thread-safe issue, we have to strip CGImageSourceRef, using Force-Decode (or have to use SPI `CGImageSetImageSource`), See: https://github.com/SDWebImage/SDWebImage/issues/3273
292
302
if (@available (iOS 15 , tvOS 15 , *)) {
293
303
// User pass `lazyDecode == YES`, but we still have to strip the CGImageSourceRef
@@ -297,21 +307,19 @@ + (UIImage *)createFrameAtIndex:(NSUInteger)index source:(CGImageSourceRef)sourc
297
307
CGImageRelease (imageRef);
298
308
imageRef = newImageRef;
299
309
}
300
- }
301
- }
302
310
#if SD_CHECK_CGIMAGE_RETAIN_SOURCE
303
- if (@available (iOS 15 , tvOS 15 , *)) {
304
- // Assert here to check CGImageRef should not retain the CGImageSourceRef and has possible thread-safe issue (this is behavior on iOS 15+)
305
- // If assert hit, fire issue to https://github.com/SDWebImage/SDWebImage/issues and we update the condition for this behavior check
306
- static dispatch_once_t onceToken;
307
- dispatch_once (&onceToken, ^{
308
- SDCGImageGetImageSource = dlsym (RTLD_DEFAULT, " CGImageGetImageSource" );
309
- });
310
- if (SDCGImageGetImageSource) {
311
- NSCAssert (!SDCGImageGetImageSource(imageRef), @"Animated Coder created CGImageRef should not retain CGImageSourceRef, which may cause thread-safe issue without lock");
311
+ // Assert here to check CGImageRef should not retain the CGImageSourceRef and has possible thread-safe issue (this is behavior on iOS 15+)
312
+ // If assert hit, fire issue to https://github.com/SDWebImage/SDWebImage/issues and we update the condition for this behavior check
313
+ static dispatch_once_t onceToken;
314
+ dispatch_once (&onceToken, ^{
315
+ SDCGImageGetImageSource = dlsym (RTLD_DEFAULT, " CGImageGetImageSource" );
316
+ });
317
+ if (SDCGImageGetImageSource) {
318
+ NSCAssert (!SDCGImageGetImageSource(imageRef), @"Animated Coder created CGImageRef should not retain CGImageSourceRef, which may cause thread-safe issue without lock");
319
+ }
320
+ #endif
312
321
}
313
322
}
314
- #endif
315
323
316
324
#if SD_UIKIT || SD_WATCH
317
325
UIImageOrientation imageOrientation = [SDImageCoderHelper imageOrientationFromEXIFOrientation: exifOrientation];
@@ -412,12 +420,12 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDImageCoderO
412
420
413
421
BOOL decodeFirstFrame = [options[SDImageCoderDecodeFirstFrameOnly] boolValue ];
414
422
if (decodeFirstFrame || count <= 1 ) {
415
- animatedImage = [self .class createFrameAtIndex: 0 source: source scale: scale preserveAspectRatio: preserveAspectRatio thumbnailSize: thumbnailSize lazyDecode: lazyDecode options: nil ];
423
+ animatedImage = [self .class createFrameAtIndex: 0 source: source scale: scale preserveAspectRatio: preserveAspectRatio thumbnailSize: thumbnailSize lazyDecode: lazyDecode animatedImage: NO ];
416
424
} else {
417
425
NSMutableArray <SDImageFrame *> *frames = [NSMutableArray arrayWithCapacity: count];
418
426
419
427
for (size_t i = 0 ; i < count; i++) {
420
- UIImage *image = [self .class createFrameAtIndex: i source: source scale: scale preserveAspectRatio: preserveAspectRatio thumbnailSize: thumbnailSize lazyDecode: lazyDecode options: nil ];
428
+ UIImage *image = [self .class createFrameAtIndex: i source: source scale: scale preserveAspectRatio: preserveAspectRatio thumbnailSize: thumbnailSize lazyDecode: lazyDecode animatedImage: NO ];
421
429
if (!image) {
422
430
continue ;
423
431
}
@@ -473,7 +481,7 @@ - (instancetype)initIncrementalWithOptions:(nullable SDImageCoderOptions *)optio
473
481
preserveAspectRatio = preserveAspectRatioValue.boolValue ;
474
482
}
475
483
_preserveAspectRatio = preserveAspectRatio;
476
- BOOL lazyDecode = YES ; // Defaults YES for static image coder
484
+ BOOL lazyDecode = NO ; // Defaults NO for animated image coder
477
485
NSNumber *lazyDecodeValue = options[SDImageCoderDecodeUseLazyDecoding];
478
486
if (lazyDecodeValue != nil ) {
479
487
lazyDecode = lazyDecodeValue.boolValue ;
@@ -502,11 +510,7 @@ - (void)updateIncrementalData:(NSData *)data finished:(BOOL)finished {
502
510
CGImageSourceUpdateData (_imageSource, (__bridge CFDataRef)data, finished);
503
511
504
512
if (_width + _height == 0 ) {
505
- NSDictionary *options = @{
506
- (__bridge NSString *)kCGImageSourceShouldCacheImmediately : @(YES ),
507
- (__bridge NSString *)kCGImageSourceShouldCache : @(YES ) // Always cache to reduce CPU usage
508
- };
509
- CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex (_imageSource, 0 , (__bridge CFDictionaryRef)options);
513
+ CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex (_imageSource, 0 , NULL );
510
514
if (properties) {
511
515
CFTypeRef val = CFDictionaryGetValue (properties, kCGImagePropertyPixelHeight );
512
516
if (val) CFNumberGetValue (val, kCFNumberLongType , &_height);
@@ -533,7 +537,7 @@ - (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options {
533
537
if (scaleFactor != nil ) {
534
538
scale = MAX ([scaleFactor doubleValue ], 1 );
535
539
}
536
- image = [self .class createFrameAtIndex: 0 source: _imageSource scale: scale preserveAspectRatio: _preserveAspectRatio thumbnailSize: _thumbnailSize lazyDecode: _lazyDecode options: nil ];
540
+ image = [self .class createFrameAtIndex: 0 source: _imageSource scale: scale preserveAspectRatio: _preserveAspectRatio thumbnailSize: _thumbnailSize lazyDecode: _lazyDecode animatedImage: NO ];
537
541
if (image) {
538
542
image.sd_imageFormat = self.class .imageFormat ;
539
543
}
@@ -695,6 +699,12 @@ - (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data optio
695
699
preserveAspectRatio = preserveAspectRatioValue.boolValue ;
696
700
}
697
701
_preserveAspectRatio = preserveAspectRatio;
702
+ BOOL lazyDecode = NO ; // Defaults NO for animated image coder
703
+ NSNumber *lazyDecodeValue = options[SDImageCoderDecodeUseLazyDecoding];
704
+ if (lazyDecodeValue != nil ) {
705
+ lazyDecode = lazyDecodeValue.boolValue ;
706
+ }
707
+ _lazyDecode = lazyDecode;
698
708
_imageSource = imageSource;
699
709
_imageData = data;
700
710
#if SD_UIKIT
@@ -785,24 +795,7 @@ - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index {
785
795
}
786
796
787
797
- (UIImage *)safeAnimatedImageFrameAtIndex : (NSUInteger )index {
788
- NSDictionary *options;
789
- BOOL lazyDecode = NO ; // Defaults NO for animated image coder
790
- NSNumber *lazyDecodeValue = options[SDImageCoderDecodeUseLazyDecoding];
791
- if (lazyDecodeValue != nil ) {
792
- lazyDecode = lazyDecodeValue.boolValue ;
793
- }
794
- if (!lazyDecode) {
795
- options = @{
796
- (__bridge NSString *)kCGImageSourceShouldCacheImmediately : @(NO ),
797
- (__bridge NSString *)kCGImageSourceShouldCache : @(NO )
798
- };
799
- } else {
800
- options = @{
801
- (__bridge NSString *)kCGImageSourceShouldCacheImmediately : @(YES ),
802
- (__bridge NSString *)kCGImageSourceShouldCache : @(YES ) // Always cache to reduce CPU usage
803
- };
804
- }
805
- UIImage *image = [self .class createFrameAtIndex: index source: _imageSource scale: _scale preserveAspectRatio: _preserveAspectRatio thumbnailSize: _thumbnailSize lazyDecode: lazyDecode options: options];
798
+ UIImage *image = [self .class createFrameAtIndex: index source: _imageSource scale: _scale preserveAspectRatio: _preserveAspectRatio thumbnailSize: _thumbnailSize lazyDecode: _lazyDecode animatedImage: YES ];
806
799
if (!image) {
807
800
return nil ;
808
801
}
0 commit comments