Quartz 2D编程指南 (五) —— Paths路径(二)

版本记录

版本号 时间
V1.0 2018.09.04

前言

Quartz 2D框架相信大家都知道,也都一直在使用。Quartz 2D的API是纯C语言的,它是一个二维绘图引擎,同时支持iOS和Mac系统。Quartz 2D的API来自于Core Graphics框架,数据类型和函数基本都以CG作为前缀,接下来几篇我们就一起来看一下这个框架。感兴趣可以看上面几篇文章。
1. Quartz 2D编程指南 (一) —— 简介(一)
2. Quartz 2D编程指南 (二) —— Quartz 2D概览(二)
3. Quartz 2D编程指南 (三) —— 图形上下文(三)
4. Quartz 2D编程指南 (四) —— Paths路径(一)

Painting a Path - 绘制路径

您可以通过描边或填充或两者都参与来绘制当前路径。 描边画一条跨越路径的线。 填充绘制路径中包含的区域。 Quartz具有允许您描边路径,填充路径或者描边和填充路径的功能。 描边线(宽度,颜色等)的特征,填充颜色以及Quartz用于计算填充区域的方法都是图形状态的一部分(参见 Graphics States)。

1. Parameters That Affect Stroking - 影响描边的参数

您可以通过修改表3-1中列出的参数来影响路径的描边方式。 这些参数是图形状态的一部分,这意味着您为参数设置的值会影响所有后续描边,直到您将参数设置为另一个值。

Table 3-1 Parameters that affect how Quartz strokes the current path

line width是线的总宽度,以用户空间为单位表示。 该线横跨路径,两侧总宽度的一半。

line join指定Quartz如何绘制连接线段之间的连接。 Quartz支持表3-2中描述的线连接样式。 默认样式是斜接连接miter join

Table 3-2 Line join styles

line cap指定CGContextStrokePath用于绘制线的端点的方法。 Quartz支持表3-3中描述的线帽样式。 默认样式是对接上限butt cap

Table 3-3 Line cap styles

封闭的子路径将起点视为连接线段之间的连接点;使用选定的line-join方法呈现起点。 相反,如果通过添加连接到起点的线段来关闭路径,则使用选定的线帽方法绘制路径的两端。

line dash pattern - 线条虚线图案允许您沿着描边路径绘制分段线。 您可以通过将破折号数组和破折号阶段指定为CGContextSetLineDash的参数来控制破折号线段的大小和位置:

void CGContextSetLineDash (
    CGContextRef ctx,
    CGFloat phase,
    const CGFloat lengths[],
    size_t count
);

长度lengths参数的元素指定短划线的宽度,在线的绘制和未绘制段之间交替。 phase参数指定破折号模式的起始点。 图3-11显示了一些线划线图案。

Figure 3-11 Examples of line dash patterns

描边颜色空间color space决定了Quartz如何解释描边颜色空间。 您还可以指定封装颜色和颜色空间的Quartz颜色(CGColorRef数据类型)。 有关设置颜色空间和颜色的详细信息,请参阅Color and Color Spaces

2. Functions for Stroking a Path - 描边路径的函数

Quartz提供表3-4中所示的功能,用于描边当前路径。 一些是用于描边矩形或椭圆的便利函数。

Table 3-4 Functions that stroke paths

函数CGContextStrokeLineSegments等效于以下代码:

CGContextBeginPath (context);
for (k = 0; k < count; k += 2) {
    CGContextMoveToPoint(context, s[k].x, s[k].y);
    CGContextAddLineToPoint(context, s[k+1].x, s[k+1].y);
}
CGContextStrokePath(context);

当您调用CGContextStrokeLineSegments时,您将线段指定为点数组,按对进行组织。 每对由线段的起点和线段的终点组成。 例如,数组中的第一个点指定第一行的起始位置,第二个点指定第一行的结束位置,第三个点指定第二行的起始位置,依此类推。

3. Filling a Path - 填充路径

填充当前路径时,Quartz就像关闭路径中包含的每个子路径一样。然后它使用这些封闭的子路径并计算要填充的像素。 Quartz可以通过两种方式计算填充区域。椭圆形和矩形等简单路径具有明确的区域。但是,如果路径由重叠的段组成,或者路径包含多个子路径,例如图3-12中所示的同心圆,则可以使用两个规则来确定填充区域。

默认填充规则称为非零绕组编号规则- nonzero winding number rule。要确定是否应绘制特定点,请从该点开始并绘制超出图形边界的线。从计数0开始,每次路径段从左到右穿过该行时,向计数加1,并且每当路径段从右到左穿过该行时,减去1。如果结果为0,则不绘制该点。否则,该点被绘制。绘制路径段的方向会影响结果。图3-12显示了使用非零绕组编号规则填充的两组内圆和外圆。当每个圆圈以相同方向绘制时,两个圆圈都被填充。当圆圈以相反方向绘制时,内圆圈未被填充。

您可以选择使用偶数规则 - even-odd rule。要确定是否应绘制特定点,请从该点开始并绘制超出图形边界的线。计算线穿过的路径段的数量。如果结果是奇数,则绘制该点。如果结果是偶数,则不绘制点。绘制路径段的方向不会影响结果。如图3-12所示,每个圆的绘制方向无关紧要,填充将始终如图所示。

