diff --git a/SDWebImage/Core/SDImageTransformer.h b/SDWebImage/Core/SDImageTransformer.h index 0c0ff4f1..e01550a6 100644 --- a/SDWebImage/Core/SDImageTransformer.h +++ b/SDWebImage/Core/SDImageTransformer.h @@ -223,7 +223,7 @@ FOUNDATION_EXPORT NSString * _Nullable SDThumbnailedKeyForKey(NSString * _Nullab The tint color. */ @property (nonatomic, strong, readonly, nonnull) UIColor *tintColor; -/// The blend mode, defaults to `sourceAtop` if you use the old initializer +/// The blend mode, defaults to `sourceIn` if you use the initializer without blend mode @property (nonatomic, assign, readonly) CGBlendMode blendMode; - (nonnull instancetype)init NS_UNAVAILABLE; diff --git a/SDWebImage/Core/SDImageTransformer.m b/SDWebImage/Core/SDImageTransformer.m index 056cbbdd..813be2e8 100644 --- a/SDWebImage/Core/SDImageTransformer.m +++ b/SDWebImage/Core/SDImageTransformer.m @@ -252,7 +252,7 @@ NSString * _Nullable SDThumbnailedKeyForKey(NSString * _Nullable key, CGSize thu @implementation SDImageTintTransformer + (instancetype)transformerWithColor:(UIColor *)tintColor { - return [self transformerWithColor:tintColor blendMode:kCGBlendModeSourceAtop]; + return [self transformerWithColor:tintColor blendMode:kCGBlendModeSourceIn]; } + (instancetype)transformerWithColor:(UIColor *)tintColor blendMode:(CGBlendMode)blendMode { diff --git a/SDWebImage/Core/UIImage+Transform.h b/SDWebImage/Core/UIImage+Transform.h index bbacc145..f4c50d3a 100644 --- a/SDWebImage/Core/UIImage+Transform.h +++ b/SDWebImage/Core/UIImage+Transform.h @@ -98,7 +98,8 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { #pragma mark - Image Blending /** - Return a tinted image with the given color. This actually use `sourceAtop` blend mode. + Return a tinted image with the given color. This actually use `sourceIn` blend mode. + @note Before 5.20, this API actually use `sourceAtop` and cause naming confusing. After 5.20, we match UIKit's behavior using `sourceIn`. @param tintColor The tint color. @return The new image with the tint color. @@ -107,7 +108,7 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) { /** Return a tinted image with the given color and blend mode. - @note The blend mode treat `self` as background image (destination), treat `tintColor` as input image (source). So mostly you need `source` variant blend mode (use `sourceAtop` not `destinationAtop`). + @note The blend mode treat `self` as background image (destination), treat `tintColor` as input image (source). So mostly you need `source` variant blend mode (use `sourceIn` not `destinationIn`), which is different from UIKit's `+[UIImage imageWithTintColor:]`. @param tintColor The tint color. @param blendMode The blend mode. diff --git a/SDWebImage/Core/UIImage+Transform.m b/SDWebImage/Core/UIImage+Transform.m index a4d72f23..bed7279d 100644 --- a/SDWebImage/Core/UIImage+Transform.m +++ b/SDWebImage/Core/UIImage+Transform.m @@ -627,7 +627,7 @@ static NSString * _Nullable SDGetCIFilterNameFromBlendMode(CGBlendMode blendMode } - (nullable UIImage *)sd_tintedImageWithColor:(nonnull UIColor *)tintColor { - return [self sd_tintedImageWithColor:tintColor blendMode:kCGBlendModeSourceAtop]; + return [self sd_tintedImageWithColor:tintColor blendMode:kCGBlendModeSourceIn]; } - (nullable UIImage *)sd_tintedImageWithColor:(nonnull UIColor *)tintColor blendMode:(CGBlendMode)blendMode { @@ -694,7 +694,7 @@ static NSString * _Nullable SDGetCIFilterNameFromBlendMode(CGBlendMode blendMode // MAX ciImage = [ciImage imageByApplyingFilter:@"CIColorClamp" withInputParameters:nil]; } else { - SD_LOG("UIImage+Transform error: Unsupported blend mode: %zu", blendMode); + SD_LOG("UIImage+Transform error: Unsupported blend mode: %d", blendMode); ciImage = nil; } } diff --git a/Tests/Tests/SDImageTransformerTests.m b/Tests/Tests/SDImageTransformerTests.m index b099fb7e..550a854b 100644 --- a/Tests/Tests/SDImageTransformerTests.m +++ b/Tests/Tests/SDImageTransformerTests.m @@ -244,9 +244,33 @@ static void SDAssertCGImageFirstComponentWhite(CGImageRef image, OSType pixelTyp expect([topCenterColor.sd_hexString isEqualToString:[UIColor blackColor].sd_hexString]).beTruthy(); UIImage *tintedSourceInImage = [testImage sd_tintedImageWithColor:tintColor blendMode:kCGBlendModeSourceIn]; - centerColor = [tintedSourceInImage sd_colorAtPoint:CGPointMake(150, 150)]; - expect([centerColor.sd_hexString isEqualToString:[UIColor blackColor].sd_hexString]).beTruthy(); + topCenterColor = [tintedSourceInImage sd_colorAtPoint:CGPointMake(150, 20)]; +#if SD_UIKIT + // Test UIKit's tint color behavior + if (@available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)) { + UIImage *tintedSystemImage = [testImage imageWithTintColor:tintColor renderingMode:UIImageRenderingModeAlwaysTemplate]; + UIGraphicsImageRendererFormat *format = UIGraphicsImageRendererFormat.preferredFormat; + format.scale = tintedSourceInImage.scale; + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:tintedSystemImage.size format:format]; + // Draw template image + tintedSystemImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) { + [tintedSystemImage drawInRect:CGRectMake(0, 0, tintedSystemImage.size.width, tintedSystemImage.size.height)]; + }]; + UIColor *testColor1 = [tintedSourceInImage sd_colorAtPoint:CGPointMake(150, 20)]; + UIColor *testColor2 = [tintedSystemImage sd_colorAtPoint:CGPointMake(150, 20)]; + CGFloat r1, g1, b1, a1; + CGFloat r2, g2, b2, a2; + [testColor1 getRed:&r1 green:&g1 blue:&b1 alpha:&a1]; + [testColor2 getRed:&r2 green:&g2 blue:&b2 alpha:&a2]; + expect(r1).beCloseToWithin(r2, 0.01); + expect(g1).beCloseToWithin(g2, 0.01); + expect(b1).beCloseToWithin(b2, 0.01); + expect(a1).beCloseToWithin(a2, 0.01); + } +#endif + expect([topCenterColor.sd_hexString isEqualToString:tintColor.sd_hexString]).beTruthy(); } +#pragma clang diagnostic pop - (void)test07UIImageTransformBlurCG { [self test07UIImageTransformBlurWithImage:self.testImageCG]; @@ -357,7 +381,7 @@ static void SDAssertCGImageFirstComponentWhite(CGImageRef image, OSType pixelTyp @"SDImageRoundCornerTransformer(50.000000,18446744073709551615,1.000000,#ff000000)", @"SDImageFlippingTransformer(1,1)", @"SDImageCroppingTransformer({0.000000,0.000000,50.000000,50.000000})", - @"SDImageTintTransformer(#00000000,20)", + @"SDImageTintTransformer(#00000000,18)", @"SDImageBlurTransformer(5.000000)", @"SDImageFilterTransformer(CIColorInvert)" ];