碰到一个需要解决的问题就是可能需要同样的图标,同样的素材,但是需要按照用户喜爱变为不同的颜色,从而搭配不同的模板造型。如果有个红色的图片,又想要蓝色的图片,如果让美工仅仅是调色,估计三套之后就会被打的,并且也会占用资源。
所以就找找看有没有用代码控制,同一套图片弄成不同的颜色就行了,找到了很多前人的方法,我就跟着乘凉了
思路就是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];
}
原图如下
生成之后的效果图
这个是纯色,所以也可以渲染一次,但是如果碰到了不是纯色,那么一次就不行了,比如demo中的图,如果只是使用kCGBlendModeDestinationIn
渲染一次,那么效果就是这样的
所以需要渲染两次,一次保持灰度,一次保持原有透明度,这样就可以得到正确的图
当然也可以设置不同颜色,比如这个棕色和橘色
如果图片不是透明的记得把UIGraphicsBeginImageContextWithOptions
里面的不透明设置为YES。
三、demo下载
Github下载:https://github.com/DamonHu/HudongBlogDemo/tree/master/ImageChangeDemo
Gitosc下载:http://git.oschina.net/DamonHoo/ImageChangeDemo
四、参考文章
- iOS中使用blend改变图片颜色
- Swift - 使用CGBlendMode改变UIImage颜色
- UIGraphicsBeginImageContext和UIGraphicsBeginImageContextWithOptions
- 图片Premultiplied Alpha到底是干嘛用的
- UIGraphicsBeginImageContextWithOptions
- CGBlendMode
版权属于:东哥笔记 - DongGe.org
本文链接:https://dongge.org/blog/447.html
自2017年12月26日起,『转载以及大段采集进行后续编辑』须注明本文标题和链接!否则禁止所有转载和采集行为!