Quartz提供表3-5中所示的函数,用于填充当前路径。 一些是用于描边矩形或椭圆的便利函数。

Table 3-5 Functions that fill paths

4. Setting Blend Modes - 设置混合模式

混合模式(Blend modes)指定Quartz如何在背景上进行绘制。 Quartz默认使用普通混合模式,它使用以下公式将前景绘画与背景绘画相结合:

result =(alpha * foreground)+(1 - alpha)* background

Color and Color Spaces提供了颜色的alpha分量的详细讨论,它指定颜色的不透明度。对于本节中的示例,您可以假设颜色完全不透明(alpha值= 1.0)。对于不透明的颜色,当您使用普通混合模式进行绘制时,在背景上绘制的任何内容都会完全遮盖背景。

您可以通过调用函数CGContextSetBlendMode设置混合模式以实现各种效果,并传递适当的混合模式常量。请记住,混合模式是图形状态的一部分。如果在更改混合模式之前使用CGContextSaveGState函数,则调用函数CGContextRestoreGState会将混合模式重置为normal

本节的其余部分显示了在图3-14中所示的矩形上绘制图3-13中所示矩形的结果。在每种情况下(图3-15至图3-30),使用普通混合模式绘制背景矩形。然后通过使用适当的常量调用函数CGContextSetBlendMode来更改混合模式。最后,绘制前景矩形。

Figure 3-13 The rectangles painted in the foreground
Figure 3-14 The rectangles painted in the background

注意:您还可以使用混合模式合成两个图像,或者将图像合成到已经绘制到图形上下文的任何内容上。 Using Blend Modes with Images可提供有关如何使用混合模式合成图像的信息,并显示将混合模式应用于两个图像的结果。

(1)Normal Blend Mode - 正常混合模式

由于普通混合模式是默认的混合模式,因此只使用常量kCGBlendModeNormal调用函数CGContextSetBlendMode,以便在使用其他混合模式常量之一后将混合模式重置为默认值。 图3-15显示了使用普通混合模式绘制图3-14上绘制图3-13的结果。

Figure 3-15 Rectangles painted using normal blend mode
(2)Multiply Blend Mode - 乘法混合模式

乘法混合模式指定将前景图像样本与背景图像样本相乘。 得到的颜色至少与两种样本颜色中的任何一种颜色一样深。 图3-16显示了使用乘法混合模式绘制图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeMultiply调用函数CGContextSetBlendMode

Figure 3-16 Rectangles painted using multiply blend mode
(3) Screen Blend Mode - 屏幕混合模式

屏幕混合模式指定将前景图像样本的倒数与背景图像样本的倒数相乘。 得到的颜色至少与两种样本颜色中的任何一种颜色一样浅。 图3-17显示了使用屏幕混合模式绘制图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeScreen调用函数CGContextSetBlendMode

Figure 3-17 Rectangles painted using screen blend mode
(4) Overlay Blend Mode - 叠加混合模式

叠加混合模式指定将前景图像样本与背景图像样本相乘,具体取决于背景颜色。 背景颜色与前景色混合以反映背景的亮度或暗度。 图3-18显示了使用叠加混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeOverlay调用函数CGContextSetBlendMode

Figure 3-18 Rectangles painted using overlay blend mode
(5) Darken Blend Mode - 变暗混合模式

指定通过选择较暗的样本(来自前景图像或背景)来创建合成图像样本。 背景图像样本被任何较暗的前景图像样本替换。 否则,背景图像样本保持不变。 图3-19显示了使用变暗混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeDarken调用函数CGContextSetBlendMode

Figure 3-19 Rectangles painted using darken blend mode
(6) Lighten Blend Mode - 减轻混合模式

指定通过选择较亮的样本(来自前景或背景)来创建合成图像样本。 结果是背景图像样本被任何较轻的前景图像样本替换。 否则,背景图像样本保持不变。 图3-20显示了使用淡化混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeLighten调用函数CGContextSetBlendMode

Figure 3-20 Rectangles painted using lighten blend mode
(7) Color Dodge Blend Mode - 颜色减淡混合模式

指定使背景图像样本变亮以反映前景图像样本。 指定黑色的前景图像样本值不会产生更改。 图3-21显示了使用颜色减淡混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeColorDodge调用函数CGContextSetBlendMode

Figure 3-21 Rectangles painted using color dodge blend mode
(8) Color Burn Blend Mode - 彩色混合模式

指定使背景图像样本变暗以反映前景图像样本。 指定白色的前景图像样本值不会产生更改。 图3-22显示了使用彩色混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeColorBurn调用函数CGContextSetBlendMode

Figure 3-22 Rectangles painted using color burn blend mode
(9) Soft Light Blend Mode - 柔光混合模式

