Files
keyboard/Pods/SDWebImage/SDWebImage/Core/SDImageCacheDefine.m
2025-10-27 21:55:05 +08:00

154 lines
7.4 KiB
Objective-C

/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDImageCacheDefine.h"
#import "SDImageCodersManager.h"
#import "SDImageCoderHelper.h"
#import "SDAnimatedImage.h"
#import "UIImage+Metadata.h"
#import "SDInternalMacros.h"
#import "SDDeviceHelper.h"
#import <CoreServices/CoreServices.h>
SDImageCoderOptions * _Nonnull SDGetDecodeOptionsFromContext(SDWebImageContext * _Nullable context, SDWebImageOptions options, NSString * _Nonnull cacheKey) {
BOOL decodeFirstFrame = SD_OPTIONS_CONTAINS(options, SDWebImageDecodeFirstFrameOnly);
NSNumber *scaleValue = context[SDWebImageContextImageScaleFactor];
CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); // Use cache key to detect scale
NSNumber *preserveAspectRatioValue = context[SDWebImageContextImagePreserveAspectRatio];
NSValue *thumbnailSizeValue;
BOOL shouldScaleDown = SD_OPTIONS_CONTAINS(options, SDWebImageScaleDownLargeImages);
NSNumber *scaleDownLimitBytesValue = context[SDWebImageContextImageScaleDownLimitBytes];
if (scaleDownLimitBytesValue == nil && shouldScaleDown) {
// Use the default limit bytes
scaleDownLimitBytesValue = @(SDImageCoderHelper.defaultScaleDownLimitBytes);
}
if (context[SDWebImageContextImageThumbnailPixelSize]) {
thumbnailSizeValue = context[SDWebImageContextImageThumbnailPixelSize];
}
NSString *typeIdentifierHint = context[SDWebImageContextImageTypeIdentifierHint];
NSString *fileExtensionHint;
if (!typeIdentifierHint) {
// UTI has high priority
fileExtensionHint = cacheKey.pathExtension; // without dot
if (fileExtensionHint.length == 0) {
// Ignore file extension which is empty
fileExtensionHint = nil;
}
}
// First check if user provided decode options
SDImageCoderMutableOptions *mutableCoderOptions;
if (context[SDWebImageContextImageDecodeOptions] != nil) {
mutableCoderOptions = [NSMutableDictionary dictionaryWithDictionary:context[SDWebImageContextImageDecodeOptions]];
} else {
mutableCoderOptions = [NSMutableDictionary dictionaryWithCapacity:6];
}
// Some options need preserve the custom decode options
NSNumber *decodeToHDR = context[SDWebImageContextImageDecodeToHDR];
if (decodeToHDR == nil) {
decodeToHDR = mutableCoderOptions[SDImageCoderDecodeToHDR];
}
// Override individual options
mutableCoderOptions[SDImageCoderDecodeFirstFrameOnly] = @(decodeFirstFrame);
mutableCoderOptions[SDImageCoderDecodeScaleFactor] = @(scale);
mutableCoderOptions[SDImageCoderDecodePreserveAspectRatio] = preserveAspectRatioValue;
mutableCoderOptions[SDImageCoderDecodeThumbnailPixelSize] = thumbnailSizeValue;
mutableCoderOptions[SDImageCoderDecodeTypeIdentifierHint] = typeIdentifierHint;
mutableCoderOptions[SDImageCoderDecodeFileExtensionHint] = fileExtensionHint;
mutableCoderOptions[SDImageCoderDecodeScaleDownLimitBytes] = scaleDownLimitBytesValue;
mutableCoderOptions[SDImageCoderDecodeToHDR] = decodeToHDR;
return [mutableCoderOptions copy];
}
void SDSetDecodeOptionsToContext(SDWebImageMutableContext * _Nonnull mutableContext, SDWebImageOptions * _Nonnull mutableOptions, SDImageCoderOptions * _Nonnull decodeOptions) {
if ([decodeOptions[SDImageCoderDecodeFirstFrameOnly] boolValue]) {
*mutableOptions |= SDWebImageDecodeFirstFrameOnly;
} else {
*mutableOptions &= ~SDWebImageDecodeFirstFrameOnly;
}
mutableContext[SDWebImageContextImageScaleFactor] = decodeOptions[SDImageCoderDecodeScaleFactor];
mutableContext[SDWebImageContextImagePreserveAspectRatio] = decodeOptions[SDImageCoderDecodePreserveAspectRatio];
mutableContext[SDWebImageContextImageThumbnailPixelSize] = decodeOptions[SDImageCoderDecodeThumbnailPixelSize];
mutableContext[SDWebImageContextImageScaleDownLimitBytes] = decodeOptions[SDImageCoderDecodeScaleDownLimitBytes];
mutableContext[SDWebImageContextImageDecodeToHDR] = decodeOptions[SDImageCoderDecodeToHDR];
NSString *typeIdentifierHint = decodeOptions[SDImageCoderDecodeTypeIdentifierHint];
if (!typeIdentifierHint) {
NSString *fileExtensionHint = decodeOptions[SDImageCoderDecodeFileExtensionHint];
if (fileExtensionHint) {
typeIdentifierHint = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtensionHint, kUTTypeImage);
// Ignore dynamic UTI
if (UTTypeIsDynamic((__bridge CFStringRef)typeIdentifierHint)) {
typeIdentifierHint = nil;
}
}
}
mutableContext[SDWebImageContextImageTypeIdentifierHint] = typeIdentifierHint;
}
UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context) {
NSCParameterAssert(imageData);
NSCParameterAssert(cacheKey);
UIImage *image;
SDImageCoderOptions *coderOptions = SDGetDecodeOptionsFromContext(context, options, cacheKey);
BOOL decodeFirstFrame = SD_OPTIONS_CONTAINS(options, SDWebImageDecodeFirstFrameOnly);
CGFloat scale = [coderOptions[SDImageCoderDecodeScaleFactor] doubleValue];
// Grab the image coder
id<SDImageCoder> imageCoder = context[SDWebImageContextImageCoder];
if (!imageCoder) {
imageCoder = [SDImageCodersManager sharedManager];
}
if (!decodeFirstFrame) {
Class animatedImageClass = context[SDWebImageContextAnimatedImageClass];
// check whether we should use `SDAnimatedImage`
if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) {
image = [[animatedImageClass alloc] initWithData:imageData scale:scale options:coderOptions];
if (image) {
// Preload frames if supported
if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
[((id<SDAnimatedImage>)image) preloadAllFrames];
}
} else {
// Check image class matching
if (options & SDWebImageMatchAnimatedImageClass) {
return nil;
}
}
}
}
if (!image) {
image = [imageCoder decodedImageWithData:imageData options:coderOptions];
}
if (image) {
SDImageForceDecodePolicy policy = SDImageForceDecodePolicyAutomatic;
NSNumber *policyValue = context[SDWebImageContextImageForceDecodePolicy];
if (policyValue != nil) {
policy = policyValue.unsignedIntegerValue;
}
// TODO: Deprecated, remove in SD 6.0...
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
if (SD_OPTIONS_CONTAINS(options, SDWebImageAvoidDecodeImage)) {
policy = SDImageForceDecodePolicyNever;
}
#pragma clang diagnostic pop
image = [SDImageCoderHelper decodedImageWithImage:image policy:policy];
// assign the decode options, to let manager check whether to re-decode if needed
image.sd_decodeOptions = coderOptions;
}
return image;
}