From 5a32da7953adfb6c5da58c6b1599aa5c7483c3c1 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Tue, 17 Apr 2018 20:04:59 +0800 Subject: [PATCH] Move the complicated built-in decode process into a global function to allow user who custom web cache use it --- SDWebImage/SDImageCache.m | 47 +++++++++------------------------- SDWebImage/SDWebImageCache.h | 12 +++++++++ SDWebImage/SDWebImageCache.m | 49 ++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 35 deletions(-) diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index c1d8eb6b..dd92e8e4 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -317,41 +317,7 @@ - (nullable UIImage *)diskImageForKey:(nullable NSString *)key data:(nullable NSData *)data options:(SDImageCacheOptions)options context:(SDWebImageContext *)context { if (data) { - UIImage *image; - BOOL decodeFirstFrame = options & SDImageCacheDecodeFirstFrameOnly; - NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; - CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(key); - if (!decodeFirstFrame) { - // check whether we should use `SDAnimatedImage` - if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { - Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass]; - if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { - image = [[animatedImageClass alloc] initWithData:data scale:scale]; - if (options & SDImageCachePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { - [((id)image) preloadAllFrames]; - } - } - } - } - if (!image) { - image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:data options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; - } - BOOL shouldDecode = (options & SDImageCacheAvoidDecodeImage) == 0; - if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { - // `SDAnimatedImage` do not decode - shouldDecode = NO; - } else if (image.sd_isAnimated) { - // animated image do not decode - shouldDecode = NO; - } - if (shouldDecode) { - BOOL shouldScaleDown = options & SDImageCacheScaleDownLargeImages; - if (shouldScaleDown) { - image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; - } else { - image = [SDWebImageCoderHelper decodedImageWithImage:image]; - } - } + UIImage *image = SDWebImageCacheDecodeImageData(data, key, [[self class] imageOptionsFromCacheOptions:options], context); return image; } else { return nil; @@ -589,6 +555,17 @@ }); } +#pragma mark - Helper ++ (SDWebImageOptions)imageOptionsFromCacheOptions:(SDImageCacheOptions)cacheOptions { + SDWebImageOptions options = 0; + if (cacheOptions & SDImageCacheScaleDownLargeImages) options |= SDWebImageScaleDownLargeImages; + if (cacheOptions & SDImageCacheDecodeFirstFrameOnly) options |= SDWebImageDecodeFirstFrameOnly; + if (cacheOptions & SDImageCachePreloadAllFrames) options |= SDWebImagePreloadAllFrames; + if (cacheOptions & SDImageCacheAvoidDecodeImage) options |= SDWebImageAvoidDecodeImage; + + return options; +} + @end @implementation SDImageCache (SDWebImageCache) diff --git a/SDWebImage/SDWebImageCache.h b/SDWebImage/SDWebImageCache.h index ed101362..c5aeb0b4 100644 --- a/SDWebImage/SDWebImageCache.h +++ b/SDWebImage/SDWebImageCache.h @@ -37,6 +37,18 @@ typedef NS_ENUM(NSInteger, SDImageCacheType) { typedef void(^SDImageCacheQueryCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); typedef void(^SDImageCacheContainsCompletionBlock)(SDImageCacheType containsCacheType); +/** + This is the built-in decoding process for image query from cache. + @note If you want to implement your custom loader with `queryImageForKey:options:context:completion:` API, but also want to keep compatible with SDWebImage's behavior, you'd better use this to produce image. + + @param imageData The image data from the cache. Should not be nil + @param cacheKey The image cache key from the input. Should not be nil + @param options The options arg from the input + @param context The context arg from the input + @return The decoded image for current image data query from cache + */ +FOUNDATION_EXPORT UIImage * _Nullable SDWebImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context); + /** This is the image cache protocol to provide custom image cache for `SDWebImageManager`. Though the best practice to custom image cache, is to write your own class which conform `SDMemoryCache` or `SDDiskCache` protocol for `SDImageCache` class (See more on `SDImageCacheConfig.memoryCacheClass & SDImageCacheConfig.diskCacheClass`). diff --git a/SDWebImage/SDWebImageCache.m b/SDWebImage/SDWebImageCache.m index 8203e7bd..bfd67063 100644 --- a/SDWebImage/SDWebImageCache.m +++ b/SDWebImage/SDWebImageCache.m @@ -7,3 +7,52 @@ */ #import "SDWebImageCache.h" +#import "SDWebImageCodersManager.h" +#import "SDWebImageCoderHelper.h" +#import "SDAnimatedImage.h" +#import "UIImage+WebCache.h" + +UIImage * _Nullable SDWebImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context) { + UIImage *image; + BOOL decodeFirstFrame = options & SDWebImageDecodeFirstFrameOnly; + NSNumber *scaleValue = [context valueForKey:SDWebImageContextImageScaleFactor]; + CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); + if (scale < 1) { + scale = 1; + } + if (!decodeFirstFrame) { + // check whether we should use `SDAnimatedImage` + if ([context valueForKey:SDWebImageContextAnimatedImageClass]) { + Class animatedImageClass = [context valueForKey:SDWebImageContextAnimatedImageClass]; + if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) { + image = [[animatedImageClass alloc] initWithData:imageData scale:scale]; + if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) { + [((id)image) preloadAllFrames]; + } + } + } + } + if (!image) { + image = [[SDWebImageCodersManager sharedManager] decodedImageWithData:imageData options:@{SDWebImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDWebImageCoderDecodeScaleFactor : @(scale)}]; + } + if (image) { + BOOL shouldDecode = (options & SDWebImageAvoidDecodeImage) == 0; + if ([image conformsToProtocol:@protocol(SDAnimatedImage)]) { + // `SDAnimatedImage` do not decode + shouldDecode = NO; + } else if (image.sd_isAnimated) { + // animated image do not decode + shouldDecode = NO; + } + if (shouldDecode) { + BOOL shouldScaleDown = options & SDWebImageScaleDownLargeImages; + if (shouldScaleDown) { + image = [SDWebImageCoderHelper decodedAndScaledDownImageWithImage:image limitBytes:0]; + } else { + image = [SDWebImageCoderHelper decodedImageWithImage:image]; + } + } + } + + return image; +}