Allows the transformer to preserve the UIImage metadata like image format (#3688)

* Allows the transformer to preserve the UIImage metadata like image format

This can make it by defaults to still use JPEG encoding for JPEG thumbnail image

* Update the test case for preserveImageMetadata

* Fix the `sd_isTransformed` metadata
This commit is contained in:
DreamPiggy 2024-03-25 16:57:35 +08:00 committed by GitHub
parent b557de276d
commit b156318507
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 46 additions and 2 deletions

View File

@ -36,6 +36,17 @@ FOUNDATION_EXPORT NSString * _Nullable SDThumbnailedKeyForKey(NSString * _Nullab
*/
@protocol SDImageTransformer <NSObject>
@optional
/**
Defaults to YES.
We keep some metadata like Image Format (`sd_imageFormat`)/ Animated Loop Count (`sd_imageLoopCount`) via associated object on UIImage instance.
When transformer generate a new UIImage instance, in most cases you still want to keep these information. So this is what for during the image loading pipeline.
If the value is YES, we will keep and override the metadata **After you generate the UIImage**
If the value is NO, we will not touch the UIImage metadata and it's controlled by you during the generation. Read `UIImage+Medata.h` and pick the metadata you want for the new generated UIImage.
*/
@property (nonatomic, assign, readonly) BOOL preserveImageMetadata;
@required
/**
For each transformer, it must contains its cache key to used to store the image cache or query from the cache. This key will be appened after the original cache key generated by URL or from user.

View File

@ -510,6 +510,16 @@ static id<SDImageLoader> _defaultImageLoader;
// Case that transformer on thumbnail, which this time need full pixel image
UIImage *transformedImage = [transformer transformedImageWithImage:cacheImage forKey:key];
if (transformedImage) {
// We need keep some metadata from the full size image when needed
// Because most of our transformer does not care about these information
BOOL preserveImageMetadata = YES;
if ([transformer respondsToSelector:@selector(preserveImageMetadata)]) {
preserveImageMetadata = transformer.preserveImageMetadata;
}
if (preserveImageMetadata) {
SDImageCopyAssociatedObject(cacheImage, transformedImage);
}
// Mark the transformed
transformedImage.sd_isTransformed = YES;
[self callStoreOriginCacheProcessForOperation:operation url:url options:options context:context originalImage:originalImage cacheImage:transformedImage originalData:originalData cacheData:nil cacheType:cacheType finished:finished completed:completedBlock];
} else {

View File

@ -132,10 +132,16 @@
- (void)test08ThatImageTransformerWork {
XCTestExpectation *expectation = [self expectationWithDescription:@"Image transformer work"];
NSURL *url = [NSURL URLWithString:@"https://placehold.co/80x60.png"];
NSURL *url = [NSURL URLWithString:@"https://placehold.co/80x60.jpg"];
SDWebImageTestTransformer *transformer = [[SDWebImageTestTransformer alloc] init];
transformer.preserveImageMetadata = YES; // preserve metadata
NSData *extData = [@"Foobar" dataUsingEncoding:NSUTF8StringEncoding];
transformer.testImage = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]];
CGSize transformSize = CGSizeMake(40, 30);
UIImage *testImage = [[[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]] sd_resizedImageWithSize:transformSize scaleMode:SDImageScaleModeFill];
testImage.sd_imageFormat = SDImageFormatUndefined;
testImage.sd_extendedObject = extData;
transformer.testImage = testImage;
SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"Transformer"];
SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:cache loader:SDWebImageDownloader.sharedDownloader];
NSString *key = [manager cacheKeyForURL:url];
@ -150,6 +156,12 @@
SDImageCoderOptions *encodeOptions = @{SDImageCoderEncodeMaxPixelSize : @(CGSizeMake(40, 30))};
[manager loadImageWithURL:url options:SDWebImageTransformAnimatedImage | SDWebImageTransformVectorImage | SDWebImageWaitStoreCache context:@{SDWebImageContextImageEncodeOptions : encodeOptions} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
expect(image).equal(transformer.testImage);
// Test metadata
expect(image.size).equal(transformSize);
expect(image.sd_isTransformed).equal(YES);
expect(image.sd_imageFormat).equal(SDImageFormatJPEG); // override from full image
expect(image.sd_extendedObject).beNil(); // override from full image
// Query the encoded data again
NSData *encodedData = [cache diskImageDataForKey:transformedKey];
UIImage *encodedImage = [UIImage sd_imageWithData:encodedData];
@ -256,6 +268,7 @@
SDWebImageManager *manager = [[SDWebImageManager alloc] initWithCache:cache loader:SDWebImageDownloader.sharedDownloader];
SDWebImageTestTransformer *transformer = [[SDWebImageTestTransformer alloc] init];
transformer.testImage = [[UIImage alloc] initWithContentsOfFile:[self testJPEGPath]];
transformer.preserveImageMetadata = NO; // the transformed image should not inherite any attribute from original one
manager.transformer = transformer;
// test: original image -> disk only, transformed image -> memory only

View File

@ -11,6 +11,8 @@
@interface SDWebImageTestTransformer : NSObject <SDImageTransformer>
@property (nonatomic, assign) BOOL preserveImageMetadata;
@property (nonatomic, strong, nullable) UIImage *testImage;
@end

View File

@ -11,6 +11,14 @@
@implementation SDWebImageTestTransformer
- (instancetype)init {
self = [super init];
if (self) {
_preserveImageMetadata = YES;
}
return self;
}
- (NSString *)transformerKey {
return @"SDWebImageTestTransformer";
}