Added sd_isThumbnail to mark metadata, avoid the case when full size image request re-use the image from thumbnail decoding for the same URL

I think this is a temp workaround
This commit is contained in:
DreamPiggy 2022-06-23 18:46:21 +08:00
parent e7e9268a7e
commit 2c9290f109
7 changed files with 53 additions and 8 deletions

View File

@ -14,6 +14,8 @@
#import "SDInternalMacros.h"
UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context) {
NSCParameterAssert(imageData);
NSCParameterAssert(cacheKey);
UIImage *image;
BOOL decodeFirstFrame = SD_OPTIONS_CONTAINS(options, SDWebImageDecodeFirstFrameOnly);
NSNumber *scaleValue = context[SDWebImageContextImageScaleFactor];
@ -79,6 +81,8 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSS
if (shouldDecode) {
image = [SDImageCoderHelper decodedImageWithImage:image];
}
// mark the image as thumbnail, to let manager check whether to re-decode if needed
image.sd_isThumbnail = thumbnailSizeValue != nil;
}
return image;

View File

@ -311,11 +311,14 @@ static NSString * kSDCGImageDestinationRequestedFileSize = @"kCGImageDestination
// Which decode frames in time and reduce memory usage
if (thumbnailSize.width == 0 || thumbnailSize.height == 0) {
SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:data];
NSSize size = NSMakeSize(imageRep.pixelsWide / scale, imageRep.pixelsHigh / scale);
imageRep.size = size;
NSImage *animatedImage = [[NSImage alloc] initWithSize:size];
[animatedImage addRepresentation:imageRep];
return animatedImage;
if (imageRep) {
NSSize size = NSMakeSize(imageRep.pixelsWide / scale, imageRep.pixelsHigh / scale);
imageRep.size = size;
NSImage *animatedImage = [[NSImage alloc] initWithSize:size];
[animatedImage addRepresentation:imageRep];
animatedImage.sd_imageFormat = self.class.imageFormat;
return animatedImage;
}
}
#endif

View File

@ -106,6 +106,8 @@ UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NS
if (shouldDecode) {
image = [SDImageCoderHelper decodedImageWithImage:image];
}
// mark the image as thumbnail, to let manager check whether to re-decode if needed
image.sd_isThumbnail = thumbnailSizeValue != nil;
}
return image;
@ -204,6 +206,8 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im
}
// mark the image as progressive (completed one are not mark as progressive)
image.sd_isIncremental = !finished;
// mark the image as thumbnail, to let manager check whether to re-decode if needed
image.sd_isThumbnail = thumbnailSizeValue != nil;
}
return image;

View File

@ -510,7 +510,7 @@ static id<SDImageLoader> _defaultImageLoader;
// normally use the store cache type, but if target image is transformed, use original store cache type instead
SDImageCacheType targetStoreCacheType = shouldTransformImage ? originalStoreCacheType : storeCacheType;
UIImage *originalImage = downloadedImage;
BOOL thumbnailed = context[SDWebImageContextImageThumbnailPixelSize];
BOOL thumbnailed = context[SDWebImageContextImageThumbnailPixelSize] != nil;
if (thumbnailed) {
// Thumbnail decoding does not keep original image
// Here we only store the original data to disk for original cache key
@ -560,10 +560,16 @@ static id<SDImageLoader> _defaultImageLoader;
}
id<SDWebImageCacheSerializer> cacheSerializer = context[SDWebImageContextCacheSerializer];
// transformer check
BOOL shouldTransformImage = originalImage && transformer;
shouldTransformImage = shouldTransformImage && (!originalImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage));
shouldTransformImage = shouldTransformImage && (!originalImage.sd_isVector || (options & SDWebImageTransformVectorImage));
// if available, store transformed image to cache
// thumbnail check
// This exist when previous thumbnail pipeline callback into next full size pipeline, because we share the same URL download but need different image
// Actually this is a hack, we attach the metadata into image object, which should design a better concept like `ImageInfo` and keep that around
BOOL shouldDecodeFullImage = originalImage.sd_isThumbnail && context[SDWebImageContextImageThumbnailPixelSize] == nil;
if (shouldTransformImage) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
@autoreleasepool {
@ -587,6 +593,19 @@ static id<SDImageLoader> _defaultImageLoader;
}
}
});
} else if (shouldDecodeFullImage) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
@autoreleasepool {
// transformed/thumbnailed cache key
NSString *key = [self cacheKeyForURL:url context:context];
// disable thumbnail decoding
SDWebImageMutableContext *tempContext = [context mutableCopy];
tempContext[SDWebImageContextImageThumbnailPixelSize] = nil;
UIImage *originalImage = SDImageCacheDecodeImageData(originalData, key, options, tempContext);
// Continue store transform cache process
[self callStoreTransformCacheProcessForOperation:operation url:url options:options context:context image:originalImage data:originalData cacheType:cacheType transformed:NO finished:finished completed:completedBlock];
}
});
} else {
// Continue store transform cache process
[self callStoreTransformCacheProcessForOperation:operation url:url options:options context:context image:originalImage data:originalData cacheType:cacheType transformed:NO finished:finished completed:completedBlock];
@ -620,7 +639,7 @@ static id<SDImageLoader> _defaultImageLoader;
// but the storeImage does not handle the thumbnail context option
// to keep exist SDImageCache's impl compatible, we introduce this helper
NSData *cacheData = data;
BOOL thumbnailed = context[SDWebImageContextImageThumbnailPixelSize];
BOOL thumbnailed = context[SDWebImageContextImageThumbnailPixelSize] != nil;
if (thumbnailed) {
// Thumbnail decoding already stored original data before in `storeCacheProcess`
// Here we only store the thumbnail image to memory for thumbnail cache key

View File

@ -65,4 +65,9 @@
*/
@property (nonatomic, assign) BOOL sd_isIncremental;
/**
A bool value indicating whether the image is from thumbnail decoding and may be smaller than the full image data pixel size.
*/
@property (nonatomic, assign) BOOL sd_isThumbnail;
@end

View File

@ -186,4 +186,13 @@
return value.boolValue;
}
- (void)setSd_isThumbnail:(BOOL)sd_isThumbnail {
objc_setAssociatedObject(self, @selector(sd_isThumbnail), @(sd_isThumbnail), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)sd_isThumbnail {
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_isThumbnail));
return value.boolValue;
}
@end

View File

@ -18,6 +18,7 @@ void SDImageCopyAssociatedObject(UIImage * _Nullable source, UIImage * _Nullable
}
// Image Metadata
target.sd_isIncremental = source.sd_isIncremental;
target.sd_isThumbnail = source.sd_isThumbnail;
target.sd_imageLoopCount = source.sd_imageLoopCount;
target.sd_imageFormat = source.sd_imageFormat;
// Force Decode