iOS中使用blend改变图片颜色

在一个应用中, 常见的需求之一: 同一个图标但是有不同的颜色,一般的做法是让UI切出不同颜色的图片,这无疑会增加包的大小, 图片修改起来也会很痛苦~

在iOS5以及6的SDK部分标准控件引入了tintColer, 但是对于UIImageView的图片并没有好的效果,google学习一下;

准备一张带有alpha通道的图片,原始颜色是纯的灰色, 可以很好地看出来效果

Alt text

我们需要做的就是在图片上tint另外一种颜色,并保持原有的alpha通道,用Core Graphics的做法如下:

1.创建一个上下文用以画新的图片
2.将新的tintColor设置为填充颜色
3.将原图片画在创建的上下文中,并用新的填充色着色(注意保持alpha通道)
4.从当前上下文中取得图片并返回

UIImage文档中提供了blend绘图的方法drawInRect: blendMode: alpha: ,首先了解一下blendMode:

Alt text

R表示结果,S表示包含alpha的原色,D表示包含alpha的目标色,Ra,Sa和Da分别是三个的alpha。 此处我们想要的结果就是目标色和原色透明度的加成 选用kCGBlendModeDestinationIn

为了方便以后使用写一个UIImage的Category:

.h

@interface UIImage (Tint)

- (UIImage *) imageWithTintColor:(UIColor *)tintColor;

@end

.m

@implementation UIImage (Tint)
- (UIImage *) imageWithTintColor:(UIColor *)tintColor
{
    //We want to keep alpha, set opaque to NO; Use 0.0f for scale to use the scale factor of the device’s main screen.
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
    [tintColor setFill];
    CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height);
    UIRectFill(bounds);

//Draw the tinted image in context
    [self drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0f];

    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

       return tintedImage;
}
@end

使用的时候用UIImage的对象调用就可以了:测试结果如下:

Alt text

...发现tintColor的颜色虽然是变了, 但是边框以及星星周边的棱角没有了, 整个一渐变色, 有点丑~~ kCGBlendModeDestinationIn:R = D * Sa,我们虽然保留了原色的透明度,但是缺丢失了所有的灰度信息,blendMode还有另外一枚举kCGBlendModeOverlay,它可以保持背景色的灰度信息

- (UIImage *) imageWithTintColor:(UIColor *)tintColor
{
    //We want to keep alpha, set opaque to NO; Use 0.0f for scale to use the scale factor of the device’s main screen.
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
    [tintColor setFill];
    CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height);
    UIRectFill(bounds);

    //Draw the tinted image in context
    [self drawInRect:bounds blendMode:kCGBlendModeOverlay alpha:1.0f];

    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return tintedImage;
}

测下结果如下:

Alt text

呃,颜色及棱角都对了, 但是透明度又没了...那么既然我们用kCGBlendModeOverlay能保留灰度信息,用kCGBlendModeDestinationIn能保留, 那用两个blendMode画两次就行了呗, 试下看看~~

- (UIImage *) imageWithTintColor:(UIColor *)tintColor
{
    //We want to keep alpha, set opaque to NO; Use 0.0f for scale to use the scale factor of the device’s main screen.
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
    [tintColor setFill];
    CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height);
    UIRectFill(bounds);

    //Draw the tinted image in context
    [self drawInRect:bounds blendMode:kCGBlendModeOverlay alpha:1.0f];

    [self drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0f];

    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return tintedImage;
}

结果如下:

Alt text

确实达到了我们想要的效果,但是要是只想要第一种效果的话, kCGBlendModeOverlay的效果就不需要了, 具体代码可以在OneV's Den大神的GitHub上找到.

results matching ""

    No results matching ""