Add blend mode to UIImage+Transform tint color API
Also works for CIFilter variant
This commit is contained in:
parent
c8f74d2de0
commit
099371823e
|
@ -98,13 +98,23 @@ typedef NS_OPTIONS(NSUInteger, SDRectCorner) {
|
|||
#pragma mark - Image Blending
|
||||
|
||||
/**
|
||||
Return a tinted image with the given color. This actually use alpha blending of current image and the tint color.
|
||||
Return a tinted image with the given color. This actually use `sourceAtop` blend mode.
|
||||
|
||||
@param tintColor The tint color.
|
||||
@return The new image with the tint color.
|
||||
*/
|
||||
- (nullable UIImage *)sd_tintedImageWithColor:(nonnull UIColor *)tintColor;
|
||||
|
||||
/**
|
||||
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`).
|
||||
|
||||
@param tintColor The tint color.
|
||||
@param blendMode The blend mode.
|
||||
@return The new image with the tint color.
|
||||
*/
|
||||
- (nullable UIImage *)sd_tintedImageWithColor:(nonnull UIColor *)tintColor blendMode:(CGBlendMode)blendMode;
|
||||
|
||||
/**
|
||||
Return the pixel color at specify position. The point is from the top-left to the bottom-right and 0-based. The returned the color is always be RGBA format. The image must be CG-based.
|
||||
@note The point's x/y will be converted into integer.
|
||||
|
|
|
@ -536,28 +536,173 @@ static inline CGImageRef _Nullable SDCreateCGImageFromCIImage(CIImage * _Nonnull
|
|||
|
||||
#pragma mark - Image Blending
|
||||
|
||||
static NSString * _Nullable SDGetCIFilterNameFromBlendMode(CGBlendMode blendMode) {
|
||||
// CGBlendMode: https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_images/dq_images.html#//apple_ref/doc/uid/TP30001066-CH212-CJBIJEFG
|
||||
// CIFilter: https://developer.apple.com/library/archive/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html#//apple_ref/doc/uid/TP30000136-SW71
|
||||
NSString *filterName;
|
||||
switch (blendMode) {
|
||||
case kCGBlendModeMultiply:
|
||||
filterName = @"CIMultiplyBlendMode";
|
||||
break;
|
||||
case kCGBlendModeScreen:
|
||||
filterName = @"CIScreenBlendMode";
|
||||
break;
|
||||
case kCGBlendModeOverlay:
|
||||
filterName = @"CIOverlayBlendMode";
|
||||
break;
|
||||
case kCGBlendModeDarken:
|
||||
filterName = @"CIDarkenBlendMode";
|
||||
break;
|
||||
case kCGBlendModeLighten:
|
||||
filterName = @"CILightenBlendMode";
|
||||
break;
|
||||
case kCGBlendModeColorDodge:
|
||||
filterName = @"CIColorDodgeBlendMode";
|
||||
break;
|
||||
case kCGBlendModeColorBurn:
|
||||
filterName = @"CIColorBurnBlendMode";
|
||||
break;
|
||||
case kCGBlendModeSoftLight:
|
||||
filterName = @"CISoftLightBlendMode";
|
||||
break;
|
||||
case kCGBlendModeHardLight:
|
||||
filterName = @"CIHardLightBlendMode";
|
||||
break;
|
||||
case kCGBlendModeDifference:
|
||||
filterName = @"CIDifferenceBlendMode";
|
||||
break;
|
||||
case kCGBlendModeExclusion:
|
||||
filterName = @"CIExclusionBlendMode";
|
||||
break;
|
||||
case kCGBlendModeHue:
|
||||
filterName = @"CIHueBlendMode";
|
||||
break;
|
||||
case kCGBlendModeSaturation:
|
||||
filterName = @"CISaturationBlendMode";
|
||||
break;
|
||||
case kCGBlendModeColor:
|
||||
// Color blend mode uses the luminance values of the background with the hue and saturation values of the source image.
|
||||
filterName = @"CIColorBlendMode";
|
||||
break;
|
||||
case kCGBlendModeLuminosity:
|
||||
filterName = @"CILuminosityBlendMode";
|
||||
break;
|
||||
|
||||
// macOS 10.5+
|
||||
case kCGBlendModeSourceAtop:
|
||||
case kCGBlendModeDestinationAtop:
|
||||
filterName = @"CISourceAtopCompositing";
|
||||
break;
|
||||
case kCGBlendModeSourceIn:
|
||||
case kCGBlendModeDestinationIn:
|
||||
filterName = @"CISourceInCompositing";
|
||||
break;
|
||||
case kCGBlendModeSourceOut:
|
||||
case kCGBlendModeDestinationOut:
|
||||
filterName = @"CISourceOutCompositing";
|
||||
break;
|
||||
case kCGBlendModeNormal: // SourceOver
|
||||
case kCGBlendModeDestinationOver:
|
||||
filterName = @"CISourceOverCompositing";
|
||||
break;
|
||||
|
||||
// need special handling
|
||||
case kCGBlendModeClear:
|
||||
// use clear color instead
|
||||
break;
|
||||
case kCGBlendModeCopy:
|
||||
// use input color instead
|
||||
break;
|
||||
case kCGBlendModeXOR:
|
||||
// unsupported
|
||||
break;
|
||||
case kCGBlendModePlusDarker:
|
||||
// chain filters
|
||||
break;
|
||||
case kCGBlendModePlusLighter:
|
||||
// chain filters
|
||||
break;
|
||||
}
|
||||
return filterName;
|
||||
}
|
||||
|
||||
- (nullable UIImage *)sd_tintedImageWithColor:(nonnull UIColor *)tintColor {
|
||||
return [self sd_tintedImageWithColor:tintColor blendMode:kCGBlendModeSourceAtop];
|
||||
}
|
||||
|
||||
- (nullable UIImage *)sd_tintedImageWithColor:(nonnull UIColor *)tintColor blendMode:(CGBlendMode)blendMode {
|
||||
BOOL hasTint = CGColorGetAlpha(tintColor.CGColor) > __FLT_EPSILON__;
|
||||
if (!hasTint) {
|
||||
return self;
|
||||
}
|
||||
|
||||
// blend mode, see https://en.wikipedia.org/wiki/Alpha_compositing
|
||||
#if SD_UIKIT || SD_MAC
|
||||
// CIImage shortcut
|
||||
if (self.CIImage) {
|
||||
CIImage *ciImage = self.CIImage;
|
||||
CIImage *ciImage = self.CIImage;
|
||||
if (ciImage) {
|
||||
CIImage *colorImage = [CIImage imageWithColor:[[CIColor alloc] initWithColor:tintColor]];
|
||||
colorImage = [colorImage imageByCroppingToRect:ciImage.extent];
|
||||
CIFilter *filter = [CIFilter filterWithName:@"CISourceAtopCompositing"];
|
||||
[filter setValue:colorImage forKey:kCIInputImageKey];
|
||||
[filter setValue:ciImage forKey:kCIInputBackgroundImageKey];
|
||||
ciImage = filter.outputImage;
|
||||
NSString *filterName = SDGetCIFilterNameFromBlendMode(blendMode);
|
||||
// Some blend mode is not nativelly supported
|
||||
if (filterName) {
|
||||
CIFilter *filter = [CIFilter filterWithName:filterName];
|
||||
[filter setValue:colorImage forKey:kCIInputImageKey];
|
||||
[filter setValue:ciImage forKey:kCIInputBackgroundImageKey];
|
||||
ciImage = filter.outputImage;
|
||||
} else {
|
||||
if (blendMode == kCGBlendModeClear) {
|
||||
// R = 0
|
||||
CIColor *clearColor;
|
||||
if (@available(iOS 10.0, macOS 10.12, tvOS 10.0, *)) {
|
||||
clearColor = CIColor.clearColor;
|
||||
} else {
|
||||
clearColor = [[CIColor alloc] initWithColor:UIColor.clearColor];
|
||||
}
|
||||
ciImage = [CIImage imageWithColor:clearColor];
|
||||
} else if (blendMode == kCGBlendModeCopy) {
|
||||
// R = S
|
||||
ciImage = colorImage;
|
||||
} else if (blendMode == kCGBlendModePlusLighter) {
|
||||
// R = MIN(1, S + D)
|
||||
// S + D
|
||||
CIFilter *filter = [CIFilter filterWithName:@"CIAdditionCompositing"];
|
||||
[filter setValue:colorImage forKey:kCIInputImageKey];
|
||||
[filter setValue:ciImage forKey:kCIInputBackgroundImageKey];
|
||||
ciImage = filter.outputImage;
|
||||
// MIN
|
||||
ciImage = [ciImage imageByApplyingFilter:@"CIColorClamp" withInputParameters:nil];
|
||||
} else if (blendMode == kCGBlendModePlusDarker) {
|
||||
// R = MAX(0, (1 - D) + (1 - S))
|
||||
// (1 - D)
|
||||
CIFilter *filter1 = [CIFilter filterWithName:@"CIColorInvert"];
|
||||
[filter1 setValue:ciImage forKey:kCIInputImageKey];
|
||||
ciImage = filter1.outputImage;
|
||||
// (1 - S)
|
||||
CIFilter *filter2 = [CIFilter filterWithName:@"CIColorInvert"];
|
||||
[filter2 setValue:colorImage forKey:kCIInputImageKey];
|
||||
colorImage = filter2.outputImage;
|
||||
// +
|
||||
CIFilter *filter = [CIFilter filterWithName:@"CIAdditionCompositing"];
|
||||
[filter setValue:colorImage forKey:kCIInputImageKey];
|
||||
[filter setValue:ciImage forKey:kCIInputBackgroundImageKey];
|
||||
ciImage = filter.outputImage;
|
||||
// MAX
|
||||
ciImage = [ciImage imageByApplyingFilter:@"CIColorClamp" withInputParameters:nil];
|
||||
} else {
|
||||
SD_LOG("UIImage+Transform error: Unsupported blend mode: %zu", blendMode);
|
||||
ciImage = nil;
|
||||
}
|
||||
}
|
||||
|
||||
if (ciImage) {
|
||||
#if SD_UIKIT
|
||||
UIImage *image = [UIImage imageWithCIImage:ciImage scale:self.scale orientation:self.imageOrientation];
|
||||
#else
|
||||
UIImage *image = [[UIImage alloc] initWithCIImage:ciImage scale:self.scale orientation:kCGImagePropertyOrientationUp];
|
||||
#endif
|
||||
return image;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -565,9 +710,6 @@ static inline CGImageRef _Nullable SDCreateCGImageFromCIImage(CIImage * _Nonnull
|
|||
CGRect rect = { CGPointZero, size };
|
||||
CGFloat scale = self.scale;
|
||||
|
||||
// blend mode, see https://en.wikipedia.org/wiki/Alpha_compositing
|
||||
CGBlendMode blendMode = kCGBlendModeSourceAtop;
|
||||
|
||||
SDGraphicsImageRendererFormat *format = [[SDGraphicsImageRendererFormat alloc] init];
|
||||
format.scale = scale;
|
||||
SDGraphicsImageRenderer *renderer = [[SDGraphicsImageRenderer alloc] initWithSize:size format:format];
|
||||
|
|
Loading…
Reference in New Issue