SDImageTransformer.m 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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+HexString.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. @interface SDImagePipelineTransformer ()
  38. @property (nonatomic, copy, readwrite, nonnull) NSArray<id<SDImageTransformer>> *transformers;
  39. @property (nonatomic, copy, readwrite) NSString *transformerKey;
  40. @end
  41. @implementation SDImagePipelineTransformer
  42. + (instancetype)transformerWithTransformers:(NSArray<id<SDImageTransformer>> *)transformers {
  43. SDImagePipelineTransformer *transformer = [SDImagePipelineTransformer new];
  44. transformer.transformers = transformers;
  45. transformer.transformerKey = [[self class] cacheKeyForTransformers:transformers];
  46. return transformer;
  47. }
  48. + (NSString *)cacheKeyForTransformers:(NSArray<id<SDImageTransformer>> *)transformers {
  49. if (transformers.count == 0) {
  50. return @"";
  51. }
  52. NSMutableArray<NSString *> *cacheKeys = [NSMutableArray arrayWithCapacity:transformers.count];
  53. [transformers enumerateObjectsUsingBlock:^(id<SDImageTransformer> _Nonnull transformer, NSUInteger idx, BOOL * _Nonnull stop) {
  54. NSString *cacheKey = transformer.transformerKey;
  55. [cacheKeys addObject:cacheKey];
  56. }];
  57. return [cacheKeys componentsJoinedByString:SDImageTransformerKeySeparator];
  58. }
  59. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  60. if (!image) {
  61. return nil;
  62. }
  63. UIImage *transformedImage = image;
  64. for (id<SDImageTransformer> transformer in self.transformers) {
  65. transformedImage = [transformer transformedImageWithImage:transformedImage forKey:key];
  66. }
  67. return transformedImage;
  68. }
  69. @end
  70. @interface SDImageRoundCornerTransformer ()
  71. @property (nonatomic, assign) CGFloat cornerRadius;
  72. @property (nonatomic, assign) SDRectCorner corners;
  73. @property (nonatomic, assign) CGFloat borderWidth;
  74. @property (nonatomic, strong, nullable) UIColor *borderColor;
  75. @end
  76. @implementation SDImageRoundCornerTransformer
  77. + (instancetype)transformerWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor {
  78. SDImageRoundCornerTransformer *transformer = [SDImageRoundCornerTransformer new];
  79. transformer.cornerRadius = cornerRadius;
  80. transformer.corners = corners;
  81. transformer.borderWidth = borderWidth;
  82. transformer.borderColor = borderColor;
  83. return transformer;
  84. }
  85. - (NSString *)transformerKey {
  86. return [NSString stringWithFormat:@"SDImageRoundCornerTransformer(%f,%lu,%f,%@)", self.cornerRadius, (unsigned long)self.corners, self.borderWidth, self.borderColor.sd_hexString];
  87. }
  88. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  89. if (!image) {
  90. return nil;
  91. }
  92. return [image sd_roundedCornerImageWithRadius:self.cornerRadius corners:self.corners borderWidth:self.borderWidth borderColor:self.borderColor];
  93. }
  94. @end
  95. @interface SDImageResizingTransformer ()
  96. @property (nonatomic, assign) CGSize size;
  97. @property (nonatomic, assign) SDImageScaleMode scaleMode;
  98. @end
  99. @implementation SDImageResizingTransformer
  100. + (instancetype)transformerWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode {
  101. SDImageResizingTransformer *transformer = [SDImageResizingTransformer new];
  102. transformer.size = size;
  103. transformer.scaleMode = scaleMode;
  104. return transformer;
  105. }
  106. - (NSString *)transformerKey {
  107. CGSize size = self.size;
  108. return [NSString stringWithFormat:@"SDImageResizingTransformer({%f,%f},%lu)", size.width, size.height, (unsigned long)self.scaleMode];
  109. }
  110. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  111. if (!image) {
  112. return nil;
  113. }
  114. return [image sd_resizedImageWithSize:self.size scaleMode:self.scaleMode];
  115. }
  116. @end
  117. @interface SDImageCroppingTransformer ()
  118. @property (nonatomic, assign) CGRect rect;
  119. @end
  120. @implementation SDImageCroppingTransformer
  121. + (instancetype)transformerWithRect:(CGRect)rect {
  122. SDImageCroppingTransformer *transformer = [SDImageCroppingTransformer new];
  123. transformer.rect = rect;
  124. return transformer;
  125. }
  126. - (NSString *)transformerKey {
  127. CGRect rect = self.rect;
  128. return [NSString stringWithFormat:@"SDImageCroppingTransformer({%f,%f,%f,%f})", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height];
  129. }
  130. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  131. if (!image) {
  132. return nil;
  133. }
  134. return [image sd_croppedImageWithRect:self.rect];
  135. }
  136. @end
  137. @interface SDImageFlippingTransformer ()
  138. @property (nonatomic, assign) BOOL horizontal;
  139. @property (nonatomic, assign) BOOL vertical;
  140. @end
  141. @implementation SDImageFlippingTransformer
  142. + (instancetype)transformerWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical {
  143. SDImageFlippingTransformer *transformer = [SDImageFlippingTransformer new];
  144. transformer.horizontal = horizontal;
  145. transformer.vertical = vertical;
  146. return transformer;
  147. }
  148. - (NSString *)transformerKey {
  149. return [NSString stringWithFormat:@"SDImageFlippingTransformer(%d,%d)", self.horizontal, self.vertical];
  150. }
  151. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  152. if (!image) {
  153. return nil;
  154. }
  155. return [image sd_flippedImageWithHorizontal:self.horizontal vertical:self.vertical];
  156. }
  157. @end
  158. @interface SDImageRotationTransformer ()
  159. @property (nonatomic, assign) CGFloat angle;
  160. @property (nonatomic, assign) BOOL fitSize;
  161. @end
  162. @implementation SDImageRotationTransformer
  163. + (instancetype)transformerWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize {
  164. SDImageRotationTransformer *transformer = [SDImageRotationTransformer new];
  165. transformer.angle = angle;
  166. transformer.fitSize = fitSize;
  167. return transformer;
  168. }
  169. - (NSString *)transformerKey {
  170. return [NSString stringWithFormat:@"SDImageRotationTransformer(%f,%d)", self.angle, self.fitSize];
  171. }
  172. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  173. if (!image) {
  174. return nil;
  175. }
  176. return [image sd_rotatedImageWithAngle:self.angle fitSize:self.fitSize];
  177. }
  178. @end
  179. #pragma mark - Image Blending
  180. @interface SDImageTintTransformer ()
  181. @property (nonatomic, strong, nonnull) UIColor *tintColor;
  182. @end
  183. @implementation SDImageTintTransformer
  184. + (instancetype)transformerWithColor:(UIColor *)tintColor {
  185. SDImageTintTransformer *transformer = [SDImageTintTransformer new];
  186. transformer.tintColor = tintColor;
  187. return transformer;
  188. }
  189. - (NSString *)transformerKey {
  190. return [NSString stringWithFormat:@"SDImageTintTransformer(%@)", self.tintColor.sd_hexString];
  191. }
  192. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  193. if (!image) {
  194. return nil;
  195. }
  196. return [image sd_tintedImageWithColor:self.tintColor];
  197. }
  198. @end
  199. #pragma mark - Image Effect
  200. @interface SDImageBlurTransformer ()
  201. @property (nonatomic, assign) CGFloat blurRadius;
  202. @end
  203. @implementation SDImageBlurTransformer
  204. + (instancetype)transformerWithRadius:(CGFloat)blurRadius {
  205. SDImageBlurTransformer *transformer = [SDImageBlurTransformer new];
  206. transformer.blurRadius = blurRadius;
  207. return transformer;
  208. }
  209. - (NSString *)transformerKey {
  210. return [NSString stringWithFormat:@"SDImageBlurTransformer(%f)", self.blurRadius];
  211. }
  212. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  213. if (!image) {
  214. return nil;
  215. }
  216. return [image sd_blurredImageWithRadius:self.blurRadius];
  217. }
  218. @end
  219. #if SD_UIKIT || SD_MAC
  220. @interface SDImageFilterTransformer ()
  221. @property (nonatomic, strong, nonnull) CIFilter *filter;
  222. @end
  223. @implementation SDImageFilterTransformer
  224. + (instancetype)transformerWithFilter:(CIFilter *)filter {
  225. SDImageFilterTransformer *transformer = [SDImageFilterTransformer new];
  226. transformer.filter = filter;
  227. return transformer;
  228. }
  229. - (NSString *)transformerKey {
  230. return [NSString stringWithFormat:@"SDImageFilterTransformer(%@)", self.filter.name];
  231. }
  232. - (UIImage *)transformedImageWithImage:(UIImage *)image forKey:(NSString *)key {
  233. if (!image) {
  234. return nil;
  235. }
  236. return [image sd_filteredImageWithFilter:self.filter];
  237. }
  238. @end
  239. #endif