diff --git a/Cartfile b/Cartfile index eda0676..299439a 100644 --- a/Cartfile +++ b/Cartfile @@ -1,3 +1,3 @@ -github "SDWebImage/SDWebImage" ~> 5.10 +github "SDWebImage/SDWebImage" ~> 5.15 github "ibireme/YYCache" ~> 1.0 github "ibireme/YYImage" ~> 1.0 diff --git a/Example/Podfile.lock b/Example/Podfile.lock index dcdafc7..7cd8fe5 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,15 +1,15 @@ PODS: - Expecta (1.0.6) - - SDWebImage/Core (5.10.3) - - SDWebImageYYPlugin (0.6.0): - - SDWebImage/Core (~> 5.10) - - SDWebImageYYPlugin/YYCache (= 0.6.0) - - SDWebImageYYPlugin/YYImage (= 0.6.0) - - SDWebImageYYPlugin/YYCache (0.6.0): - - SDWebImage/Core (~> 5.10) + - SDWebImage/Core (5.15.0) + - SDWebImageYYPlugin (0.7.0): + - SDWebImage/Core (~> 5.15) + - SDWebImageYYPlugin/YYCache (= 0.7.0) + - SDWebImageYYPlugin/YYImage (= 0.7.0) + - SDWebImageYYPlugin/YYCache (0.7.0): + - SDWebImage/Core (~> 5.15) - YYCache - - SDWebImageYYPlugin/YYImage (0.6.0): - - SDWebImage/Core (~> 5.10) + - SDWebImageYYPlugin/YYImage (0.7.0): + - SDWebImage/Core (~> 5.15) - YYImage/Core - YYCache (1.0.4) - YYImage/Core (1.0.4) @@ -34,11 +34,11 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Expecta: 3b6bd90a64b9a1dcb0b70aa0e10a7f8f631667d5 - SDWebImage: e378178472b735e84b007bfb55514c97948a0598 - SDWebImageYYPlugin: 44e88320fc9604b6abb09d8271504bdd986dcf2e + SDWebImage: 9bec4c5cdd9579e1f57104735ee0c37df274d593 + SDWebImageYYPlugin: 9ff87103cef7b39ac608303d756f1ce9899b9012 YYCache: 8105b6638f5e849296c71f331ff83891a4942952 YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54 PODFILE CHECKSUM: 71679fe963dea37bf4e76ca762d8b118854ce524 -COCOAPODS: 1.8.4 +COCOAPODS: 1.11.3 diff --git a/README.md b/README.md index 7060a3e..9721a3b 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/SDWebImage/SDWebImageYYPlugin) [![codecov](https://codecov.io/gh/SDWebImage/SDWebImageYYPlugin/branch/master/graph/badge.svg)](https://codecov.io/gh/SDWebImage/SDWebImageYYPlugin) - ## What's for SDWebImageYYPlugin is a plugin for [SDWebImage](https://github.com/rs/SDWebImage/) framework, which provide the image loading support for [YYImage](https://github.com/ibireme/YYImage) (including YYImage's decoding system and `YYAnimatedImageView`) and [YYCache](https://github.com/ibireme/YYCache) cache system. @@ -15,6 +14,11 @@ By using SDWebImageYYPlugin, you can use all you familiar SDWebImage's loading m And you can also use `YYCache` instead of `SDImageCache` for image cache system, which may better memory cache performance (By taking advanced of LRU algorithm), and disk cache performance (By taking advanced of sqlite blob storage) +## Long term maintenance +This repo was created as a showcase how power the SDWebImage 5.0's customization can be. But actually is not recommended to use in commercial applications. + +Since the upstream YYImage/YYCache has no longer maintained, and SDWebImage itself has become more and more performant than previous versions. I will not always up-to-date the compatibility with SDWebImage's internal changes from version to version. This repo will be deprecated in the future (like SDWebImage 6.0). But the PR for bugfix is still welcomed. + ## Usage #### YYImage Plugin diff --git a/SDWebImageYYPlugin.podspec b/SDWebImageYYPlugin.podspec index d683b34..3523eff 100644 --- a/SDWebImageYYPlugin.podspec +++ b/SDWebImageYYPlugin.podspec @@ -31,7 +31,7 @@ TODO: Add long description of the pod here. s.source_files = 'SDWebImageYYPlugin/Module/SDWebImageYYPlugin.h' s.module_map = 'SDWebImageYYPlugin/Module/SDWebImageYYPlugin.modulemap' - s.dependency 'SDWebImage/Core', '~> 5.10' + s.dependency 'SDWebImage/Core', '~> 5.15' s.subspec 'YYCache' do |ss| ss.dependency 'YYCache' diff --git a/SDWebImageYYPlugin/Classes/YYCache/YYCacheBridge/YYCache+SDAdditions.m b/SDWebImageYYPlugin/Classes/YYCache/YYCacheBridge/YYCache+SDAdditions.m index 395d817..6580864 100644 --- a/SDWebImageYYPlugin/Classes/YYCache/YYCacheBridge/YYCache+SDAdditions.m +++ b/SDWebImageYYPlugin/Classes/YYCache/YYCacheBridge/YYCache+SDAdditions.m @@ -10,32 +10,66 @@ #import "YYMemoryCache+SDAdditions.h" #import "YYDiskCache+SDAdditions.h" -static NSData * SDYYPluginCacheDataWithImageData(UIImage *image, NSData *imageData) { - NSData *data = imageData; - if (!data && [image conformsToProtocol:@protocol(SDAnimatedImage)]) { - // If image is custom animated image class, prefer its original animated data - data = [((id)image) animatedImageData]; +static void SDYYPluginUnarchiveObject(NSData *data, UIImage *image) { + if (!data || !image) { + return; } - if (!data && image) { - // Check image's associated image format, may return .undefined - SDImageFormat format = image.sd_imageFormat; - if (format == SDImageFormatUndefined) { - // If image is animated, use GIF (APNG may be better, but has bugs before macOS 10.14) - if (image.sd_isAnimated) { - format = SDImageFormatGIF; - } else { - // If we do not have any data to detect image format, check whether it contains alpha channel to use PNG or JPEG format - if ([SDImageCoderHelper CGImageContainsAlpha:image.CGImage]) { - format = SDImageFormatPNG; - } else { - format = SDImageFormatJPEG; - } - } + // Check extended data + NSData *extendedData = [YYDiskCache getExtendedDataFromObject:data]; + if (!extendedData) { + return; + } + id extendedObject; + if (@available(iOS 11, tvOS 11, macOS 10.13, watchOS 4, *)) { + NSError *error; + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:extendedData error:&error]; + unarchiver.requiresSecureCoding = NO; + extendedObject = [unarchiver decodeTopLevelObjectForKey:NSKeyedArchiveRootObjectKey error:&error]; + if (error) { + NSLog(@"NSKeyedUnarchiver unarchive failed with error: %@", error); + } + } else { + @try { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + extendedObject = [NSKeyedUnarchiver unarchiveObjectWithData:extendedData]; +#pragma clang diagnostic pop + } @catch (NSException *exception) { + NSLog(@"NSKeyedUnarchiver unarchive failed with exception: %@", exception); } - data = [[SDImageCodersManager sharedManager] encodedDataWithImage:image format:format options:nil]; } - - return data; + image.sd_extendedObject = extendedObject; +} + +static void SDYYPluginArchiveObject(NSData *data, UIImage *image) { + if (!data || !image) { + return; + } + // Check extended data + id extendedObject = image.sd_extendedObject; + if (![extendedObject conformsToProtocol:@protocol(NSCoding)]) { + return; + } + NSData *extendedData; + if (@available(iOS 11, tvOS 11, macOS 10.13, watchOS 4, *)) { + NSError *error; + extendedData = [NSKeyedArchiver archivedDataWithRootObject:extendedObject requiringSecureCoding:NO error:&error]; + if (error) { + NSLog(@"NSKeyedArchiver archive failed with error: %@", error); + } + } else { + @try { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + extendedData = [NSKeyedArchiver archivedDataWithRootObject:extendedObject]; +#pragma clang diagnostic pop + } @catch (NSException *exception) { + NSLog(@"NSKeyedArchiver archive failed with exception: %@", exception); + } + } + if (extendedData) { + [YYDiskCache setExtendedData:extendedData toObject:data]; + } } @implementation YYCache (SDAdditions) @@ -68,8 +102,7 @@ @implementation YYCache (SDAdditions) if (image) { if (options & SDImageCacheDecodeFirstFrameOnly) { // Ensure static image - Class animatedImageClass = image.class; - if (image.sd_isAnimated || ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)])) { + if (image.sd_isAnimated) { #if SD_MAC image = [[NSImage alloc] initWithCGImage:image.CGImage scale:image.scale orientation:kCGImagePropertyOrientationUp]; #else @@ -95,176 +128,160 @@ @implementation YYCache (SDAdditions) } // Second check the disk cache... + SDCallbackQueue *queue = context[SDWebImageContextCallbackQueue]; NSOperation *operation = [NSOperation new]; // Check whether we need to synchronously query disk // 1. in-memory cache hit & memoryDataSync // 2. in-memory cache miss & diskDataSync BOOL shouldQueryDiskSync = ((image && options & SDImageCacheQueryMemoryDataSync) || (!image && options & SDImageCacheQueryDiskDataSync)); - void(^queryDiskBlock)(NSData *) = ^(NSData *diskData) { - if (operation.isCancelled) { - if (doneBlock) { - doneBlock(nil, nil, SDImageCacheTypeNone); + NSData* (^queryDiskDataBlock)(void) = ^NSData* { + @synchronized (operation) { + if (operation.isCancelled) { + return nil; } - return; } - @autoreleasepool { - UIImage *diskImage; - if (image) { - // the image is from in-memory cache, but need image data - diskImage = image; - } else if (diskData) { - BOOL shouldCacheToMomery = YES; - if (context[SDWebImageContextStoreCacheType]) { - SDImageCacheType cacheType = [context[SDWebImageContextStoreCacheType] integerValue]; - shouldCacheToMomery = (cacheType == SDImageCacheTypeAll || cacheType == SDImageCacheTypeMemory); - } - // decode image data only if in-memory cache missed - diskImage = SDImageCacheDecodeImageData(diskData, key, options, context); - if (diskImage) { - // Check extended data - NSData *extendedData = [YYDiskCache getExtendedDataFromObject:diskData]; - if (extendedData) { - id extendedObject; - if (@available(iOS 11, tvOS 11, macOS 10.13, watchOS 4, *)) { - NSError *error; - NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:extendedData error:&error]; - unarchiver.requiresSecureCoding = NO; - extendedObject = [unarchiver decodeTopLevelObjectForKey:NSKeyedArchiveRootObjectKey error:&error]; - if (error) { - NSLog(@"NSKeyedUnarchiver unarchive failed with error: %@", error); - } - } else { - @try { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - extendedObject = [NSKeyedUnarchiver unarchiveObjectWithData:extendedData]; -#pragma clang diagnostic pop - } @catch (NSException *exception) { - NSLog(@"NSKeyedUnarchiver unarchive failed with exception: %@", exception); - } - } - diskImage.sd_extendedObject = extendedObject; - } - } - if (shouldCacheToMomery && diskImage) { - NSUInteger cost = diskImage.sd_memoryCost; - [self.memoryCache setObject:diskImage forKey:key cost:cost]; - } + return [self.diskCache dataForKey:key]; + }; + UIImage* (^queryDiskImageBlock)(NSData*) = ^UIImage*(NSData* diskData) { + @synchronized (operation) { + if (operation.isCancelled) { + return nil; } - - if (doneBlock) { - if (shouldQueryDiskSync) { - doneBlock(diskImage, diskData, SDImageCacheTypeDisk); - } else { - dispatch_async(dispatch_get_main_queue(), ^{ - doneBlock(diskImage, diskData, SDImageCacheTypeDisk); - }); - } + } + + UIImage *diskImage; + if (image) { + // the image is from in-memory cache, but need image data + diskImage = image; + } else if (diskData) { + BOOL shouldCacheToMomery = YES; + if (context[SDWebImageContextStoreCacheType]) { + SDImageCacheType cacheType = [context[SDWebImageContextStoreCacheType] integerValue]; + shouldCacheToMomery = (cacheType == SDImageCacheTypeAll || cacheType == SDImageCacheTypeMemory); + } + CGSize thumbnailSize = CGSizeZero; + NSValue *thumbnailSizeValue = context[SDWebImageContextImageThumbnailPixelSize]; + if (thumbnailSizeValue != nil) { + #if SD_MAC + thumbnailSize = thumbnailSizeValue.sizeValue; + #else + thumbnailSize = thumbnailSizeValue.CGSizeValue; + #endif + } + if (thumbnailSize.width > 0 && thumbnailSize.height > 0) { + // Query full size cache key which generate a thumbnail, should not write back to full size memory cache + shouldCacheToMomery = NO; + } + // decode image data only if in-memory cache missed + diskImage = SDImageCacheDecodeImageData(diskData, key, options, context); + SDYYPluginUnarchiveObject(diskData, diskImage); + if (shouldCacheToMomery && diskImage) { + NSUInteger cost = diskImage.sd_memoryCost; + [self.memoryCache setObject:diskImage forKey:key cost:cost]; } } + return diskImage; }; + // YYCache has its own IO queue if (shouldQueryDiskSync) { - NSData *diskData = [self.diskCache dataForKey:key]; - queryDiskBlock(diskData); + NSData* diskData = queryDiskDataBlock(); + UIImage* diskImage = queryDiskImageBlock(diskData); + if (doneBlock) { + doneBlock(diskImage, diskData, SDImageCacheTypeDisk); + } } else { - // YYDiskCache's completion block is called in the global queue - [self.diskCache objectForKey:key withBlock:^(NSString * _Nonnull key, id _Nullable object) { - NSData *diskData = nil; - if ([(id)object isKindOfClass:[NSData class]]) { - diskData = (NSData *)object; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + NSData* diskData = queryDiskDataBlock(); + UIImage* diskImage = queryDiskImageBlock(diskData); + @synchronized (operation) { + if (operation.isCancelled) { + return; + } } - queryDiskBlock(diskData); - }]; + if (doneBlock) { + [(queue ?: SDCallbackQueue.mainQueue) async:^{ + // Dispatch from IO queue to main queue need time, user may call cancel during the dispatch timing + // This check is here to avoid double callback (one is from `SDImageCacheToken` in sync) + @synchronized (operation) { + if (operation.isCancelled) { + return; + } + } + doneBlock(diskImage, diskData, SDImageCacheTypeDisk); + }]; + } + }); } return operation; } -- (void)storeImageToDisk:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key completion:(SDWebImageNoParamsBlock)completionBlock { - NSData *data = SDYYPluginCacheDataWithImageData(image, imageData); - if (!data) { - // SDImageCache does not remove object if `data` is nil +- (void)storeImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock { + [self storeImage:image imageData:imageData forKey:key options:0 context:nil cacheType:cacheType completion:completionBlock]; +} + +- (void)storeImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key options:(SDWebImageOptions)options context:(SDWebImageContext *)context cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock { + if ((!image && !imageData) || !key) { if (completionBlock) { - dispatch_async(dispatch_get_main_queue(), ^{ - completionBlock(); - }); + completionBlock(); } return; } - if (image) { - // Check extended data - id extendedObject = image.sd_extendedObject; - if ([extendedObject conformsToProtocol:@protocol(NSCoding)]) { - NSData *extendedData; - if (@available(iOS 11, tvOS 11, macOS 10.13, watchOS 4, *)) { - NSError *error; - extendedData = [NSKeyedArchiver archivedDataWithRootObject:extendedObject requiringSecureCoding:NO error:&error]; - if (error) { - NSLog(@"NSKeyedArchiver archive failed with error: %@", error); - } - } else { - @try { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - extendedData = [NSKeyedArchiver archivedDataWithRootObject:extendedObject]; -#pragma clang diagnostic pop - } @catch (NSException *exception) { - NSLog(@"NSKeyedArchiver archive failed with exception: %@", exception); - } - } - if (extendedData) { - [YYDiskCache setExtendedData:extendedData toObject:data]; - } - } + BOOL toMemory = cacheType == SDImageCacheTypeMemory || cacheType == SDImageCacheTypeAll; + BOOL toDisk = cacheType == SDImageCacheTypeDisk || cacheType == SDImageCacheTypeAll; + // if memory cache is enabled + if (image && toMemory) { + NSUInteger cost = image.sd_memoryCost; + [self.memoryCache setObject:image forKey:key cost:cost]; } - [self.diskCache setObject:data forKey:key withBlock:^{ + + if (!toDisk) { if (completionBlock) { - dispatch_async(dispatch_get_main_queue(), ^{ - completionBlock(); - }); + completionBlock(); } - }]; -} - -- (void)storeImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSString *)key cacheType:(SDImageCacheType)cacheType completion:(SDWebImageNoParamsBlock)completionBlock { - switch (cacheType) { - case SDImageCacheTypeNone: { - if (completionBlock) { - completionBlock(); - } - } - break; - case SDImageCacheTypeMemory: { - NSUInteger cost = image.sd_memoryCost; - [self.memoryCache setObject:image forKey:key cost:cost]; - if (completionBlock) { - completionBlock(); + return; + } + NSData *data = imageData; + if (!data && [image respondsToSelector:@selector(animatedImageData)]) { + // If image is custom animated image class, prefer its original animated data + data = [((id)image) animatedImageData]; + } + SDCallbackQueue *queue = context[SDWebImageContextCallbackQueue]; + if (!data && image) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + // Check image's associated image format, may return .undefined + SDImageFormat format = image.sd_imageFormat; + if (format == SDImageFormatUndefined) { + // If image is animated, use GIF (APNG may be better, but has bugs before macOS 10.14) + if (image.sd_isAnimated) { + format = SDImageFormatGIF; + } else { + // If we do not have any data to detect image format, check whether it contains alpha channel to use PNG or JPEG format + format = [SDImageCoderHelper CGImageContainsAlpha:image.CGImage] ? SDImageFormatPNG : SDImageFormatJPEG; + } } - } - break; - case SDImageCacheTypeDisk: { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - [self storeImageToDisk:image imageData:imageData forKey:key completion:completionBlock]; - }); - } - break; - case SDImageCacheTypeAll: { - NSUInteger cost = image.sd_memoryCost; - [self.memoryCache setObject:image forKey:key cost:cost]; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - [self storeImageToDisk:image imageData:imageData forKey:key completion:completionBlock]; - }); - } - break; - default: { + NSData *data = [[SDImageCodersManager sharedManager] encodedDataWithImage:image format:format options:context[SDWebImageContextImageEncodeOptions]]; + SDYYPluginArchiveObject(data, image); + [self.diskCache setObject:data forKey:key withBlock:^{ + if (completionBlock) { + [(queue ?: SDCallbackQueue.mainQueue) async:^{ + completionBlock(); + }]; + } + }]; + }); + } else { + SDYYPluginArchiveObject(data, image); + [self.diskCache setObject:data forKey:key withBlock:^{ if (completionBlock) { - completionBlock(); + [(queue ?: SDCallbackQueue.mainQueue) async:^{ + completionBlock(); + }]; } - } - break; + }]; } } diff --git a/SDWebImageYYPlugin/Classes/YYImage/YYImageBridge/SDImageYYCoder.m b/SDWebImageYYPlugin/Classes/YYImage/YYImageBridge/SDImageYYCoder.m index ecec8d6..c40ac44 100644 --- a/SDWebImageYYPlugin/Classes/YYImage/YYImageBridge/SDImageYYCoder.m +++ b/SDWebImageYYPlugin/Classes/YYImage/YYImageBridge/SDImageYYCoder.m @@ -45,6 +45,7 @@ static inline SDImageFormat SDImageFormatFromYYImageType(YYImageType type) { @interface SDImageYYCoder () @property (nonatomic, strong) YYImageDecoder *decoder; +@property (nonatomic, assign) BOOL lazyDecode; @end @@ -123,6 +124,24 @@ - (BOOL)canEncodeToFormat:(SDImageFormat)format { } - (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format options:(SDImageCoderOptions *)options { + if (!image) { + return nil; + } + + NSArray *frames = [SDImageCoderHelper framesFromAnimatedImage:image]; + if (!frames || frames.count == 0) { + SDImageFrame *frame = [SDImageFrame frameWithImage:image duration:0]; + frames = @[frame]; + } + return [self encodedDataWithFrames:frames loopCount:image.sd_imageLoopCount format:format options:options]; +} + +- (NSData *)encodedDataWithFrames:(NSArray *)frames loopCount:(NSUInteger)loopCount format:(SDImageFormat)format options:(SDImageCoderOptions *)options { + UIImage *image = frames.firstObject.image; // Primary image + if (!image) { + return nil; + } + double compressionQuality = 1; if (options[SDImageCoderEncodeCompressionQuality]) { compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue]; @@ -133,15 +152,14 @@ - (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format o YYImageType type = YYImageTypeFromSDImageFormat(format); BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; - NSArray *frames = [SDImageCoderHelper framesFromAnimatedImage:image]; - if (encodeFirstFrame || frames.count == 0) { + if (encodeFirstFrame || frames.count <= 1) { // Static Image imageData = [YYImageEncoder encodeImage:image type:type quality:compressionQuality]; } else { // Animated Image YYImageEncoder *encoder = [[YYImageEncoder alloc] initWithType:type]; encoder.quality = compressionQuality; - encoder.loopCount = image.sd_imageLoopCount; + encoder.loopCount = loopCount; if (!encoder) { return nil; } @@ -152,7 +170,6 @@ - (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format o imageData = [encoder encode]; } - return imageData; } @@ -174,7 +191,17 @@ - (instancetype)initIncrementalWithOptions:(SDImageCoderOptions *)options { scale = 1; } } - self.decoder = [[YYImageDecoder alloc] initWithScale:scale]; + BOOL lazyDecode = NO; // Defaults NO for animated image coder + NSNumber *lazyDecodeValue = options[SDImageCoderDecodeUseLazyDecoding]; + if (lazyDecodeValue != nil) { + lazyDecode = lazyDecodeValue.boolValue; + } + _lazyDecode = lazyDecode; + YYImageDecoder *decoder = [[YYImageDecoder alloc] initWithScale:scale]; + if (!decoder) { + return nil; + } + _decoder = decoder; } return self; @@ -210,11 +237,17 @@ - (instancetype)initWithAnimatedImageData:(NSData *)data options:(SDImageCoderOp scale = 1; } } + BOOL lazyDecode = NO; // Defaults NO for animated image coder + NSNumber *lazyDecodeValue = options[SDImageCoderDecodeUseLazyDecoding]; + if (lazyDecodeValue != nil) { + lazyDecode = lazyDecodeValue.boolValue; + } + _lazyDecode = lazyDecode; YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:scale]; if (!decoder) { return nil; } - self.decoder = decoder; + _decoder = decoder; } return self; } @@ -232,7 +265,7 @@ - (NSUInteger)animatedImageLoopCount { } - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { - YYImageFrame *frame = [self.decoder frameAtIndex:index decodeForDisplay:NO]; + YYImageFrame *frame = [self.decoder frameAtIndex:index decodeForDisplay:!self.lazyDecode]; return frame.image; } diff --git a/SDWebImageYYPlugin/Classes/YYImage/YYImageBridge/YYImage+SDAdditions.m b/SDWebImageYYPlugin/Classes/YYImage/YYImageBridge/YYImage+SDAdditions.m index fe171f1..8c803ed 100644 --- a/SDWebImageYYPlugin/Classes/YYImage/YYImageBridge/YYImage+SDAdditions.m +++ b/SDWebImageYYPlugin/Classes/YYImage/YYImageBridge/YYImage+SDAdditions.m @@ -8,6 +8,24 @@ #import "YYImage+SDAdditions.h" #import +static inline SDImageFormat SDImageFormatFromYYImageType(YYImageType type) { + switch (type) { + case YYImageTypeJPEG: + case YYImageTypeJPEG2000: + return SDImageFormatJPEG; + case YYImageTypePNG: + return SDImageFormatPNG; + case YYImageTypeGIF: + return SDImageFormatGIF; + case YYImageTypeTIFF: + return SDImageFormatTIFF; + case YYImageTypeWebP: + return SDImageFormatWebP; + default: + return SDImageFormatUndefined; + } +} + @implementation YYImage (SDAdditions) #pragma mark - SDAnimatedImage @@ -80,21 +98,7 @@ - (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount { } - (SDImageFormat)sd_imageFormat { - switch (self.animatedImageType) { - case YYImageTypeJPEG: - case YYImageTypeJPEG2000: - return SDImageFormatJPEG; - case YYImageTypePNG: - return SDImageFormatPNG; - case YYImageTypeGIF: - return SDImageFormatGIF; - case YYImageTypeTIFF: - return SDImageFormatTIFF; - case YYImageTypeWebP: - return SDImageFormatWebP; - default: - return SDImageFormatUndefined; - } + return SDImageFormatFromYYImageType(self.animatedImageType); } - (void)setSd_imageFormat:(SDImageFormat)sd_imageFormat {