碰到一个需要解决的问题就是可能需要同样的图标,同样的素材,但是需要按照用户喜爱变为不同的颜色,从而搭配不同的模板造型。如果有个红色的图片,又想要蓝色的图片,如果让美工仅仅是调色,估计三套之后就会被打的,并且也会占用资源。

所以就找找看有没有用代码控制,同一套图片弄成不同的颜色就行了,找到了很多前人的方法,我就跟着乘凉了

思路就是UIGraphicsBeginImageContext根据图片设置的颜色重新绘制生成新的图片。

一、创建一个UIImage的Category

UIImage+ChangeColor.h文件

#import <UIKit/UIKit.h>

@interface UIImage (ChangeColor)
-(UIImage*)imageChangeColor:(UIColor*)color;
@end

UIImage+ChangeColor.m文件

#import "UIImage+ChangeColor.h"

@implementation UIImage (ChangeColor)

//绘图
-(UIImage*)imageChangeColor:(UIColor*)color
{
    //获取画布
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
    //画笔沾取颜色
    [color setFill];
    
    CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height);
    UIRectFill(bounds);
    //绘制一次
    [self drawInRect:bounds blendMode:kCGBlendModeOverlay alpha:1.0f];
    //再绘制一次
    [self drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0f];
    //获取图片
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return img;
}
@end

1.1、参数说明

1.1.1、设置画布

//获取画布
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);

获取画布时,里面三个参数分别代表大小,是否是不透明的,缩放比例。根据原图设置是否是不透明的,如果原图不透明,那么设置为YES,如果是透明的就设置为NO。第三个参数是缩放比例,因为有Retina屏幕,所以设置为0即可,根据屏幕缩放

1.1.2、绘制图片

//绘制一次
[self drawInRect:bounds blendMode:kCGBlendModeOverlay alpha:1.0f];

绘制的参数blendMode里面中,苹果官方说明

R is the premultiplied result
<br/>S is the source color, and includes alpha
<br/>D is the destination color, and includes alpha
<br/>Ra, Sa, and Da are the alpha components of R, S, and D

意思就是

R--result
<br/>S--原色
<br/>D--目标色
<br/>Ra、Sa、Da分别为三种颜色的透明度

然后根据不同的blendMode来看结果,比如

kCGBlendModeSourceIn,    /* R = S*Da */
//就是说目标色 = 原色*目标色的透明度

具体怎么算请看参考文章里面吧,颜色计算挺复杂我也没有静下心来看明白。至于为什么需要渲染两次,我在使用的时候看着图片说

二、修改图片颜色

用的时候导入头文件,然后通过这个Category使用即可,这个例子中,点击按钮,同一张图片生成红色和黄色图片

#import "ViewController.h"
#import "UIImage+ChangeColor.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor lightGrayColor];
    
    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 100, 140, 40)];
    [button setTitle:@"渲染红色" forState:UIControlStateNormal];
    [button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button addTarget:self action:@selector(setColorsRed) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
    
    UIButton *button2 = [[UIButton alloc] initWithFrame:CGRectMake(10, 160, 140, 40)];
    [button2 setTitle:@"渲染橘色" forState:UIControlStateNormal];
    [button2 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button2 addTarget:self action:@selector(setColorsOrange) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button2];
}

-(void)setColorsRed{
    UIImage *img =  [UIImage imageNamed:@"test.png"];
    
    UIImageView *imgview = [[UIImageView alloc] initWithFrame:CGRectMake(0, 200, 300, 300)];
    [imgview setImage:[img imageChangeColor:[UIColor redColor]]];//brownColor
    [self.view addSubview:imgview];
}

-(void)setColorsOrange{
    UIImage *img =  [UIImage imageNamed:@"test.png"];
    
    UIImageView *imgview = [[UIImageView alloc] initWithFrame:CGRectMake(0, 400, 300, 300)];
    [imgview setImage:[img imageChangeColor:[UIColor orangeColor]]];
    [self.view addSubview:imgview];
}

原图如下

test.png

生成之后的效果图

Simulator Screen Shot 2017年2月14日 16.02.08.png

这个是纯色,所以也可以渲染一次,但是如果碰到了不是纯色,那么一次就不行了,比如demo中的图,如果只是使用kCGBlendModeDestinationIn渲染一次,那么效果就是这样的

Simulator Screen Shot 2017年2月14日 15.06.10.png

所以需要渲染两次,一次保持灰度,一次保持原有透明度,这样就可以得到正确的图

Simulator Screen Shot 2017年2月14日 15.26.27.png

当然也可以设置不同颜色,比如这个棕色和橘色

Simulator Screen Shot 2017年2月14日 15.35.20.png

如果图片不是透明的记得把UIGraphicsBeginImageContextWithOptions里面的不透明设置为YES。

三、demo下载

Github下载:https://github.com/DamonHu/HudongBlogDemo/tree/master/ImageChangeDemo

Gitosc下载:http://git.oschina.net/DamonHoo/ImageChangeDemo

四、参考文章


☟☟可点击下方广告支持一下☟☟

最后修改:2021 年 03 月 07 日
请我喝杯可乐,请随意打赏: ☞已打赏列表