【重读iOS】CoreGraphics&Quartz 2D

两者关系

The Quartz 2D API defines a variety of opaque data types in addition to graphics contexts. Because the API is part of the Core Graphics framework, the data types and the routines that operate on them use the CG prefix.

从这段话理解,Quartz 2D只是一套API,CoreGraphic建立了一套图形绘制的体系。CoreGraphic中那些提供图形绘制功能的API,开放出来集合成了Quartz 2D

图形绘制目标

核心为The Graphics Context,即CGContextRef。

A graphics context is an opaque data type (CGContextRef) that encapsulates the information Quartz uses to draw images to an output device

graphics context并不是绘制的输出目标,但是它包含了绘制和输出所需的所有数据,是一个封装。针对不同的输出,有不同的context封装,所以一定程度,可以把context理解为输出目标。或者说对于输出目标,开发者也只能接触到context这个级别了。

总之context包含了绘制所有的参数,这也正是context这类角色的作用,只需要向context里输入绘制要求就可以了,剩余的它来处理。

就这6种输出目标:

绘制目标

PDF跟打印机没什么可说的,bitmap就是生成一个位图,window就是窗口,iOS里就是view,这里的Layer不是跟view一起的CALayer,而是CGLayer。CGLayer作用就是单图形的复用,替代原本用图片做的事,要更高效些。

所以内容就清晰的分为了两大部分: 1. 针对绘制目标的特殊处理,bigmap CGLayer 2. 绘制指令,path color shadow等

绘制指令

1. 路径path

路径是什么?理解这个首先要理解Quartz 2D的绘制模式:

  • 画线条,图形有了
  • 线条构成封闭的图形,填充颜色,有了色块
  • 多层图形时上面的会覆盖下面的,产生混合效果,上下顺序影响最后结果。

所以图形根本是线条,这个线条就是路径。

绘制路径的手段有:

  • 点+连线

CGContextMoveToPoint CGContextAddLineToPoint搞定所有只有直线的图形

  • 圆弧

CGContextAddArcToPoint
这个就是指定圆心、半径、开始角度、结束角度,很好理解

CGContextAddArc
这个画圆弧的逻辑是:当前点+这个方法里的两个点,3个点构成一个夹角,然后画一个圆弧和这两条线都相切。这个方法在画圆角矩形的时候很好用,因为圆弧结束后还会把直线部分也一起画出来。

  • 曲线

双控制点:CGContextAddCurveToPoint

cubic_bezier_curve.gif

单控制点:CGContextAddQuadCurveToPoint

quadratic_bezier_curve.gif

然后是方便的添加矩形、椭圆。变化性最大的就是贝塞尔曲线了,可以模拟很多情况。

路线绘制好后还可以设置样式:

  • 颜色,常用属性之1
  • 宽度,常用属性之2
  • 不常用的还有虚线、线边缘样式(lineCap)、两线连接处样式(lineJoin)
2. 特殊处理
  • 混合模式setBlendMode

graphics context的混合模式,并不是指view和其他view,或layer之间的混合,而是一次绘制过程中,对某个点的多次上色之前的混合。就像绘画时,在鼻子上画了黄色,然后加点白色表现高光。

  • 路线剪切
currentCtx.addRect(CGRect(x: 40, y: 40, width: 100, height: 100))
currentCtx.clip()

之后的绘制只会在被切出来的那个区域,其他区域绘制无效。

3 transform

trasnform是对绘制的坐标进行了转换,前面都是说如何绘制出一个图,有了完整的图形后,可以用trasnform来对它进行整体的转换:移动、旋转、缩放以及这3个的叠加效果。

  • 绘制图形之前应用的transform才有用,如drawImage,addRect
  • CGContextConcatCTM来给context加入transform
  • 背后的原理:
    • 公式:[图片上传失败...(image-cee73b-1534563448369)]
    • 移动矩阵:[图片上传失败...(image-f769f8-1534563448369)]
    • 缩放矩阵:[图片上传失败...(image-c4db7e-1534563448369)]

位图构建

位图是什么?

A bitmap image (or sampled image) is an array of pixels (or samples). Each pixel represents a single point in the image

一个位图就是一个像素数组,每个像素表示图片里的一个点。显示器上的图像都是一个个像素构成的,每个像素有自己的颜色,如果建一个表,把显示器上的每个像素的颜色都记录到表里,这个表数组就是一个位图bitmap。常用的JPEG PNG都是位图,当然这些图片都是压缩过得,内存和像素颜色不是一一对应的,但现实到屏幕之前一定会做解压。