指定使颜色变暗或变亮,具体取决于前景图像样本颜色。 如果前景图像样本颜色浅于50%灰色,则背景会变亮,类似于dodging。 如果前景图像样本颜色深于50%灰色,则背景变暗,类似于burning。 如果前景图像样本颜色等于50%灰色,则不更改背景。 等于纯黑色或纯白色的图像样本会产生较暗或较亮的区域,但不会产生纯黑色或白色。 整体效果类似于通过在前景图像上照射漫反射聚光灯所实现的效果。 使用此选项可为场景添加高光。 图3-23显示了使用柔和光混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeSoftLight调用函数CGContextSetBlendMode

Figure 3-23 Rectangles painted using soft light blend mode
(10) Hard Light Blend Mode - 硬光混合模式

指定乘法或screen颜色,具体取决于前景图像样本颜色。 如果前景图像样本颜色浅于50%灰色,则背景会变亮,类似于screening。 如果前景图像样本颜色深于50%灰色,则背景变暗,类似于相乘。 如果前景图像样本颜色等于50%灰度,则不更改前景图像。 等于纯黑色或纯白色的图像样本产生纯黑色或白色。 整体效果类似于通过在前景图像上发出刺眼的聚光灯而实现的效果。 使用此选项可为场景添加高光。 图3-24显示了使用硬光混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeHardLight调用函数CGContextSetBlendMode

Figure 3-24 Rectangles painted using hard light blend mode
(11) Difference Blend Mode - 差异混合模式

指定从背景图像样本颜色中减去前景图像样本颜色,或reverse,根据哪个样本具有更高的亮度值。 黑色的前景图像样本值不会产生任何变化; 白色反转背景颜色值。 图3-25显示了使用差异混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeDifference调用函数CGContextSetBlendMode

Figure 3-25 Rectangles painted using difference blend mode
(12) Exclusion Blend Mode - 排除混合模式

指定与kCGBlendModeDifference生成的效果类似的效果,但对比度较低。 黑色的前景图像样本值不会产生变化; 白色反转背景颜色值。 图3-26显示了使用排除混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeExclusion调用函数CGContextSetBlendMode

Figure 3-26 Rectangles painted using exclusion blend mode
(13) Hue Blend Mode - 色调混合模式

指定使用背景的亮度和饱和度值以及前景图像的色调。 图3-27显示了使用色调混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeHue调用函数CGContextSetBlendMode

Figure 3-27 Rectangles painted using hue blend mode
(14) Saturation Blend Mode - 饱和度混合模式

指定使用背景的亮度和色调值以及前景图像的饱和度。 没有饱和的背景区域(即纯灰色区域)不会产生变化。 图3-28显示了使用饱和度混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeSaturation调用函数CGContextSetBlendMode

Figure 3-28 Rectangles painted using saturation blend mode
(15) Color Blend Mode - 颜色混合模式

指定使用背景的亮度值以及前景图像的色调和饱和度值。 此模式保留图像中的灰度级。 您可以使用此模式为单色图像着色或着色彩色图像。 图3-29显示了使用颜色混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeColor调用函数CGContextSetBlendMode

Figure 3-29 Rectangles painted using color blend mode
(16) Luminosity Blend Mode - 亮度混合模式

指定使用背景的色调和饱和度以及前景图像的亮度。 此模式创建的效果与kCGBlendModeColor创建的效果相反。 图3-30显示了使用光度混合模式在图3-14上绘制图3-13的结果。 要使用此混合模式,请使用常量kCGBlendModeLuminosity调用函数CGContextSetBlendMode

Figure 3-30 Rectangles painted using luminosity blend mode

Clipping to a Path - 剪切路径

当前剪切区域(current clipping area )是从用作蒙版的路径创建的,允许您阻止不想绘制的页面部分。例如,如果您有一个非常大的位图图像并且只想显示它的一小部分,则可以将剪切区域设置为仅显示您要显示的部分。

绘制时,Quartz仅在剪切区域内渲染绘制。在剪切区域的封闭子路径内发生的绘图是可见的;在剪切区域的闭合子路径之外发生的绘制不是。

最初创建图形上下文时,剪切区域包括上下文的所有可绘制区域(例如,PDF上下文的媒体框)。您可以通过设置当前路径然后使用剪切功能而不是绘图功能来更改剪切区域。剪切功能将当前路径的填充区域与现有剪切区域相交。因此,您可以与剪切区域相交,缩小图片的可见区域,但不能增加剪裁区域的面积。

剪切区域是图形状态的一部分。要将剪切区域恢复到先前的状态,可以在剪切之前保存图形状态,并在完成剪切绘图后恢复图形状态。

Listing 3-1显示了一个代码片段,用于设置圆形的剪切区域。此代码会导致绘图被剪裁,类似于图3-3中所示。 (有关另一个示例,请参阅Gradients一章中的Clip the Context。)

// Listing 3-1  Setting up a circular clip area

CGContextBeginPath (context);
CGContextAddArc (context, w/2, h/2, ((w>h) ? h : w)/2, 0, 2*PI, 0);
CGContextClosePath (context);
CGContextClip (context);

Table 3-6 Functions that clip the graphics context

后记

本篇主要讲述了Paths路径,感兴趣的给个赞或者关注~~~

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

推荐阅读更多精彩内容