|
iOS开发系列--打造自己的“美图秀秀” |
|
|
iOS开发系列--打造自己的“美图秀秀”
概述
在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益于它强大的开发框架。今天我们将围绕iOS中两大图形、图像绘图框架进行介绍:Quartz2D绘制2D图形和CoreImage中强大的滤镜功能。
Quartz2D
基本图形绘制
视图刷新
其他图形上下文
CoreImage
Quartz2D
在iOS中常用的绘图框架就是Quartz2D,Quartz2D是CoreGraphics框架的一部分,是一个强大的二维图像绘制引擎。Quartz2D在UIKit中也有很好的封装和集成,我们日常开发时所用到的UIKit中的组件都是由CoreGraphics进行绘制的。不仅如此,当我们引入UIKit框架时系统会自动引入CoreGraphics框架,并且为了方便开发者使用在UIKit内部还对一些常用的绘图API进行了封装。
在iOS中绘图一般分为以下几个步骤:
1.获取绘图上下文
2.创建并设置路径
3.将路径添加到上下文
4.设置上下文状态
5.绘制路径
6.释放路径
图形上下文CGContextRef代表图形输出设备(也就是绘制的位置),包含了绘制图形的一些设备信息,Quartz2D中的所有对象最终都必须绘制到图形上下文。这样一来,我们在绘制图形时就不必关心具体的设备信息,统一了代码编写方式(在Quartz2D中的绘图上下文可以是位图Bitmap、PDF、窗口Window、层Layer、打印对象Printer)。
基本图形绘制
在UIKit中默认已经为我们准备好了一个图形上下文对象,在UI控件的drawRect:方法(这个方法在loadView、viewDidLoad方法后执行)中我们可以通过UIKit封装函数UIGraphicsGetCurrentContext()方法获得这个图形上下文(注意在其他UI控件方法中无法取得这个对象),然后我们只要按照绘图步骤一步步执行即可。下面自定义一个KCView继承自UIView,重写drawRect:方法绘制两条直线说明上面绘图的步骤:
KCView.m
//
//KCView.m
//Quartz2D
//
//CreatedbyKenshinCuion14-3-17.
//Copyright(c)2014年KenshinCui.Allrightsreserved.
//
/
基本绘图
/
#import"KCView.h"
@implementationKCView
#pragmamark绘图
//绘图只能在此方法中调用,否则无法得到当前图形上下文
-(void)drawRect:(CGRect)rect{
//1.取得图形上下文对象
CGContextRefcontext=UIGraphicsGetCurrentContext();
//2.创建路径对象
CGMutablePathRefpath=CGPathCreateMutable();
CGPathMoveToPoint(path,nil,20,50);//移动到指定位置(设置路径起点)
CGPathAddLineToPoint(path,nil,20,100);//绘制直线(从起始位置开始)
CGPathAddLineToPoint(path,nil,300,100);//绘制另外一条直线(从上一直线终点开始绘制)
//3.添加路径到图形上下文
CGContextAddPath(context,path);
//4.设置图形上下文状态属性
CGContextSetRGBStrokeColor(context,1.0,0,0,1);//设置笔触颜色
CGContextSetRGBFillColor(context,0,1.0,0,1);//设置填充色
CGContextSetLineWidth(context,2.0);//设置线条宽度
CGContextSetLineCap(context,kCGLineCapRound);//设置顶点样式,(20,50)和(300,100)是顶点
CGContextSetLineJoin(context,kCGLineJoinRound);//设置连接点样式,(20,100)是连接点
/设置线段样式
phase:虚线开始的位置
lengths:虚线长度间隔(例如下面的定义说明第一条线段长度8,然后间隔3重新绘制8点的长度线段,当然这个数组可以定义更多元素)
count:虚线数组元素个数
/
CGFloatlengths[2]={18,9};
CGContextSetLineDash(context,0,lengths,2);
/设置阴影
context:图形上下文
offset:偏移量
blur:模糊度
color:阴影颜色
/
CGColorRefcolor=[UIColorgrayColor].CGColor;//颜色转化,由于Quartz2D跨平台,所以其中不能使用UIKit中的对象,但是UIkit提供了转化方法
CGContextSetShadowWithColor(context,CGSizeMake(2,2),0.8,color);
//5.绘制图像到指定图形上下文
/CGPathDrawingMode是填充方式,枚举类型
kCGPathFill:只有填充(非零缠绕数填充),不绘制边框
kCGPathEOFill:奇偶规则填充(多条路径交叉时,奇数交叉填充,偶交叉不填充)
kCGPathStroke:只有边框
kCGPathFillStroke:既有边框又有填充
kCGPathEOFillStroke:奇偶填充并绘制边框
/
CGContextDrawPath(context,kCGPathFillStroke);//最后一个参数是填充类型
//6.释放对象
CGPathRelease(path);
}
@end
在视图控制器创建KCView并添加到根视图中:
-(void)viewDidLoad{
[superviewDidLoad];
KCViewview=[[KCViewalloc]initWithFrame:[UIScreenmainScreen].bounds];
view.backgroundColor=[UIColorwhiteColor];
[self.viewaddSubview:view];
}
简化绘图方式
上面的绘图方式未免显得有些麻烦,其实CoreGraphics内部对创建对象添加到上下文这两步操作进行了封装,可以一步完成。另外前面也说过UIKit内部其实封装了一些以“UI”开头的方法帮助大家进行图形绘制。就拿前面的例子来说我们改进一些绘制方法:
-(void)drawLine2{
//1.获得图形上下文
CGContextRefcontext=UIGraphicsGetCurrentContext();
//2.绘制路径(相当于前面创建路径并添加路径到图形上下文两步操作)
CGContextMoveToPoint(context,20,50);
CGContextAddLineToPoint(context,20,100);
CGContextAddLineToPoint(context,300,100);
//封闭路径:a.创建一条起点和终点的线,不推荐
//CGPathAddLineToPoint(path,nil,20,50);
//封闭路径:b.直接调用路径封闭方法
CGContextClosePath(context);
//3.设置图形上下文属性
[[UIColorredColor]setStroke];//设置红色边框
[[UIColorgreenColor]setFill];//设置绿色填充
//[[UIColorblueColor]set];//同时设置填充和边框色
//4.绘制路径
CGContextDrawPath(context,kCGPathFillStroke);
}
上面的操作相比前面的方法应该说已经简化了不少,除了路径之外其他矩形、椭圆等都有对应的创建方法。另外上面我们也演示了封闭路径的方法,大家可以运行看一下效果。
其他图形绘制
相信大家了解了上面的绘制步骤其他图形绘制并不麻烦,下面以一个例子简单演示一下其他图形的绘制,包括文字和图像的绘制。
绘制矩形
在下面的方法中还可以看到UIKit对绘图方法的封装,使用起来更加简单。
#pragmamark绘制矩形
-(void)drawRectWithContext:(CGContextRef)context{
//添加矩形对象
CGRectrect=CGRectMake(20,50,280.0,50.0);
CGContextAddRect(context,rect);
//设置属性
[[UIColorblueColor]set];
//绘制
CGContextDrawPath(context,kCGPathFillStroke);
}
#pragmamark绘制矩形(利用UIKit的封装方法)
-(void)drawRectByUIKitWithContext:(CGContextRef)context{
CGRectrect=CGRectMake(20,150,280.0,50.0);
CGRectrect2=CGRectMake(20,250,280.0,50.0);
//设置属性
[[UIColoryellowColor]set];
//绘制矩形,相当于创建对象、添加对象到上下文、绘制三个步骤
UIRectFill(rect);//绘制矩形(只有填充)
[[UIColorredColor]setStroke];
UIRectFrame(rect2);//绘制矩形(只有边框)
}
@end
绘制椭圆
#pragmamark绘制椭圆
-(void)drawEllipse:(CGContextRef)context{
//添加对象,绘制椭圆(圆形)的过程也是先创建一个矩形
CGRectrect=CGRectMake(50,50,220.0,200.0);
CGContextAddEllipseInRect(context,rect);
//设置属性
[[UIColorpurpleColor]set];
//绘制
CGContextDrawPath(context,kCGPathFillStroke);
}
@end
绘制弧形
-(void)drawArc:(CGContextRef)context{
/添加弧形对象
x:中心点x坐标
y:中心点y坐标
radius:半径
startAngle:起始弧度
endAngle:终止弧度
closewise:是否逆时针绘制,0则顺时针绘制
/
CGContextAddArc(context,160,160,100.0,0.0,M_PI_2,1);
//设置属性
[[UIColoryellowColor]set];
//绘制
CGContextDrawPath(context,kCGPathFillStroke);
}
绘制贝塞尔曲线
要绘制规则图形在iOS中相当简单,但是不规则图形怎么绘制呢?此时就要利用路径。前面我们绘制了直线,它和曲线绘制都属于路径绘制。和直线绘制相比曲线绘制就要复杂一些,但是路径作为高级动画的基础又是我们必须掌握的,因此这里我们就一起来熟悉一下曲线绘制。在Quartz2D中曲线绘制分为两种:二次贝塞尔曲线和三次贝塞尔曲线。二次曲线只有一个控制点,而三次曲线有两个控制点,
当然,在iOS中两种曲线分别对应两种方法:
CGContextAddQuadCurveToPoint(CGContextRefc,CGFloatcpx,CGFloatcpy,CGFloatx,CGFloaty);
CGContextAddCurveToPoint(context,CGFloatcp1x,CGFloatcp1y,CGFloatcp2x,CGFloatcp2y,CGFloatx,CGFloaty);
下面就演示一下这两种曲线的绘制方法
#pragmamark绘制贝塞尔曲线
-(void)drawCurve:(CGContextRef)context{
//绘制曲线
CGContextMoveToPoint(context,20,100);//移动到起始位置
/绘制二次贝塞尔曲线
c:图形上下文
cpx:控制点x坐标
cpy:控制点y坐标
x:结束点x坐标
y:结束点y坐标
/
CGContextAddQuadCurveToPoint(context,160,0,300,100);
CGContextMoveToPoint(context,20,500);
/绘制三次贝塞尔曲线
c:图形上下文
cp1x:第一个控制点x坐标
cp1y:第一个控制点y坐标
cp2x:第二个控制点x坐标
cp2y:第二个控制点y坐标
x:结束点x坐标
y:结束点y坐标
/
CGContextAddCurveToPoint(context,80,300,240,500,300,300);
//设置图形上下文属性
[[UIColoryellowColor]setFill];
[[UIColorredColor]setStroke];
//绘制路径
CGContextDrawPath(context,kCGPathFillStroke);
}
文字绘制
除了绘制图形还可以绘制文本内容。
-(void)drawText:(CGContextRef)context{
//绘制到指定的区域内容
NSStringstr=@"StarWalkisthemostbeautifulstargazingappyou’veeverseenonamobiledevice.Itwillbecomeyourgo-tointeractiveastroguidetothenightsky,followingyoureverymovementinreal-timeandallowingyoutoexploreover200,000celestialbodieswithextensiveinformationaboutstarsandconstellationsthatyoufind.";
CGRectrect=CGRectMake(20,50,280,300);
UIFontfont=[UIFontsystemFontOfSize:18];//设置字体
UIColorcolor=[UIColorredColor];//字体颜色
NSMutableParagraphStylestyle=[[NSMutableParagraphStylealloc]init];//段落样式
NSTextAlignmentalign=NSTextAlignmentLeft;//对齐方式
style.alignment=align;
[strdrawInRect:rectwithAttributes:@{NSFontAttributeName:font,NSForegroundColorAttributeName:color,NSParagraphStyleAttributeName:style}];
}
图像绘制
Quartz2D还可以将图像绘制到图形上下文。
-(void)drawImage:(CGContextRef)context{
UIImageimage=[UIImageimageNamed:@"image2.jpg"];
//从某一点开始绘制
[imagedrawAtPoint:CGPointMake(10,50)];
//绘制到指定的矩形中,注意如果大小不合适会会进行拉伸
//[imagedrawInRect:CGRectMake(10,50,300,450)];
//平铺绘制
//[imagedrawAsPatternInRect:CGRectMake(0,0,320,568)];
}
绘制渐变填充
从前面的示例中我们可以看到如何设置填充颜色,事实上很多时候纯色的填充并不能满足我们的需求,例如有时候我们要绘制一些图形可能需要设置一个漂亮的背景,这个时候我们可能就会选择渐变填充方式。Quartz2D的渐变方式分为两种:
a.线性渐变线:渐变色以直线方式从开始位置逐渐向结束位置渐变
b.径向渐变:以中心点为圆心从起始渐变色向四周辐射,直到终止渐变色
要做渐变则必须先设置从开始位置到结束位置的渐变颜色,做过photoshop的朋友相信对于渐变色设置并不陌生,只要在指定位置指定不同的颜色,剩下的事情交给系统处理即可,如下图在起始位置、3/10位置、结束位置指定了三种颜色就形成由三种颜色组成的渐变色:
GradientColor
另外,在iOS中绘制渐变还需要注意一点就是指定颜色空间,所谓颜色空间就是不同颜色在不同的维度上取值最终组成一种颜色的过程。就拿RGB来说,如果将红色、绿色、蓝色看成是x、y、z轴坐标系,那么在三个坐标上分别取0~255范围内的不同值则可以组成各类颜色。当然,不同颜色空间的“坐标系”也是不同的(也就是说颜色表示的方式是不同的),常用的颜色空间除了RGB还有CMYK(印刷业常用这种颜色模式)、Gray。
在使用Quartz2D绘图时我们的颜色除了使用常规的方法(如何前面CGContextSetRGBFillColor(CGContextRefcontext,CGFloatred,CGFloatgreen,CGFloatblue,CGFloatalpha)方法)设置RGB和透明度外,有时还会遇到颜色参数是一个数组情况。如使用颜色空间填充时用到的CGContextSetFillColor(CGContextRefcontext,constCGFloatcomponents)方法,这个时候components数组中具体是如何存储颜色就要根据颜色空间而定,如果颜色空间使用RGB则数组中的元素四个为一组,分别是red(红)、green(绿)、blue(蓝)、alpha(透明度);如果使用CMYK颜色空间,那么数组中的元素五个为一组,分别是cyan(青)、magenta(洋红)、yellow(黄)、black(黑)、alpha(透明度)。
下面的代码分别演示了两种渐变方式,具体渐变绘制函数参数代码中已经注释的很清楚了:
//
//KCView3.m
//Quartz2D
//
//CreatedbyKenshinCuion14-3-16.
//Copyright(c)2014年KenshinCui.Allrightsreserved.
//
#import"KCView3.h"
@implementationKCView3
-(void)drawRect:(CGRect)rect{
CGContextRefcontext=UIGraphicsGetCurrentContext();
//[selfdrawLinearGradient:context];
[selfdrawRadialGradient:context];
}
#pragmamark线性渐变
-(void)drawLinearGradient:(CGContextRef)context{
//使用rgb颜色空间
CGColorSpaceRefcolorSpace=CGColorSpaceCreateDeviceRGB();
/指定渐变色
space:颜色空间
components:颜色数组,注意由于指定了RGB颜色空间,那么四个数组元素表示一个颜色(red、green、blue、alpha),
如果有三个颜色则这个数组有43个元素
locations:颜色所在位置(范围0~1),这个数组的个数不小于components中存放颜色的个数
count:渐变个数,等于locations的个数
/
CGFloatcompoents[12]={
248.0/255.0,86.0/255.0,86.0/255.0,1,
249.0/255.0,127.0/255.0,127.0/255.0,1,
1.0,1.0,1.0,1.0
};
CGFloatlocations[3]={0,0.3,1.0};
CGGradientRefgradient=CGGradientCreateWithColorComponents(colorSpace,compoents,locations,3);
/绘制线性渐变
context:图形上下文
gradient:渐变色
startPoint:起始位置
endPoint:终止位置
options:绘制方式,kCGGradientDrawsBeforeStartLocation开始位置之前就进行绘制,到结束位置之后不再绘制,
kCGGradientDrawsAfterEndLocation开始位置之前不进行绘制,到结束点之后继续填充
/
CGContextDrawLinearGradient(context,gradient,CGPointZero,CGPointMake(320,300),kCGGradientDrawsAfterEndLocation);
//释放颜色空间
CGColorSpaceRelease(colorSpace);
}
#pragmamark径向渐变
-(void)drawRadialGradient:(CGContextRef)context{
//使用rgb颜色空间
CGColorSpaceRefcolorSpace=CGColorSpaceCreateDeviceRGB();
/指定渐变色
space:颜色空间
components:颜色数组,注意由于指定了RGB颜色空间,那么四个数组元素表示一个颜色(red、green、blue、alpha),
如果有三个颜色则这个数组有43个元素
locations:颜色所在位置(范围0~1),这个数组的个数不小于components中存放颜色的个数
count:渐变个数,等于locations的个数
/
CGFloatcompoents[12]={
248.0/255.0,86.0/255.0,86.0/255.0,1,
249.0/255.0,127.0/255.0,127.0/255.0,1,
1.0,1.0,1.0,1.0
};
CGFloatlocations[3]={0,0.3,1.0};
CGGradientRefgradient=CGGradientCreateWithColorComponents(colorSpace,compoents,locations,3);
/绘制径向渐变
context:图形上下文
gradient:渐变色
startCenter:起始点位置
startRadius:起始半径(通常为0,否则在此半径范围内容无任何填充)
endCenter:终点位置(通常和起始点相同,否则会有偏移)
endRadius:终点半径(也就是渐变的扩散长度)
options:绘制方式,kCGGradientDrawsBeforeStartLocation开始位置之前就进行绘制,但是到结束位置之后不再绘制,
kCGGradientDrawsAfterEndLocation开始位置之前不进行绘制,但到结束点之后继续填充
/
CGContextDrawRadialGradient(context,gradient,CGPointMake(160,284),0,CGPointMake(165,289),150,kCGGradientDrawsAfterEndLocation);
//释放颜色空间
CGColorSpaceRelease(colorSpace);
}
@end
扩展--渐变填充
上面我们只是绘制渐变到图形上下文,实际开发中有时候我们还需要填充对应的渐变色,例如现在绘制了一个矩形,如何填充成渐变色呢?在此可以利用渐变裁切来完成(当然利用层CALayer更加方便但这不在今天的话题讨论范围内),特别说明一下区域裁切并不仅仅适用于渐变填充,对于其他图形绘制仍然适用,并且注意裁切只能限于矩形裁切。
-(void)drawRectWithLinearGradientFill:(CGContextRef)context{
CGColorSpaceRefcolorSpace=CGColorSpaceCreateDeviceRGB();
//裁切处一块矩形用于显示,注意必须先裁切再调用渐变
//CGContextClipToRect(context,CGRectMake(20,50,280,300));
//裁切还可以使用UIKit中对应的方法
UIRectClip(CGRectMake(20,50,280,300));
CGFloatcompoents[12]={
248.0/255.0,86.0/255.0,86.0/255.0,1,
249.0/255.0,127.0/255.0,127.0/255.0,1,
1.0,1.0,1.0,1.0
};
CGFloatlocations[3]={0,0.3,1.0};
CGGradientRefgradient=CGGradientCreateWithColorComponents(colorSpace,compoents,locations,3);
CGContextDrawLinearGradient(context,gradient,CGPointMake(20,50),CGPointMake(300,300),kCGGradientDrawsAfterEndLocation);
//释放颜色空间
CGColorSpaceRelease(colorSpace);
}
其他状态设置
常用的图形上下文状态设置上面基本都用到了,我们不再一一解释,这里着重说一下叠加模式和填充模式,初学者对于这两个状态设置往往容易产生疑惑。
叠加模式
使用Quartz2D绘图时后面绘制的图像会覆盖前面的,默认情况下如果前面的被覆盖后将看不到后面的内容,但是有时候这个结果并不是我们想要的,因此在Quartz2D中提供了填充模式供开发者配置调整。由于填充模式类别特别多,因此下面以一个例子来说明:
-(void)drawRectByUIKitWithContext2:(CGContextRef)context{
CGRectrect=CGRectMake(0,130.0,320.0,50.0);
CGRectrect1=CGRectMake(0,390.0,320.0,50.0);
CGRectrect2=CGRectMake(20,50.0,10.0,250.0);
CGRectrect3=CGRectMake(40.0,50.0,10.0,250.0);
CGRectrect4=CGRectMake(60.0,50.0,10.0,250.0);
CGRectrect5=CGRectMake(80.0,50.0,10.0,250.0);
CGRectrect6=CGRectMake(100.0,50.0,10.0,250.0);
CGRectrect7=CGRectMake(120.0,50.0,10.0,250.0);
CGRectrect8=CGRectMake(140.0,50.0,10.0,250.0);
CGRectrect9=CGRectMake(160.0,50.0,10.0,250.0);
CGRectrect10=CGRectMake(180.0,50.0,10.0,250.0);
CGRectrect11=CGRectMake(200.0,50.0,10.0,250.0);
CGRectrect12=CGRectMake(220.0,50.0,10.0,250.0);
CGRectrect13=CGRectMake(240.0,50.0,10.0,250.0);
CGRectrect14=CGRectMake(260.0,50.0,10.0,250.0);
CGRectrect15=CGRectMake(280.0,50.0,10.0,250.0);
CGRectrect16=CGRectMake(30.0,310.0,10.0,250.0);
CGRectrect17=CGRectMake(50.0,310.0,10.0,250.0);
CGRectrect18=CGRectMake(70.0,310.0,10.0,250.0);
CGRectrect19=CGRectMake(90.0,310.0,10.0,250.0);
CGRectrect20=CGRectMake(110.0,310.0,10.0,250.0);
CGRectrect21=CGRectMake(130.0,310.0,10.0,250.0);
CGRectrect22=CGRectMake(150.0,310.0,10.0,250.0);
CGRectrect23=CGRectMake(170.0,310.0,10.0,250.0);
CGRectrect24=CGRectMake(190.0,310.0,10.0,250.0);
CGRectrect25=CGRectMake(210.0,310.0,10.0,250.0);
CGRectrect26=CGRectMake(230.0,310.0,10.0,250.0);
CGRectrect27=CGRectMake(250.0,310.0,10.0,250.0);
CGRectrect28=CGRectMake(270.0,310.0,10.0,250.0);
CGRectrect29=CGRectMake(290.0,310.0,10.0,250.0);
[[UIColoryellowColor]set];
UIRectFill(rect);
[[UIColorgreenColor]setFill];
UIRectFill(rect1);
[[UIColorredColor]setFill];
UIRectFillUsingBlendMode(rect2,kCGBlendModeClear);
UIRectFillUsingBlendMode(rect3,kCGBlendModeColor);
UIRectFillUsingBlendMode(rect4,kCGBlendModeColorBurn);
UIRectFillUsingBlendMode(rect5,kCGBlendModeColorDodge);
UIRectFillUsingBlendMode(rect6,kCGBlendModeCopy);
UIRectFillUsingBlendMode(rect7,kCGBlendModeDarken);
UIRectFillUsingBlendMode(rect8,kCGBlendModeDestinationAtop);
UIRectFillUsingBlendMode(rect9,kCGBlendModeDestinationIn);
UIRectFillUsingBlendMode(rect10,kCGBlendModeDestinationOut);
UIRectFillUsingBlendMode(rect11,kCGBlendModeDestinationOver);
UIRectFillUsingBlendMode(rect12,kCGBlendModeDifference);
UIRectFillUsingBlendMode(rect13,kCGBlendModeExclusion);
UIRectFillUsingBlendMode(rect14,kCGBlendModeHardLight);
UIRectFillUsingBlendMode(rect15,kCGBlendModeHue);
UIRectFillUsingBlendMode(rect16,kCGBlendModeLighten);
UIRectFillUsingBlendMode(rect17,kCGBlendModeLuminosity);
UIRectFillUsingBlendMode(rect18,kCGBlendModeMultiply);
UIRectFillUsingBlendMode(rect19,kCGBlendModeNormal);
UIRectFillUsingBlendMode(rect20,kCGBlendModeOverlay);
UIRectFillUsingBlendMode(rect21,kCGBlendModePlusDarker);
UIRectFillUsingBlendMode(rect22,kCGBlendModePlusLighter);
UIRectFillUsingBlendMode(rect23,kCGBlendModeSaturation);
UIRectFillUsingBlendMode(rect24,kCGBlendModeScreen);
UIRectFillUsingBlendMode(rect25,kCGBlendModeSoftLight);
UIRectFillUsingBlendMode(rect26,kCGBlendModeSourceAtop);
UIRectFillUsingBlendMode(rect27,kCGBlendModeSourceIn);
UIRectFillUsingBlendMode(rect28,kCGBlendModeSourceOut);
UIRectFillUsingBlendMode(rect29,kCGBlendModeXOR);
}
填充模式
前面的示例中已经演示过纯色填充、渐变填充,而有时我们需要按一定的自定义样式进行填充,这种方式有点类似于贴瓷砖的方式。我们知道如果家里贴地板或瓷砖时,通常我们会先选择一种瓷砖样式,根据房间面积我们购买不同量的瓷砖。但是不管买多少,这些瓷砖的样式都是一模一样的。填充模式就是为了达到这种效果而产生的:我们只需要绘制一个瓷砖的样式,然后让程序自动调用这种样式填充指定大小的区域。
Quartz2D支持两种填充模式:有颜色填充和无颜色填充。两种模式使用起来区别很小,有颜色填充就是在绘制瓷砖时就指定颜色,在调用填充时就不用再指定瓷砖颜色;无颜色填充模式就是绘制瓷砖时不用指定任何颜色,在调用填充时再指定具体填充颜色。相比较无颜色填充模式而言,有颜色填充模式更加的灵活,推荐使用。
下面我们具体看一下如何按指定模式进行图形填充:
1.在使用填充模式时首先要构建一个符合CGPatternDrawPatternCallback签名的方法,这个方法专门用来创建“瓷砖”。注意:如果使用有颜色填充模式,需要设置填充色。例如我们定义一个方法drawTile绘制以下瓷砖(有颜色填充):
Tile
2.接着需要指定一个填充的颜色空间,这个颜色空间跟前面绘制渐变的颜色空间不太一样,前面创建渐变使用的颜色空间是设备无关的,我们需要基于这个颜色空间创建一个颜色空间专门用于填充(注意对于有颜色填充创建填充颜色空间参数为NULL,不用基于设备无关的颜色空间创建)。
3.然后我们就可以使用CGPatternCreate方法创建一个填充模式,创建填充模式时需要注意其中的参数,在代码中已经做了一一解释(这里注意对于有颜色填充模式isColored设置为true,否则为false)。
4.最后调用CGContextSetFillPattern方法给图形上下文指定填充模式(这个时候注意最后一个参数,如果是有颜色填充模式最后一个参数为透明度alpa的地址,对于无颜色填充模式最后一个参数是当前填充颜色空间的颜色数组)。
5.绘制图形,这里我们绘制一个矩形。
6.释放资源。
下面是具体代码(包含两种填充模式代码,可以一一运行)
//
//UIView4.m
//Quartz2D
//
//CreatedbyKenshinCuion14-3-17.
//Copyright(c)2014年KenshinCui.Allrightsreserved.
//
#import"KCView.h"
#defineTILE_SIZE20
@implementationKCView
-(void)drawRect:(CGRect)rect{
CGContextRefcontext=UIGraphicsGetCurrentContext();
[selfdrawBackgroundWithColoredPattern:context];
//[selfdrawBackgroundWithPattern:context];
}
#pragmamark-有颜色填充模式
voiddrawColoredTile(voidinfo,CGContextRefcontext){
//有颜色填充,这里设置填充色
CGContextSetRGBFillColor(context,254.0/255.0,52.0/255.0,90.0/255.0,1);
CGContextFillRect(context,CGRectMake(0,0,TILE_SIZE,TILE_SIZE));
CGContextFillRect(context,CGRectMake(TILE_SIZE,TILE_SIZE,TILE_SIZE,TILE_SIZE));
}
-(void)drawBackgroundWithColoredPattern:(CGContextRef)context{
//设备无关的颜色空间
//CGColorSpaceRefrgbSpace=CGColorSpaceCreateDeviceRGB();
//模式填充颜色空间,注意对于有颜色填充模式,这里传NULL
CGColorSpaceRefcolorSpace=CGColorSpaceCreatePattern(NULL);
//将填充色颜色空间设置为模式填充的颜色空间
CGContextSetFillColorSpace(context,colorSpace);
//填充模式回调函数结构体
CGPatternCallbackscallback={0,&drawColoredTile,NULL};
/填充模式
info://传递给callback的参数
bounds:瓷砖大小
matrix:形变
xStep:瓷砖横向间距
yStep:瓷砖纵向间距
tiling:贴砖的方法
isClored:绘制的瓷砖是否已经指定了颜色(对于有颜色瓷砖此处指定位true)
callbacks:回调函数
/
CGPatternRefpattern=CGPatternCreate(NULL,CGRectMake(0,0,2TILE_SIZE,2TILE_SIZE),CGAffineTransformIdentity,2TILE_SIZE+5,2TILE_SIZE+5,kCGPatternTilingNoDistortion,true,&callback);
CGFloatalpha=1;
//注意最后一个参数对于有颜色瓷砖指定为透明度的参数地址,对于无颜色瓷砖则指定当前颜色空间对应的颜色数组
CGContextSetFillPattern(context,pattern,&alpha);
UIRectFill(CGRectMake(0,0,320,568));
//CGColorSpaceRelease(rgbSpace);
CGColorSpaceRelease(colorSpace);
CGPatternRelease(pattern);
}
#pragmamark-无颜色填充模式
//填充瓷砖的回调函数(必须满足CGPatternCallbacks签名)
voiddrawTile(voidinfo,CGContextRefcontext){
CGContextFillRect(context,CGRectMake(0,0,TILE_SIZE,TILE_SIZE));
CGContextFillRect(context,CGRectMake(TILE_SIZE,TILE_SIZE,TILE_SIZE,TILE_SIZE));
}
-(void)drawBackgroundWithPattern:(CGContextRef)context{
//设备无关的颜色空间
CGColorSpaceRefrgbSpace=CGColorSpaceCreateDeviceRGB();
//模式填充颜色空间
CGColorSpaceRefcolorSpace=CGColorSpaceCreatePattern(rgbSpace);
//将填充色颜色空间设置为模式填充的颜色空间
CGContextSetFillColorSpace(context,colorSpace);
//填充模式回调函数结构体
CGPatternCallbackscallback={0,&drawTile,NULL};
/填充模式
info://传递给callback的参数
bounds:瓷砖大小
matrix:形变
xStep:瓷砖横向间距
yStep:瓷砖纵向间距
tiling:贴砖的方法(瓷砖摆放的方式)
isClored:绘制的瓷砖是否已经指定了颜色(对于无颜色瓷砖此处指定位false)
callbacks:回调函数
/
CGPatternRefpattern=CGPatternCreate(NULL,CGRectMake(0,0,2TILE_SIZE,2TILE_SIZE),CGAffineTransformIdentity,2TILE_SIZE+5,2TILE_SIZE+5,kCGPatternTilingNoDistortion,false,&callback);
CGFloatcomponents[]={254.0/255.0,52.0/255.0,90.0/255.0,1.0};
//注意最后一个参数对于无颜色填充模式指定为当前颜色空间颜色数据
CGContextSetFillPattern(context,pattern,components);
//CGContextSetStrokePattern(context,pattern,components);
UIRectFill(CGRectMake(0,0,320,568));
CGColorSpaceRelease(rgbSpace);
CGColorSpaceRelease(colorSpace);
CGPatternRelease(pattern);
}
@end
上下文变换
我们知道在UIKit开发中UIView有一个transform属性用于控件的形变,其实在绘图中我们也经常用到图形形变,这个时候可以借助图形上下文的形变方法来完成。在弄清形变之前我们要清楚图形上下文的坐标原点,因为无论是位移还是旋转都是相对于坐标原点进行的。其实Quartz2D的坐标系同UIKit并不一样,它的坐标原点在屏幕左下方,但是为了统一编程方式,UIKit对其进行了转换,坐标原点统一在屏幕左上角。注意在设置图形上下文形变之前一定要注意保存上下文的初始状态,在使用完之后进行恢复。否则在处理多个图形形变的时候很容易弄不清楚到底是基于怎样的坐标系进行绘图,容易找不到原点(做过html5canvas绘图的朋友对这一点应该很熟悉,在html5中绘图也经常进行状态保存和恢复)。下面通过一个图片的变换演示一下图形上下文的形变(其他图形也是一样的,就不再演示):
//
//KCView2.m
//Quartz2D
//
//CreatedbyKenshinCuion14-3-17.
//Copyright(c)2014年KenshinCui.Allrightsreserved.
//
#import"KCView2.h"
@implementationKCView2
-(void)drawRect:(CGRect)rect{
CGContextRefcontext=UIGraphicsGetCurrentContext();
[selfdrawImage:context];
}
#pragmamark图形上下文形变
-(void)drawImage:(CGContextRef)context{
//保存初始状态
CGContextSaveGState(context);
//形变第一步:图形上下文向右平移40
CGContextTranslateCTM(context,100,0);
//形变第二步:缩放0.8
CGContextScaleCTM(context,0.8,0.8);
//形变第三步:旋转
CGContextRotateCTM(context,M_PI_4/4);
UIImageimage=[UIImageimageNamed:@"photo1.jpg"];
[imagedrawInRect:CGRectMake(0,50,240,300)];
//恢复到初始状态
CGContextRestoreGState(context);
}
@end
扩展--使用CoreGraphics绘制图像
在前面基本绘图部分,绘制图像时使用了UIKit中封装的方法进行了图像绘制,我们不妨看一下使用Quartz2D内置方法绘制是什么效果。
-(void)drawImage2:(CGContextRef)context{
UIImageimage=[UIImageimageNamed:@"image2.jpg"];
//图像绘制
CGRectrect=CGRectMake(10,50,300,450);
CGContextDrawImage(context,rect,image.CGImage);
}
看起来整个图像是倒过来的,原因正是前面说的:在CoreGraphics中坐标系的y轴正方向是向上的,坐标原点在屏幕左下角,y轴方向刚好和UIKit中y轴方向相反。而使用UIKit进行绘图之所以没有问题是因为UIKit中进行了处理,事实上对于其他图形即使使用CoreGraphics绘制也没有问题,因为UIKit统一了编程方式。但是使用CoreGraphics中内置方法绘制图像是存在这种问题的,如何解决呢?
其实图形上下文只要沿着x轴旋转180度,然后向上平移适当的高度即可(但是注意不要沿着z轴旋转,这样得不到想要的结果)。可是通过前面介绍的CGContextRotateCTM方法只能通过沿着z轴旋转,此时不妨使用另外一种方法,那就是在y轴方向缩放-1,同样可以达到想要的效果:
-(void)drawImage2:(CGContextRef)context{
UIImageimage=[UIImageimageNamed:@"image2.jpg"];
CGSizesize=[UIScreenmainScreen].bounds.size;
CGContextSaveGState(context);
CGFloatheight=450,y=50;
//上下文形变
CGContextScaleCTM(context,1.0,-1.0);//在y轴缩放-1相当于沿着x张旋转180
CGContextTranslateCTM(context,0,-(size.height-(size.height-2y-height)));//向上平移
//图像绘制
CGRectrect=CGRectMake(10,y,300,height);
CGContextDrawImage(context,rect,image.CGImage);
CGContextRestoreGState(context);
}
视图刷新
在UIView的drawRect:中绘制的图形会在控件显示的时候调用(而且显示时会重绘所有图形),有时候我们希望绘制内容的显示是实时的,此时我们就需要调用绘图方法重新绘制,但是在iOS开发中不允许开发者直接调用drawRect:方法,刷新绘制内容需要调用setNeedsDisplay方法。下面以一个调整字体大小的界面演示一下视图的刷新。
KCView.h
//
//KCView.h
//RefreshView
//
//CreatedbyKenshinCuion14-3-17.
//Copyright(c)2014年KenshinCui.Allrightsreserved.
//
#import
@interfaceKCView:UIView
@property(nonatomic,copy)NSStringtitle;
@property(nonatomic,assign)CGFloatfontSize;
@end
KCView.m
//
//KCView.m
//RefreshView
//
//CreatedbyKenshinCuion14-3-17.
//Copyright(c)2014年KenshinCui.Allrightsreserved.
//
#import"KCView.h"
@implementationKCView
-(void)drawRect:(CGRect)rect{
NSStringstr=_title;
UIFontfont=[UIFontfontWithName:@"MarkerFelt"size:_fontSize];
UIColorforeignColor=[UIColorredColor];
[strdrawInRect:CGRectMake(100,120,300,200)withAttributes:@{NSFontAttributeName:font,NSForegroundColorAttributeName:foreignColor}];
}
@end
KCMainViewController.m
//
//KCMainViewController.m
//RefreshView
//
//CreatedbyKenshinCuion14-3-17.
//Copyright(c)2014年KenshinCui.Allrightsreserved.
//
#import"KCMainViewController.h"
#import"KCView.h"
@interfaceKCMainViewController(){
KCView_contentView;
NSArray_fontSize;
}
@end
@implementationKCMainViewController
-(void)viewDidLoad{
[superviewDidLoad];
[selfinitLayout];
[selfaddPickerView];
}
-(void)initLayout{
_fontSize=@[@15,@18,@20,@22,@25,@28,@30,@32,@35,@40];
_contentView=[[KCViewalloc]initWithFrame:CGRectMake(0,0,320,300)];
_contentView.backgroundColor=[UIColorwhiteColor];
_contentView.title=@"Helloworld!";
_contentView.fontSize=[_fontSize[0]intValue];
[self.viewaddSubview:_contentView];
}
-(void)addPickerView{
UIPickerViewpicker=[[UIPickerViewalloc]initWithFrame:CGRectMake(0,300,320,268)];
picker.dataSource=self;
picker.delegate=self;
[self.viewaddSubview:picker];
}
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView)pickerView{
return1;
}
-(NSInteger)pickerView:(UIPickerView)pickerViewnumberOfRowsInComponent:(NSInteger)component{
return_fontSize.count;
}
-(NSString)pickerView:(UIPickerView)pickerViewtitleForRow:(NSInteger)rowforComponent:(NSInteger)component{
return[NSStringstringWithFormat:@"%@号字体",_fontSize[row]];
}
-(void)pickerView:(UIPickerView)pickerViewdidSelectRow:(NSInteger)rowinComponent:(NSInteger)component{
_contentView.fontSize=[[_fontSizeobjectAtIndex:row]intValue];
//刷新视图
[_contentViewsetNeedsDisplay];
}
@end
其他图形上下文
前面我们也说过,Quartz2D的图形上下方除了可以绘制到层上还可以绘制到位图、PDF等,这里我们就介绍一下如何利用Quartz2D绘制图像到位图及PDF中。
上面的示例中一直都是在drawRect:方法中利用UIGraphicsGetCurrentContext()方法取得上下文,要得到位图或者PDF的上下文可以利用UIGraphicsBeginImageContext(CGSizesize)和UIGraphicsBeginPDFPageWithInfo(CGRectbounds,NSDictionarypageInfo)方法。位图图形上下文和PDF图形上下文UIKit是不会负责创建的,所以需要用户手动创建,并且在使用完后关闭它。在使用UIKit中系统创建的图形上下文的时候,我们只能在drawRect:方法中使用,由于这两类图形上下文是由我们手动创建的因此可以放到任何方法中调用。此外,这两个方法开启的图形上下文并没有返回值,如果我们要得到我们创建的图形上下文只要在创建上下文之后、关闭之前调用UIGraphicsGetCurrentContext()方法,此时取得的上下文即是我们自己创建的图形上下文。
绘制到位图
下面利用位图图形上下文给一个图片添加水印,在下面的程序中我们首先创建上下文,然后在上下文中绘制图片、直线和文本,最后从当前位图上下文中取得最终形成的新图片显示到界面。
//
//KCMainViewController.m
//Quartz2D
//
//CreatedbyKenshinCuion14-3-17.
//Copyright(c)2014年KenshinCui.Allrightsreserved.
//
#import
#import"KCMainViewController.h"
#import"KCView.h"
#import"KCView2.h"
#import"KCView3.h"
@interfaceKCMainViewController()
@end
@implementationKCMainViewController
-(void)viewDidLoad{
[superviewDidLoad];
UIImageimage=[selfdrawImageAtImageContext];
UIImageViewimageView=[[UIImageViewalloc]initWithImage:image];
imageView.center=CGPointMake(160,284);
[self.viewaddSubview:imageView];
}
#pragmamark利用位图上下文添加水印效果
-(UIImage)drawImageAtImageContext{
//获得一个位图图形上下文
CGSizesize=CGSizeMake(300,188);//画布大小
UIGraphicsBeginImageContext(size);
UIImageimage=[UIImageimageNamed:@"photo2.png"];
[imagedrawInRect:CGRectMake(0,0,300,188)];//注意绘图的位置是相对于画布顶点而言,不是屏幕
//添加水印
CGContextRefcontext=UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context,200,178);
CGContextAddLineToPoint(context,270,178);
[[UIColorredColor]setStroke];
CGContextSetLineWidth(context,2);
CGContextDrawPath(context,kCGPathStroke);
NSStringstr=@"KenshinCui";
[strdrawInRect:CGRectMake(200,158,100,30)withAttributes:@{NSFontAttributeName:[UIFontfontWithName:@"MarkerFelt"size:15],NSForegroundColorAttributeName:[UIColorredColor]}];
//返回绘制的新图形
UIImagenewImage=UIGraphicsGetImageFromCurrentImageContext();
//最后一定不要忘记关闭对应的上下文
UIGraphicsEndImageContext();
//保存图片
//NSDatadata=UIImagePNGRepresentation(newImage);
//[datawriteToFile:@"/Users/kenshincui/Desktop/myPic.png"atomically:YES];
returnnewImage;
}
@end
绘制到PDF
绘制到PDF则要启用pdf图形上下文,PDF图形上下文的创建使用方式跟位图图形上下文是类似的,需要注意的一点就是绘制内容到PDF时需要创建分页,每页内容的开始都要调用一次IGraphicsBeginPDFPage();方法。下面的示例演示了文本绘制和图片绘制(其他图形绘制也是类似的):
//
//KCMainViewController.m
//Quartz2D
//
//CreatedbyKenshinCuion14-3-17.
//Copyright(c)2014年KenshinCui.Allrightsreserved.
//
#import
#import"KCMainViewController.h"
#import"KCView.h"
#import"KCView2.h"
@interfaceKCMainViewController()
@end
@implementationKCMainViewController
-(void)viewDidLoad{
[superviewDidLoad];
[selfdrawContentToPdfContext];
}
#pragmamark利用pdf图形上下文绘制内容到pdf文档
-(void)drawContentToPdfContext{
//沙盒路径(也就是我们应用程序文件运行的路径)
NSArraypaths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSStringpath=[[pathsfirstObject]stringByAppendingPathComponent:@"myPDF.pdf"];
NSLog(@"%@",path);
//启用pdf图形上下文
/
path:保存路径
bounds:pdf文档大小,如果设置为CGRectZero则使用默认值:612792
pageInfo:页面设置,为nil则不设置任何信息
/
UIGraphicsBeginPDFContextToFile(path,CGRectZero,[NSDictionarydictionaryWithObjectsAndKeys:@"KenshinCui",kCGPDFContextAuthor,nil]);
//由于pdf文档是分页的,所以首先要创建一页画布供我们绘制
UIGraphicsBeginPDFPage();
NSStringtitle=@"WelcometoAppleSupport";
NSMutableParagraphStylestyle=[[NSMutableParagraphStylealloc]init];
NSTextAlignmentalign=NSTextAlignmentCenter;
style.alignment=align;
[titledrawInRect:CGRectMake(26,20,300,50)withAttributes:@{NSFontAttributeName:[UIFontsystemFontOfSize:18],NSParagraphStyleAttributeName:style}];
NSStringcontent=@"LearnaboutAppleproducts,viewonlinemanuals,getthelatestdownloads,andmore.ConnectwithotherAppleusers,orgetservice,support,andprofessionaladvicewww.wang027.comfromApple.";
NSMutableParagraphStylestyle2=[[NSMutableParagraphStylealloc]init];
style2.alignment=NSTextAlignmentLeft;
//style2.firstLineHeadIndent=20;
[contentdrawInRect:CGRectMake(26,56,300,255)withAttributes:@{NSFontAttributeName:[UIFontsystemFontOfSize:15],NSForegroundColorAttributeName:[UIColorgrayColor],NSParagraphStyleAttributeName:style2}];
UIImageimage=[UIImageimageNamed:@"applecare_folks_tall.png"];
[imagedrawInRect:CGRectMake(316,20,290,305)];
UIImageimage2=[UIImageimageNamed:@"applecare_page1.png"];
[image2drawInRect:CGRectMake(6,320,600,281)];
//创建新的一页继续绘制其他内容
UIGraphicsBeginPDFPage();
UIImageimage3=[UIImageimageNamed:@"applecare_page2.png"];
[image3drawInRect:CGRectMake(6,20,600,629)];
//结束pdf上下文
UIGraphicsEndPDFContext();
}
@end
CoreImage
利用Quartz2D我们可以绘制各类图形、图像,功能确实强大。用过photoshop的朋友都知道,使用photoshop可以制作各种滤镜特效,那么在iOS中能否实现滤镜呢?在iOS5.0之前这些算法基本全部要靠程序员编程实现,实现过程相当复杂。从iOS5.0开始苹果官方已经提供了CoreImage框架来帮助开发者进行特效制作。
先来看一下滤镜使用过程中常用的基类对象:
CIContext:图像上下文,用于管理整个图片处理过程,不同的图形上下文将利用不同的图像处理硬件进行图像处理(在iOS中可以通过不同的方式创建图像上下文,例如可以创建基于CPU的图像上下方、创建基于GPU的图像上下方以及创建OpenGL优化过的图像上下文)。
CIFilter:图像处理滤镜,每种滤镜有不同的参数设置。
CIImage:CoreImage框架中的图像类型,主要用于输入和输出图像。
在使用滤镜之前我们先要弄清平台主要支持哪些滤镜,以及这些滤镜的方法和参数如何设置,此时不妨使用下面的方法进行打印查看:
#pragmamark查看所有内置滤镜
-(void)showAllFilters{
NSArrayfilterNames=[CIFilterfilterNamesInCategory:kCICategoryBuiltIn];
for(NSStringfilterNameinfilterNames){
CIFilterfilter=[CIFilterfilterWithName:filterName];
NSLog(@"\rfilter:%@\rattributes:%@",filterName,[filterattributes]);
}
}
在iOS7中打印会发现有127中滤镜,如果我们把每种滤镜都介绍一遍恐怕用几章内容也很难介绍详细,事实上也没有这个必要。这些滤镜使用方法是类似的,只是参数设置有所区别。在iOS文档中可以搜索“coreimagefilterreference”一节的内容,里面有每种滤镜的详细介绍和图片使用效果。
使用CoreImage框架创建滤镜效果一般分为以下几步:
1.创建图像上下文CIContext
2.创建滤镜CIFilter
3.创建过滤原图片CIImage
4.调用CIFilter的setValue:forKey:方法为滤镜指定源图片
5.设置滤镜参数【可选】
6.取得输出图片显示或保存
大家都知道在美图秀秀中有一个“增强”功能,利用它可以调整照片的饱和度、亮度、对比度,其实在CoreImage中也有这样一款滤镜,下面就以颜色滤镜来演示一下CoreImage中滤镜的使用。
//
//KCMainViewController.m
//CoreImage
//
//CreatedbyKenshinCuion14-3-17.
//Copyright(c)2014年KenshinCui.Allrightsreserved.
//
#import"KCMainViewController.h"
#defineCONSTROLPANEL_FONTSIZE12
@interfaceKCMainViewController(){
UIImagePickerController_imagePickerController;//系统照片选择控制器
UIImageView_imageView;//图片显示控件
CIContext_context;//CoreImage上下文
CIImage_image;//我们要编辑的图像
CIImage_outputImage;//处理后的图像
CIFilter_colorControlsFilter;//色彩滤镜
}
@end
@implementationKCMainViewController
-(void)viewDidLoad{
[superviewDidLoad];
[selfinitLayout];
}
#pragmamark初始化布局
-(void)initLayout{
//初始化图片选择器
_imagePickerController=[[UIImagePickerControlleralloc]init];
_imagePickerController.delegate=self;
//创建图片显示控件
_imageView=[[UIImageViewalloc]initWithFrame:CGRectMake(0,64,320,502)];
_imageView.contentMode=UIViewContentModeScaleAspectFit;
[self.viewaddSubview:_imageView];
//上方导航按钮
self.navigationItem.title=@"Enhance";
self.navigationItem.leftBarButtonItem=[[UIBarButtonItemalloc]initWithTitle:@"Open"style:UIBarButtonItemStyleDonetarget:selfaction:@selector(openPhoto:)];
self.navigationItem.rightBarButtonItem=[[UIBarButtonItemalloc]initWithTitle:@"Save"style:UIBarButtonItemStyleDonetarget:selfaction:@selector(savePhoto:)];
//下方控制面板
UIViewcontrolView=[[UIViewalloc]initWithFrame:CGRectMake(0,450,320,118)];
//controlView.alpha=0.2;
//controlView.backgroundColor=[UIColorcolorWithRed:46.0/255.0green:178.0/255.0blue:235.0/255.0alpha:1];
[self.viewaddSubview:controlView];
//饱和度(默认为1,大于饱和度增加小于1则降低)
UILabellbSaturation=[[UILabelalloc]initWithFrame:CGRectMake(10,10,60,25)];
lbSaturation.text=@"Saturation";
lbSaturation.font=[UIFontsystemFontOfSize:CONSTROLPANEL_FONTSIZE];
[controlViewaddSubview:lbSaturation];
UISlidersldStaturation=[[UISlideralloc]initWithFrame:CGRectMake(80,10,230,30)];//注意UISlider高度虽然无法调整,很多朋友会说高度设置位0即可,事实上在iOS7中设置为0后是无法拖动的
[controlViewaddSubview:sldStaturation];
sldStaturation.minimumValue=0;
sldStaturation.maximumValue=2;
sldStaturation.value=1;
[sldStaturationaddTarget:selfaction:@selector(changeStaturation:)forControlEvents:UIControlEventValueChanged];
//亮度(默认为0)
UILabellbBrightness=[[UILabelalloc]initWithFrame:CGRectMake(10,40,60,25)];
lbBrightness.text=@"Brightness";
lbBrightness.font=[UIFontsystemFontOfSize:CONSTROLPANEL_FONTSIZE];
[controlViewaddSubview:lbBrightness];
UISlidersldBrightness=[[UISlideralloc]initWithFrame:CGRectMake(80,40,230,30)];
[controlViewaddSubview:sldBrightness];
sldBrightness.minimumValue=-1;
sldBrightness.maximumValue=1;
sldBrightness.value=0;
[sldBrightnessaddTarget:selfaction:@selector(changeBrightness:)forControlEvents:UIControlEventValueChanged];
//对比度(默认为1)
UILabellbContrast=[[UILabelalloc]initWithFrame:CGRectMake(10,70,60,25)];
lbContrast.text=@"Contrast";
lbContrast.font=[UIFontsystemFontOfSize:CONSTROLPANEL_FONTSIZE];
[controlViewaddSubview:lbContrast];
UISlidersldContrast=[[UISlideralloc]initWithFrame:CGRectMake(80,70,230,30)];
[controlViewaddSubview:sldContrast];
sldContrast.minimumValue=0;
sldContrast.maximumValue=2;
sldContrast.value=1;
[sldContrastaddTarget:selfaction:@selector(changeContrast:)forControlEvents:UIControlEventValueChanged];
//初始化CIContext
//创建基于CPU的图像上下文
//NSNumbernumber=[NSNumbernumberWithBool:YES];
//NSDictionaryoption=[NSDictionarydictionaryWithObject:numberforKey:kCIContextUseSoftwareRenderer];
//_context=[CIContextcontextWithOptions:option];
_context=[CIContextcontextWithOptions:nil];//使用GPU渲染,推荐,但注意GPU的CIContext无法跨应用访问,例如直接在UIImagePickerController的完成方法中调用上下文处理就会自动降级为CPU渲染,所以推荐现在完成方法中保存图像,然后在主程序中调用
//EAGLContexteaglContext=[[EAGLContextalloc]initWithAPI:kEAGLRenderingAPIOpenGLES1];
//_context=[CIContextcontextWithEAGLContext:eaglContext];//OpenGL优化过的图像上下文
//取得滤镜
_colorControlsFilter=[CIFilterfilterWithName:@"CIColorControls"];
}
#pragmamark打开图片选择器
-(void)openPhoto:(UIBarButtonItem)btn{
//打开图片选择器
[selfpresentViewController:_imagePickerControlleranimated:YEScompletion:nil];
}
#pragmamark保存图片
-(void)savePhoto:(UIBarButtonItem)btn{
//保存照片到相册
UIImageWriteToSavedPhotosAlbum(_imageView.image,nil,nil,nil);
UIAlertViewalert=[[UIAlertViewalloc]initWithTitle:@"SytemInfo"message:@"SaveSuccess!"delegate:nilcancelButtonTitle:nilotherButtonTitles:@"OK",nil];
[alertshow];
}
#pragmamark图片选择器选择图片代理方法
-(void)imagePickerController:(UIImagePickerController)pickerdidFinishPickingMediaWithInfo:(NSDictionary)info{
//关闭图片选择器
[selfdismissViewControllerAnimated:YEScompletion:nil];
//取得选择图片
UIImageselectedImage=[infoobjectForKey:UIImagePickerControllerOriginalImage];
_imageView.image=selectedImage;
//初始化CIImage源图像
_image=[CIImageimageWithCGImage:selectedImage.CGImage];
[_colorControlsFiltersetValue:_imageforKey:@"inputImage"];//设置滤镜的输入图片
}
#pragmamark将输出图片设置到UIImageView
-(void)setImage{
CIImageoutputImage=[_colorControlsFilteroutputImage];//取得输出图像
CGImageReftemp=[_contextcreateCGImage:outputImagefromRect:[outputImageextent]];
_imageView.image=[UIImageimageWithCGImage:temp];//转化为CGImage显示在界面中
CGImageRelease(temp);//释放CGImage对象
}
#pragmamark调整饱和度
-(void)changeStaturation:(UISlider)slider{
[_colorControlsFiltersetValue:[NSNumbernumberWithFloat:slider.value]forKey:@"inputSaturation"];//设置滤镜参数
[selfsetImage];
}
#pragmamark调整亮度
-(void)changeBrightness:(UISlider)slider{
[_colorControlsFiltersetValue:[NSNumbernumberWithFloat:slider.value]forKey:@"inputBrightness"];
[selfsetImage];
}
#pragmamark调整对比度
-(void)changeContrast:(UISlider)slider{
[_colorControlsFiltersetValue:[NSNumbernumberWithFloat:slider.value]forKey:@"inputContrast"];
[selfsetImage];
}
@end
|
|
|
|
|
|
|
|
|
|
|