有位图,就有对应的矢量图,它是由一系列计算机指令来描述和记录一幅图,显示之前再从这些指令从新把图绘制出来。

用一个圆来做例子,位图就是一张图,记录了每个位置的像素,跟其他的图没有不同。而矢量图可能就是一个命令:circle(radius:5,center:(20,20),color:...)

矢量图可能就要依赖于系统对指令的解析,而且绘制也需要消耗性能,但存储和传输更方便,而且一个很大的好处是可以应对不同的分辨率。

回到Quartz 2D,bitmap的context的作用就是把绘制的截图输出到一张图片里,常见的应用就是屏幕截图了。

核心方法:

  • CGImageCreate直接从纯数据构建,指定所有格式
  • CGBitmapContextCreateImage从当前的位图上下文里构建图片,配合CGContextDrawImage把图绘制进去,内部把图片解压
  • CGImageCreateWithImageInRect从已有图截取一部分
  • CGImageCreateWithPNGDataProviderCGImageCreateWithJPEGDataProvider从图片文件构建,配合CGDataProviderCopyData,内部把图片解压

mask

mask在对个地方可以见到:这里的mask,CALayer里的mask,就是圆角的那个,哈希表里也有mask。总的来说就就是使用一种规则屏蔽掉某些数据,图像之间处理的mask,像这里,一般是根据alpha数据来的。alpha>0的地方图像显示,alpha==0的地方图像屏蔽。

  • CGImageCreateWithMask使用一个mask来处理原图,跟文档里说的并不同,mask原图的alpha是1的地方才是显示出来的地方,公式应该是a*s+(1-a)*m,a是mask的原图的alpha,s是要显示的图片,m是mask原图。
  • mask是用CGImageMaskCreate构建的特殊图片,应该只包含灰度信息
  • 不使用专门的mask方法,也可以使用图片之间构建的mask,但是需要颜色空间为灰度。
  • 使用颜色剔除,CGImageCreateWithMaskingColors,传入一个数组,依次表示每个元素的最小值和最大值,在这个范围内的颜色都被剔除,不显示。

CGLayer

CAlayer是负责view的内容显示的,而CGLayer和它完全不同,它并不做显示,而是存储。构造一个样式,比如自己绘制一个小星星,然后要重用这个小星星,两个方案:1. 使用bitmap,即把绘制的小星星变成一张图,想怎么用都可以。 2.使用CGLayer保存绘制结果。

可以理解CGLayer为对一个图形的引用、保存,可以在需要的地方绘制出来,可以看成是一种特殊的图片,消耗更小、更高效复用的图片。

除了重复绘制,高性能离屏渲染(High-quality offscreen),缓冲数据(Buffering)时也可以使用。Buffering的场景不是很清楚,但High-quality offscreen可以用于复杂图形的副线程绘制,在副线程把复杂图形绘制出来,然后存储在CGLayer里,在显示的时候直接显示,略去绘制过程的性能影响。

核心方法:

  • 构建CGLayerCreateWithContext
  • 获取它的contextCGLayerGetContext
  • 有了context,就可以在这个context里使用Quartz 2D的API绘制任意的内容
  • 使用CGContextDrawLayerAtPoint,把这个CGLayer绘制到另一个Graphic Context里,这个Graphic Context才是真正显示的那个。就像把一张贴纸贴到一张大图画上。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • 在农村 邻居基本都认识几十年了 知根知底,熟得不能再熟 人一旦熟起来 总是要聊天的 也没有那么多新鲜事 所以聊天八...
    吃瓜娃娃瞎扯淡阅读 223评论 0 0
  • 最近写了一篇2016年成就事件,不经意间收获了许多鲜花和掌声,不自觉的就飘起来了,更加奋力的去追求数字带来的快感,...
    1苏苏阅读 229评论 1 2
  • 白居易于千年前看到苏家小女简简,轻轻浅浅的一句“大都好物不坚牢,彩云易散琉璃脆”道出了多少世事变迁的心酸。千年后,...
    栖墨阅读 876评论 6 10
  • 《乖,摸摸头》记录了12个感人的故事。真实的故事流露出真挚的感情,也流露出作者大冰对朋友的思念。我觉得大冰是个很了...
    此之木阅读 1,047评论 2 2