SDImageTransformer.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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 "SDImageTransformer.h"
  9. #import "UIColor+SDHexString.h"
  10. #if SD_UIKIT || SD_MAC
  11. #import <CoreImage/CoreImage.h>
  12. #endif
  13. // Separator for different transformerKey, for example, `image.png` |> flip(YES,NO) |> rotate(pi/4,YES) => 'image-SDImageFlippingTransformer(1,0)-SDImageRotationTransformer(0.78539816339,1).png'
  14. static NSString * const SDImageTransformerKeySeparator = @"-";
  15. NSString * _Nullable SDTransformedKeyForKey(NSString * _Nullable key, NSString * _Nonnull transformerKey) {
  16. if (!key || !transformerKey) {
  17. return nil;
  18. }
  19. // Find the file extension
  20. NSURL *keyURL = [NSURL URLWithString:key];
  21. NSString *ext = keyURL ? keyURL.pathExtension : key.pathExtension;
  22. if (ext.length > 0) {
  23. // For non-file URL
  24. if (keyURL && !keyURL.isFileURL) {
  25. // keep anything except path (like URL query)
  26. NSURLComponents *component = [NSURLComponents componentsWithURL:keyURL resolvingAgainstBaseURL:NO];
  27. component.path = [[[component.path.stringByDeletingPathExtension stringByAppendingString:SDImageTransformerKeySeparator] stringByAppendingString:transformerKey] stringByAppendingPathExtension:ext];
  28. return component.URL.absoluteString;
  29. } else {
  30. // file URL
  31. return [[[key.stringByDeletingPathExtension stringByAppendingString:SDImageTransformerKeySeparator] stringByAppendingString:transformerKey] stringByAppendingPathExtension:ext];
  32. }
  33. } else {
  34. return [[key stringByAppendingString:SDImageTransformerKeySeparator] stringByAppendingString:transformerKey];
  35. }
  36. }
  37. NSString * _Nullable SDThumbnailedKeyForKey(NSString * _Nullable key, CGSize thumbnailPixelSize, BOOL preserveAspectRatio) {
  38. NSString *thumbnailKey = [NSString stringWithFormat:@"Thumbnail({%f,%f},%d)", thumbnailPixelSize.width, thumbnailPixelSize.height, preserveAspectRatio];
  39. return SDTransformedKeyForKey(key, thumbnailKey);
  40. }
  41. @interface SDImagePipelineTransformer ()
  42. @property (nonatomic, copy, readwrite, nonnull) NSArray<id<SDImageTransformer>> *transformers;
  43. @property (nonatomic, copy, readwrite) NSString *transformerKey;
  44. @end
  45. @implementation SDImagePipelineTransformer
  46. + (instancetype)transformerWithTransformers:(NSArray<id<SDImageTransformer>> *)transformers {
  47. SDImagePipelineTransformer *transformer = [SDImagePipelineTransformer new];
  48. transformer.transformers = transformers;
  49. transformer.transformerKey = [[self class] cacheKeyForTransformers:transformers];
  50. return transformer;
  51. }
  52. + (NSString *)cacheKeyForTransformers:(NSArray<id<SDImageTransformer>> *)transformers {
  53. if (transformers.count == 0) {
  54. return @"";
  55. }
  56. NSMutableArray<NSString *> *cacheKeys = [NSMutableArray arrayWithCapacity:transformers.count];
  57. [transformers enumerateObjectsUsingBlock:^(id<SDImageTransformer> _Nonnull transformer, NSUInteger idx, BOOL * _Nonnull stop) {
  58. NSString *cacheKey = transformer.transformerKey;
  59. [cacheKeys addObject:cacheKey];
  60. }];
  61. return [cacheKeys componentsJoinedByString:SDImageTransformerKeySeparator];
  62. }
  63. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  64. if (!image) {
  65. return nil;
  66. }
  67. UIImage *transformedImage = image;
  68. for (id<SDImageTransformer> transformer in self.transformers) {
  69. transformedImage = [transformer transformedImageWithImage:transformedImage forKey:key];
  70. }
  71. return transformedImage;
  72. }
  73. @end
  74. @interface SDImageRoundCornerTransformer ()
  75. @property (nonatomic, assign) CGFloat cornerRadius;
  76. @property (nonatomic, assign) SDRectCorner corners;
  77. @property (nonatomic, assign) CGFloat borderWidth;
  78. @property (nonatomic, strong, nullable) UIColor *borderColor;
  79. @end
  80. @implementation SDImageRoundCornerTransformer
  81. + (instancetype)transformerWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor {
  82. SDImageRoundCornerTransformer *transformer = [SDImageRoundCornerTransformer new];
  83. transformer.cornerRadius = cornerRadius;
  84. transformer.corners = corners;
  85. transformer.borderWidth = borderWidth;
  86. transformer.borderColor = borderColor;
  87. return transformer;
  88. }
  89. - (NSString *)transformerKey {
  90. return [NSString stringWithFormat:@"SDImageRoundCornerTransformer(%f,%lu,%f,%@)", self.cornerRadius, (unsigned long)self.corners, self.borderWidth, self.borderColor.sd_hexString];
  91. }
  92. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  93. if (!image) {
  94. return nil;
  95. }
  96. return [image sd_roundedCornerImageWithRadius:self.cornerRadius corners:self.corners borderWidth:self.borderWidth borderColor:self.borderColor];
  97. }
  98. @end
  99. @interface SDImageResizingTransformer ()
  100. @property (nonatomic, assign) CGSize size;
  101. @property (nonatomic, assign) SDImageScaleMode scaleMode;
  102. @end
  103. @implementation SDImageResizingTransformer
  104. + (instancetype)transformerWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode {
  105. SDImageResizingTransformer *transformer = [SDImageResizingTransformer new];
  106. transformer.size = size;
  107. transformer.scaleMode = scaleMode;
  108. return transformer;
  109. }
  110. - (NSString *)transformerKey {
  111. CGSize size = self.size;
  112. return [NSString stringWithFormat:@"SDImageResizingTransformer({%f,%f},%lu)", size.width, size.height, (unsigned long)self.scaleMode];
  113. }
  114. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  115. if (!image) {
  116. return nil;
  117. }
  118. return [image sd_resizedImageWithSize:self.size scaleMode:self.scaleMode];
  119. }
  120. @end
  121. @interface SDImageCroppingTransformer ()
  122. @property (nonatomic, assign) CGRect rect;
  123. @end
  124. @implementation SDImageCroppingTransformer
  125. + (instancetype)transformerWithRect:(CGRect)rect {
  126. SDImageCroppingTransformer *transformer = [SDImageCroppingTransformer new];
  127. transformer.rect = rect;
  128. return transformer;
  129. }
  130. - (NSString *)transformerKey {
  131. CGRect rect = self.rect;
  132. return [NSString stringWithFormat:@"SDImageCroppingTransformer({%f,%f,%f,%f})", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height];
  133. }
  134. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  135. if (!image) {
  136. return nil;
  137. }
  138. return [image sd_croppedImageWithRect:self.rect];
  139. }
  140. @end
  141. @interface SDImageFlippingTransformer ()
  142. @property (nonatomic, assign) BOOL horizontal;
  143. @property (nonatomic, assign) BOOL vertical;
  144. @end
  145. @implementation SDImageFlippingTransformer
  146. + (instancetype)transformerWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical {
  147. SDImageFlippingTransformer *transformer = [SDImageFlippingTransformer new];
  148. transformer.horizontal = horizontal;
  149. transformer.vertical = vertical;
  150. return transformer;
  151. }
  152. - (NSString *)transformerKey {
  153. return [NSString stringWithFormat:@"SDImageFlippingTransformer(%d,%d)", self.horizontal, self.vertical];
  154. }
  155. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  156. if (!image) {
  157. return nil;
  158. }
  159. return [image sd_flippedImageWithHorizontal:self.horizontal vertical:self.vertical];
  160. }
  161. @end
  162. @interface SDImageRotationTransformer ()
  163. @property (nonatomic, assign) CGFloat angle;
  164. @property (nonatomic, assign) BOOL fitSize;
  165. @end
  166. @implementation SDImageRotationTransformer
  167. + (instancetype)transformerWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize {
  168. SDImageRotationTransformer *transformer = [SDImageRotationTransformer new];
  169. transformer.angle = angle;
  170. transformer.fitSize = fitSize;
  171. return transformer;
  172. }
  173. - (NSString *)transformerKey {
  174. return [NSString stringWithFormat:@"SDImageRotationTransformer(%f,%d)", self.angle, self.fitSize];
  175. }
  176. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  177. if (!image) {
  178. return nil;
  179. }
  180. return [image sd_rotatedImageWithAngle:self.angle fitSize:self.fitSize];
  181. }
  182. @end
  183. #pragma mark - Image Blending
  184. @interface SDImageTintTransformer ()
  185. @property (nonatomic, strong, nonnull) UIColor *tintColor;
  186. @end
  187. @implementation SDImageTintTransformer
  188. + (instancetype)transformerWithColor:(UIColor *)tintColor {
  189. SDImageTintTransformer *transformer = [SDImageTintTransformer new];
  190. transformer.tintColor = tintColor;
  191. return transformer;
  192. }
  193. - (NSString *)transformerKey {
  194. return [NSString stringWithFormat:@"SDImageTintTransformer(%@)", self.tintColor.sd_hexString];
  195. }
  196. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  197. if (!image) {
  198. return nil;
  199. }
  200. return [image sd_tintedImageWithColor:self.tintColor];
  201. }
  202. @end
  203. #pragma mark - Image Effect
  204. @interface SDImageBlurTransformer ()
  205. @property (nonatomic, assign) CGFloat blurRadius;
  206. @end
  207. @implementation SDImageBlurTransformer
  208. + (instancetype)transformerWithRadius:(CGFloat)blurRadius {
  209. SDImageBlurTransformer *transformer = [SDImageBlurTransformer new];
  210. transformer.blurRadius = blurRadius;
  211. return transformer;
  212. }
  213. - (NSString *)transformerKey {
  214. return [NSString stringWithFormat:@"SDImageBlurTransformer(%f)", self.blurRadius];
  215. }
  216. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  217. if (!image) {
  218. return nil;
  219. }
  220. return [image sd_blurredImageWithRadius:self.blurRadius];
  221. }
  222. @end
  223. #if SD_UIKIT || SD_MAC
  224. @interface SDImageFilterTransformer ()
  225. @property (nonatomic, strong, nonnull) CIFilter *filter;
  226. @end
  227. @implementation SDImageFilterTransformer
  228. + (instancetype)transformerWithFilter:(CIFilter *)filter {
  229. SDImageFilterTransformer *transformer = [SDImageFilterTransformer new];
  230. transformer.filter = filter;
  231. return transformer;
  232. }
  233. - (NSString *)transformerKey {
  234. return [NSString stringWithFormat:@"SDImageFilterTransformer(%@)", self.filter.name];
  235. }
  236. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  237. if (!image) {
  238. return nil;
  239. }
  240. return [image sd_filteredImageWithFilter:self.filter];
  241. }
  242. @end
  243. #endif