SDImageCacheDefine.m 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. * This file is part of the SDWebImage package.
  3. * (c) Olivier Poitrey <rs@dailymotion.com>
  4. *
  5. * For the full copyright and license information, please view the LICENSE
  6. * file that was distributed with this source code.
  7. */
  8. #import "SDImageCacheDefine.h"
  9. #import "SDImageCodersManager.h"
  10. #import "SDImageCoderHelper.h"
  11. #import "SDAnimatedImage.h"
  12. #import "UIImage+Metadata.h"
  13. #import "SDInternalMacros.h"
  14. #import <CoreServices/CoreServices.h>
  15. SDImageCoderOptions * _Nonnull SDGetDecodeOptionsFromContext(SDWebImageContext * _Nullable context, SDWebImageOptions options, NSString * _Nonnull cacheKey) {
  16. BOOL decodeFirstFrame = SD_OPTIONS_CONTAINS(options, SDWebImageDecodeFirstFrameOnly);
  17. NSNumber *scaleValue = context[SDWebImageContextImageScaleFactor];
  18. CGFloat scale = scaleValue.doubleValue >= 1 ? scaleValue.doubleValue : SDImageScaleFactorForKey(cacheKey); // Use cache key to detect scale
  19. NSNumber *preserveAspectRatioValue = context[SDWebImageContextImagePreserveAspectRatio];
  20. NSValue *thumbnailSizeValue;
  21. BOOL shouldScaleDown = SD_OPTIONS_CONTAINS(options, SDWebImageScaleDownLargeImages);
  22. NSNumber *scaleDownLimitBytesValue = context[SDWebImageContextImageScaleDownLimitBytes];
  23. if (!scaleDownLimitBytesValue && shouldScaleDown) {
  24. // Use the default limit bytes
  25. scaleDownLimitBytesValue = @(SDImageCoderHelper.defaultScaleDownLimitBytes);
  26. }
  27. if (context[SDWebImageContextImageThumbnailPixelSize]) {
  28. thumbnailSizeValue = context[SDWebImageContextImageThumbnailPixelSize];
  29. }
  30. NSString *typeIdentifierHint = context[SDWebImageContextImageTypeIdentifierHint];
  31. NSString *fileExtensionHint;
  32. if (!typeIdentifierHint) {
  33. // UTI has high priority
  34. fileExtensionHint = cacheKey.pathExtension; // without dot
  35. if (fileExtensionHint.length == 0) {
  36. // Ignore file extension which is empty
  37. fileExtensionHint = nil;
  38. }
  39. }
  40. // First check if user provided decode options
  41. SDImageCoderMutableOptions *mutableCoderOptions;
  42. if (context[SDWebImageContextImageDecodeOptions] != nil) {
  43. mutableCoderOptions = [NSMutableDictionary dictionaryWithDictionary:context[SDWebImageContextImageDecodeOptions]];
  44. } else {
  45. mutableCoderOptions = [NSMutableDictionary dictionaryWithCapacity:6];
  46. }
  47. // Override individual options
  48. mutableCoderOptions[SDImageCoderDecodeFirstFrameOnly] = @(decodeFirstFrame);
  49. mutableCoderOptions[SDImageCoderDecodeScaleFactor] = @(scale);
  50. mutableCoderOptions[SDImageCoderDecodePreserveAspectRatio] = preserveAspectRatioValue;
  51. mutableCoderOptions[SDImageCoderDecodeThumbnailPixelSize] = thumbnailSizeValue;
  52. mutableCoderOptions[SDImageCoderDecodeTypeIdentifierHint] = typeIdentifierHint;
  53. mutableCoderOptions[SDImageCoderDecodeFileExtensionHint] = fileExtensionHint;
  54. mutableCoderOptions[SDImageCoderDecodeScaleDownLimitBytes] = scaleDownLimitBytesValue;
  55. return [mutableCoderOptions copy];
  56. }
  57. void SDSetDecodeOptionsToContext(SDWebImageMutableContext * _Nonnull mutableContext, SDWebImageOptions * _Nonnull mutableOptions, SDImageCoderOptions * _Nonnull decodeOptions) {
  58. if ([decodeOptions[SDImageCoderDecodeFirstFrameOnly] boolValue]) {
  59. *mutableOptions |= SDWebImageDecodeFirstFrameOnly;
  60. } else {
  61. *mutableOptions &= ~SDWebImageDecodeFirstFrameOnly;
  62. }
  63. mutableContext[SDWebImageContextImageScaleFactor] = decodeOptions[SDImageCoderDecodeScaleFactor];
  64. mutableContext[SDWebImageContextImagePreserveAspectRatio] = decodeOptions[SDImageCoderDecodePreserveAspectRatio];
  65. mutableContext[SDWebImageContextImageThumbnailPixelSize] = decodeOptions[SDImageCoderDecodeThumbnailPixelSize];
  66. mutableContext[SDWebImageContextImageScaleDownLimitBytes] = decodeOptions[SDImageCoderDecodeScaleDownLimitBytes];
  67. NSString *typeIdentifierHint = decodeOptions[SDImageCoderDecodeTypeIdentifierHint];
  68. if (!typeIdentifierHint) {
  69. NSString *fileExtensionHint = decodeOptions[SDImageCoderDecodeFileExtensionHint];
  70. if (fileExtensionHint) {
  71. typeIdentifierHint = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtensionHint, kUTTypeImage);
  72. // Ignore dynamic UTI
  73. if (UTTypeIsDynamic((__bridge CFStringRef)typeIdentifierHint)) {
  74. typeIdentifierHint = nil;
  75. }
  76. }
  77. }
  78. mutableContext[SDWebImageContextImageTypeIdentifierHint] = typeIdentifierHint;
  79. }
  80. UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSString * _Nonnull cacheKey, SDWebImageOptions options, SDWebImageContext * _Nullable context) {
  81. NSCParameterAssert(imageData);
  82. NSCParameterAssert(cacheKey);
  83. UIImage *image;
  84. SDImageCoderOptions *coderOptions = SDGetDecodeOptionsFromContext(context, options, cacheKey);
  85. BOOL decodeFirstFrame = SD_OPTIONS_CONTAINS(options, SDWebImageDecodeFirstFrameOnly);
  86. CGFloat scale = [coderOptions[SDImageCoderDecodeScaleFactor] doubleValue];
  87. // Grab the image coder
  88. id<SDImageCoder> imageCoder = context[SDWebImageContextImageCoder];
  89. if (!imageCoder) {
  90. imageCoder = [SDImageCodersManager sharedManager];
  91. }
  92. if (!decodeFirstFrame) {
  93. Class animatedImageClass = context[SDWebImageContextAnimatedImageClass];
  94. // check whether we should use `SDAnimatedImage`
  95. if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) {
  96. image = [[animatedImageClass alloc] initWithData:imageData scale:scale options:coderOptions];
  97. if (image) {
  98. // Preload frames if supported
  99. if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
  100. [((id<SDAnimatedImage>)image) preloadAllFrames];
  101. }
  102. } else {
  103. // Check image class matching
  104. if (options & SDWebImageMatchAnimatedImageClass) {
  105. return nil;
  106. }
  107. }
  108. }
  109. }
  110. if (!image) {
  111. image = [imageCoder decodedImageWithData:imageData options:coderOptions];
  112. }
  113. if (image) {
  114. SDImageForceDecodePolicy policy = SDImageForceDecodePolicyAutomatic;
  115. NSNumber *polivyValue = context[SDWebImageContextImageForceDecodePolicy];
  116. if (polivyValue != nil) {
  117. policy = polivyValue.unsignedIntegerValue;
  118. }
  119. // TODO: Deprecated, remove in SD 6.0...
  120. #pragma clang diagnostic push
  121. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  122. if (SD_OPTIONS_CONTAINS(options, SDWebImageAvoidDecodeImage)) {
  123. policy = SDImageForceDecodePolicyNever;
  124. }
  125. #pragma clang diagnostic pop
  126. image = [SDImageCoderHelper decodedImageWithImage:image policy:policy];
  127. // assign the decode options, to let manager check whether to re-decode if needed
  128. image.sd_decodeOptions = coderOptions;
  129. }
  130. return image;
  131. }