杨锴
2025-03-11 90dc3329d1973fda691e357cf4523d5c7c67fa1d
Pods/SDWebImage/SDWebImage/Core/UIImage+Transform.m
@@ -536,37 +536,183 @@
#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:kCGBlendModeSourceIn];
}
- (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];
                }
                colorImage = [CIImage imageWithColor:clearColor];
                colorImage = [colorImage imageByCroppingToRect:ciImage.extent];
                ciImage = colorImage;
            } 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:@"CIColorControls"];
                [filter1 setValue:ciImage forKey:kCIInputImageKey];
                [filter1 setValue:@(-0.5) forKey:kCIInputBrightnessKey];
                ciImage = filter1.outputImage;
                // (1 - S)
                CIFilter *filter2 = [CIFilter filterWithName:@"CIColorControls"];
                [filter2 setValue:colorImage forKey:kCIInputImageKey];
                [filter2 setValue:@(-0.5) forKey:kCIInputBrightnessKey];
                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: %d", 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
    
    CGSize size = self.size;
    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;