美文网首页
路径(Paths)—— Quartz 2D编程指导翻译 第4篇

路径(Paths)—— Quartz 2D编程指导翻译 第4篇

作者: 己庚辛壬癸 | 来源:发表于2017-12-05 16:05 被阅读55次

    本文翻译自苹果官方文档:原文地址

    路径(Paths)

    一个路径定义了一个或者多个形状或子路径。一个子路径可以包含:直线、曲线,或者两者都包含;它们可以闭合也可以不闭合。一个子路径可以是简单的形状,例如:一条线、一个圆、一个矩形、一个星星或者更复杂的形状(如山的轮廓、涂鸦等)。图 3-1 展示了你能够创建的一些路径。左上角的直线是虚线,同样,它也可以是实线。中上方的弯弯曲曲的路径是由若干的曲线构成的,它是一个开放的路径。右上方的同心圆做了填充,没有做描边。加州(加利福利亚)是由若干曲线和直线构成的闭合路径,这个路径既做了填充又做了描边。下面的星星说明了填充路径的两个选项,你将在本章后面阅读。

    图 3-1 Quartz 支持的基于路径的绘画

    在本章中,你将会学到如何创建路径、描边和填充路径、影响路径显示的参数。

    路径的创建和路径的绘制(Painting)

    路径的创建和路径的绘制是两个不相关的任务。首先,你需要创建一个路径;当你想渲染一个路径时,你请求Quartz绘制它。正如 图 3-1 所示,你能够选择对路径进行描边,也能够选择对路径填充,还可以既对路径做填充又对路径做描边。同样,你也可以使用路径来限制其他对象的绘制(在路径创建的bounds之内),也即是,裁剪区域(clipping area)。

    图 3-2 展示了绘制的一个路径。该路径包含两个子路径,左边的子路径是一个矩形,右边的子路径是一个由曲线和直线构成的路径;这两个子路径都进行描边和填充。

    图 3-2 包含两个子路径的路径

    图 3-3 展示了独立绘制的多个路径。每一个路径都包含一个随机创建的曲线,有些做了填充,有些做了描边。这些路径是在一个裁剪区域中进行绘制的。

    图 3-3 裁剪区域内的绘制

    构建块(The Building Blocks)

    子路径由线、弧、和曲线构成。Quartz同样提供了方便的方法来添加矩形、椭圆。点也同样是基本的构建块,因为点定义了图形的起点和终点。

    点(Points)

    点是用户空间坐标系下的坐标(x,y的值)。你可以使用函数CGContextMoveToPoint来指定一个新路径的起始位置。Quartz对当前的点保持了记录,当前点(Current Point)就是创建路径的最后一个位置。例如当你调用CGContextMoveToPoint来把位置设置到(10,10),当前点的位置也就变成了(10,10)。接着,如果你在水平方向上绘制了50个单位长度后,当前点就变成了(60,10)。线、弧、曲线总是从当前点开始绘制的。

    大多数情况下,可以通过传入两个浮点类型的值,来指定点的位置;有些函数则要求传入CGPoint类型的值来指定位置。

    线(Lines)

    一条线是由它的终点定义的,它的起点始终是当前点(current point)。当你创建一条线时,你仅仅需要只指定它的终点。使用函数CGContextAddLineToPoint来追加一条线到子路径。

    同样,你也可以通过函数CGContextAddLines来添加一系列相关联的线。在这个函数中,你需要传入一个数组,数组中的第一个点必须是第一条线的起点,接下来的点就依次是终点。Quartz在第一个点的地方开始了一个新的子路径,它们是由线段连起来的点。

    弧(Arcs)

    弧是圆的一部分。Quartz 提供了创建弧的两种方法。CGContentAddArc方法能够创建一个属于指定圆的某部分的弧。因此,你需要在方法中指定圆心、半径、弧度。如果你想创建一个完整的圆,你只需要指定弧度为2π。图 3-4 展示了独立绘制的多个路径,每个路径都是随机创造的圆,有些描边、有些填充。

    图 3-4 随机创造的圆

    当你想使矩形拥有圆角的时候,通常可以使用CGContextAddArcToPoint方法(当然这个方法也不局限于给矩形做圆角)。Quartz 使用你提供的两个终点,结合当前点来创造两条切线(实际上就是两条直线,第一条是:经过当前点和第一个终点的直线;第二条是:经过依次指定的两个终点的直线);同样,你还需要指定一个圆弧的半径。之所以叫这两条线为切线,是因为,最终的圆弧都将与两条切线相切,且半径等于指定的半径。 如图 3-5 所示 红色部分就是实际绘制的部分。

    图 3-5 由两条切线和半径定义弧

    ps:大家可能会对这个方法不是很好理解。经过查阅官方的详细API介绍得知:两个切点(弧和切线的交点),分别为弧的起点和终点;如果弧的起点不是当前点(current point),那么绘制出的结果中会额外添加一条由当前点到弧起点的线段。使用该方法之后,弧终点就变成了当前上下文的起点。官方API详细描述

    曲线(Curves)

    二阶和三阶贝塞尔曲线都是代数曲线,可以用来描述任意数量的有趣的曲线形状。对起点和终点以及控制点(一个或多个)使用一个多项式计算出了这些曲线上的每个点。这是定义矢量图的基本方法。使用一个多项式来保存这些点的信息,比起使用数组来说显得十分精简,而且它的优点是,你可以在任何情况下重新创建这些曲线。

    图 3-6 展示了大量的随机独立绘制的曲线,有些填充,有些描边。

    图 3-6 独立的随机曲线

    对于描述二阶和三阶贝塞尔曲线的多项式以及如何从这些多项式中创造曲线在大多数的数学相关书籍中都可以看得到,本篇文章就不进行讨论了。

    使用CGContextAddCurevToPoint方法,用你指定的控制点(control points)和终点(endpoint)从当前点追加一个三阶贝塞尔曲线。图 3-7 展示了由这些因素创建的贝塞尔曲线。控制点的位置决定了曲线的几何形状,如果控制点都在起点和终点的上方,那么曲线的拱是向上的,反之,如果控制点都在起点和终点的下方,那么拱朝下。

    图 3-7 使用2个控制点创建的三阶贝塞尔曲线

    你可以使用CGContextAddQuadCurveToPoint方法、你指定的终点和一个控制点来为当前点添加一个二阶贝塞尔曲线。图 3-8 展示了对于相同的起点和终点,不同的控制点对曲线的影响。控制点决定了曲线拱的方向,你不能够使用二阶的贝塞尔曲线来创造任意你想爱那个创造的形状,但是你可以使用三阶贝塞尔曲线来实现他,因为二阶贝塞尔曲线仅仅使用了一个控制点;例如,你不可能用一个单一的控制点来创建一个交叉曲线(For example, it’s not possible to create a crossover using a single control point.)。

    图 3-8 二阶贝塞尔曲线
    关闭一个子路径(Closing a Subpath)

    在应用程序中,使用CGContextClosePath来关闭当前的子路径。这个函数会添加一条从当前点到起点的线段,然后关闭这个子路径。当直线、圆弧、曲线在起点结束时,并没有关闭这个子路径,你必须通过调用CGContextClosePath来关闭它。

    当你的应用程序关闭子路径时,有些Quartz函数会处理他们,这些函数为每一个关闭了的子路径从当前点到起点的线段。

    在关闭一个子路径之后,应用程序的其添加路径操作,如:添加直线、圆弧、曲线等都会视为一个新的子路径,这个子路径的起点就是你刚刚关闭的子路径的起点。

    椭圆(Ellipses)

    一个椭圆看起来就像是一个被压扁了的圆。通过指定两个焦点,然后在找出到到两个焦点之和为一个你指定值的所有点,它们所构成的曲线就是椭圆。图 3-9 展示了随机绘制、填充或描边的椭圆。

    图 3-9 独立绘制的椭圆

    使用CGContextAddEllipseInRect方法来为当前的路径添加一个椭圆。该方法中指定的矩形描述了椭圆的边界。Quartz使用一系列恰当的贝塞尔曲线来表示这个椭圆,椭圆的中心和你指定的矩形的中心是相同的,如果矩形是正方形,那么得到的椭圆就是圆;如果不是正方形,那么它定义了椭圆的主轴和副轴。

    使用该方法添加到路径的椭圆,以一个move-to操作开始,close-subpath操作结束。并且它是顺时针绘制的。

    矩形(Rectangles)

    你可以使用CGContextAddRect添加一个矩形到当前的路径,在这个方法中,你需要指定一个带有起点和宽高的矩形。

    这种方法添加的矩形,以move-to操作开始,close-subpath操作结束,但是与椭圆不同的是,它是逆时针绘制的。

    同样的你也可以通过CGContextAddRects来为当前路径添加多个矩形。图 3-10 展示了随机绘制、填充或描边的矩形。

    图 3-10 独立绘制的矩形

    创建一个路径(Creating a Path)

    当你想在一个图形上下文中创建一个路径时;首先,你要使用CGContextBeginPath给Quartz发送一个开启的路径的信号;接着,调用CGContextMoveToPoint来为你的第一个形状或者路径指定一个起始点;在你指定了这个点之后,你就可以添加直线、圆弧、以及曲线,你需要记住:

    • 在开始一个新路径之前调用CGContextBeginPath
    • 线、圆弧、曲线都是从当前点开始绘制的。一个空的路径没有当前点;你必须调用CGContextMoveToPoint或者一个包含该做法的函数,来为你的第一个形状或者子路径设置起始点。
    • 当你想要关闭一个路径的子路径时,调用CGContextClosePath来实现它,该方法会添加一个当前点到起始点的线段。即是你没有指定一个起点,随后的其他路径操作,都会开始一个新的子路径。
    • 当你在绘制弧时,Quartz会额外添加一条由当前点到起始点的线段。
    • 在添加矩形和椭圆时,Quartz会默认添加一个新的关闭的子路径。
    • 如果你想看见你路径,你必对它们进行须填充或者描边。详见文中的:绘制一个路径

    当你绘制完一个路径后,图形上下文中就不再包含该路径的信息。在某些情况下,特别是在该路径表达的场景很复杂时,你可能想重用该路径;也正是出于这个原因,Quartz提供了两种数据类型来创建可以重用的路径:CGPathRefCGMutablePathRef。调用CGPathMutableCreate来创建一个可以修改的CGPath对象,你能够为其添加直线、圆弧、曲线以及矩形。Quartz提供了很多平行的在文中构建块讨论的方法。这些方式被用于对CGPath操作(而不是图形上下文)。这些方法是:

    • CGPathCreateMutable,代替 CGContextBeginPath
    • CGPathMoveToPoint,代替 CGContextMoveToPoint
    • CGPathAddLineToPoint,代替 CGContextAddLineToPoint
    • CGPathAddCurveToPoint,代替 CGContextAddCurveToPoint
    • CGPathAddEllipseInRect,代替 CGContextAddEllipseInRect
    • CGPathAddArc,代替 CGContextAddArc
    • CGPathAddRect,代替 CGContextAddRect
    • CGPathCloseSubpath,代替 CGContextClosePath

    如果想要了解完整的函数列表,去查看 Quartz 2D Reference Collection文档。

    当你想为当前路径添加一个Path时,调用CGContextAddPath,这个路径的状态在被绘制之前都会存在与图形上下文。你可以调用CGContextAddPath来再一次添加之前的路径。

    你可以通过CGContextReplacePathWithStrokedPath方法来替换图形上下文中的路径(用一个原路径的描边来替换)。

    绘制一个路径(Painting a Path)

    你可以对当前路径进行,描边、填充、或者两者都。描边就是对路径使用一条线在外边缘绘制,填充则是填充路径内部的内容。Quartz为填充、描边或者两者都实现提供了函数。描边线的特征以及填充的颜色、计算方式,都是属于当前图形状态的一部分(详见:图形状态)。

    影响描边的参数

    可以通过 表 3-1 中的参数来控制描边的样式。这些参数是图形状态的一部分,这也就意味着,一旦你设置了这些参数的值后,它将会影响接下来的描边,直到你为其设置了新的值。

    表 3-1 影响描边的参数

    参数 设置参数的函数
    Line width CGcontextSetLineWidth
    Line join CGContextSetLineJoin
    Line cap CGContextSetLineCap
    Miter limit CGContextSetMiterLimit
    Line dash pattern CGContextSetLineDash
    Stroke color space CGContextSetStrokeColorSpace
    Stroke color CGContextSetStrokeColor、CGContextSetStrokeColorWithColor
    Stroke pattern CGContextSetStrokePattern
    • line width 表示线的总宽度,它的单位是在用户空间内的单位。线横跨路径,在路径的两侧各占总宽度的一半。
    • line join 指定了Quartz如何处理两条教诲的线段。Quartz支持的line join 样式在 表3-2 中描述,默认的值是 miter join。

    表 3-2 Line join styles

    样式(Style) 展示(Appearance) 描述(Description)
    Miter join Quartz扩展两条线段的外边缘,直到它们组成一个角度,就像相框一样。如果线段组成的角度太尖锐了,就会使用bevel join 的样式来连接;如果miter除以线宽大于miter limit的话,我们就判定它太尖锐
    Round join Quartz使用一个直径为线宽(line width)的半圆连接外缘,半圆内部的区域是被填充的。
    Bevel join Quartz finishes the two segments with butt caps. The resulting notch beyond the ends of the segments is filled with a triangle.
    • line cap 指明了CGContextStrokePath函数绘制线终点的方式。Quartz 支持的 line cap 样式都列在 表 3-3 中,默认的样式是 butt cup。

    表 3-3 Line cap 的样式

    样式(Style) 展示(Appearance) 描述(Description)
    Butt cap Quartz 对于描边的端点直接切断,没有任何的补充填充
    Round cap Quartz 在两条边缘(上下边缘)线段交汇的地方绘制一个直径为line width 的圆,圆内部的区域是被填充的。
    Projecting square cap Quartz 在两端扩展一半 line width 的长度的矩形。

    在一个关闭的子路径中,它把起始点看做是一个连接(junction),因此起点的渲染会使用设置的line-join值。作为对比,如果你仅仅是手动添加一条线段到起始点,那么对于path的两端都会使用设置的line-cap值来展示。

    • line dash pattern 允许你沿着描边的路径来绘制虚线。你可以通过传入CGContextSetLineDash方法的dash数组和phase参数来控制虚线的大小和位置。
    void CGContextSetLineDash (
        CGContextRef ctx,
        CGFloat phase,
        const CGFloat lengths[],
        size_t count
    );
    

    参数lengths指明了虚线的绘制部分和空白部分,它们是间接交替的{绘制、空白、绘制、空白}。参数phase指定了绘制虚线开始的起点,如lengths为{50,10}时表示50的绘制和10的空白互相交替,如果指定了phase为40,那么绘制和空白的交替为:(50-40)、10、50、10、50、10、...

    图 3-11 一些虚线的绘制

    图 3-11 一些虚线的绘制

    描边的色域决定了颜色将被如何解析,你可以指定一个CGColorRef类型的数据(同时包含了色域和颜色值)。更多设置颜色见:颜色和色域

    路径描边的函数(Functions for Stroking a Path)

    表 3-4 展示了Quartz提供的对当前路径进行描边的函数,有些是对矩形和椭圆进行描边的快捷方法。

    表 3-4 描边的方法(函数)

    函数(Function) 描述(Description)
    CGContextStrokePath 对当前路径进行描边
    CGContextStrokeRect 对指定的矩形进行描边
    CGContextStrokeRectWithWidth 使用指定的宽度对指定的矩形进行描边
    CGContextStrokeEllipseInRect 对指定矩形的内接椭圆进行描边
    CGContextStrokeLineSegments 对一系列线段进行描边
    CGContextDrawPath 如果你传入了kCGPathStroke参数,则会对当前路径进描边,如果你想即填充又描边见本章:路径的填充

    函数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时,你需要指定成对的点的数组,每一对值都包含了线段的起点和终点。例如,数组中的第一个点是第一条线段的起点,第二个点是第一条线段的终点,第三个点是第二条线段的起点,以此类推。

    路径的填充(Filling a Path)

    当你填充当前路径时,Quartz把路径中的每一个子路径都视作关闭的路径。然后用这些关闭的路径来计算需要填充的像素。Quartz有两种可以使用的方法来计算填充区域。简单的路径,例如椭圆、矩形有一个完美定义(well-defined)的区域。但是,如果你的路径包含重叠的线段或者包含多个路径,例如 图 3-12 展示的同心圆,你有两种方式来决定填充区域。

    默认的填充规则叫做:非零绕数规则(nonzero winding number rule)。想要知道一个确定的点是否会被绘制,从这个点和一个超出路径边界的点画一条线,以count=0开始计数,如果路径从左到右穿过这条线,那么count增加1,如果路径从右到左穿过,count减1。如果照这样计算出的结果为0,那么该点就不会被绘制,否则则会绘制。因此路径的绘制方向会影响最终的填充结果。图 3-12 展示了两组同心圆使用非零绕数规则的不同结果,当圆在使用同一方向绘制时,两个圆都进行了填充;当两个圆以不同的方向绘制时,内部的小圆没有被填充。

    你也可以选择:奇偶法则(even-odd rule)。想要知道一个确定的点是否会被绘制,从这个点和一个超出路径边界的点画一条线,以count=0开始计数,如果有路径穿过这根线,那么count增加1。如果最终得到的结果为偶数,那么这个点就不会进行绘制,反之,结果为奇数时,该点会进行绘制。正如 图3-12 所示,路径的方向并不会影响填充的结果。

    图 3-12 对同心圆使用不同的填充规则

    表 3-5 列举了Quartz提供的填充当前路径的函数,有些是用于快速填充矩形和椭圆的。

    表 3-5 路径填充的函数

    函数(Function) 描述(Description)
    CGContextEOFillPath 对当前路径使用奇偶法则进行填充
    CGContextFillPath 对当前路径使用非零绕数规则进行填充
    CGContextFillRect 填充一个指定的矩形
    CGContextFillRects 填充多个指定的矩形
    CGContextFillEllipseInRect 填充一个指定矩形的内接椭圆
    CGContextDrawPath 如果你传入了:kCGPathFill(非零绕如规则)或者kCGPathEOFill(奇偶法则),那么就会进行填充。如果你传入的参数是:kCGPathFillStroke或者kCGPathEOFillStroke,那么既会进行填充也会进行描边

    设置混色模式(Setting Blend Modes)

    混色模式(Blend Modes)用于指示Quartz如何在一个背景上进行绘制。Quartz使用普通混色模式作为默认的模式,它遵循下列的表达式:

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

    颜色和色域中详细描述了一个颜色alpha值的含义,alpha指明了颜色的不透明度。当alpha值等于1时,这个颜色完全不透明。对于完全不透明的颜色来说,当你绘制的时候使用普通混色模式,你绘制的任何内容会完全遮盖背景色。

    你可以通过调用CGContextSetBlendMode方法,并传入恰当的参数,设置混色模式来完成许多效果。需要记住的是混色模式图形状态(Graphics state)的一部分,因此,如果你在设置之前调用了CGContextSaveGState,那么你可以在使用之后调用CGContextRestoreGState来还原之前的混色模式

    本部分剩下的内容展示了在 图3-14 上绘制 图3-13 的矩形。在每一个案例中(图3-15 到 图3-30),背景矩形(图3-14)都使用了普通混色模式进行绘制;然后使用CGContextSetBlendMode来设置混色模式;最后绘制前景矩形(图3-13)。

    图 3-13 前景矩形

    图 3-13 前景矩形

    图 3-14 背景矩形

    图 3-14 背景矩形

    你也可以使用混色模式来复合两张图片,或者在当前图形上下文中复合一张图片。对图片使用混色模式展示了更多关于图片的复合和效果。
    本文会引用百度百科对混合模式(多数人译为混合模式)的讲解。

    普通混色模式(Normal Blend Mode)

    普通混色模式是默认的模式,调用函数CGContextSetBlendMode并传入kCGBlendModeNormal参数来将混色模式设置为默认值。图3-15展示了使用普通混色模式将 图3-13 绘制到 图3-14上的结果。

    图 3-15 使用普通混色模式绘制矩形
    正片叠底模式(Multiply Blend Mode)

    正片叠底模式会将前景和背景色的取样相乘,然后得到一个颜色比两者都暗的结果。图 3-16 展示了使用正片叠底的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeMultiply常量来使用该模式。

    图 3-16 正片叠底效果展示

    百度百科解释:

    公式:C=(A*B)/255 (文中C为结果颜色、A为背景色、B为前景色)

    此模式就象是将两副透明的图像重叠夹在一起放在一张发光的桌子上。

    将两个颜色的像素值相乘,然后除以255得到的结果就是最终色的像素值。通常执行正片叠底模式后的颜色比原来两种颜色都深。任何颜色和黑色正片叠底得到的仍然是黑色,任何颜色和白色执行正片叠底则保持原来的颜色不变,而与其他颜色执行此模式会产生暗室中以此种颜色照明的效果。

    在MuItiply模式 中应用较淡的颜色对图像的最终像素颜色没有影响。 MuItiply模式模拟阴影是很捧的。现实 中的阴影从来也不会描绘出比源材料(阴影)或背景(获得阴影的区域)更淡的颜色或色调的 特征。用户将在本章中使用MuItiply模式在恢复的图像中对Lee加入一个下拉阴影。在RGB模式下,每一个像素点的色阶范围是0-255,纯黑色的色阶值是0,纯白色的色阶值是255。

    滤色模式(Screen Blend Mode)

    滤色模式将两个颜色的补色样本相乘,得到了最低亮度为两者中最亮者的颜色为结果。图 3-17 展示了使用该模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeScreen常量来使用该模式。

    图 3-17 滤色模式效果

    百度百科解释:

    公式:

    作用结果和正片叠底刚好相反,它是将两个颜色的互补色的像素值相乘,然后除以255得到的最终色的像素值。通常执行滤色模式后的颜色都较浅。任何颜色和黑色执行滤色,原色不受影响;任何颜色和白色执行滤色得到的是白色;而与其他颜色执行滤色会产生漂白的效果。

    此屏幕模式对于在图像中创建霓虹辉光效果是有用的。如果在层上围绕背景对象的边缘涂了白色(或任何淡颜色),然后指定层Screen模式,通过调节层的opacity设置就能 获得饱满或稀薄的辉光效果。

    (附:在Screen和Multipy运算中的重点是----两幅图做Screen运算会加强亮的部分;做Multipy运算则会加强两幅图中暗的部分)

    叠加模式(Overlay Blend Mode)

    叠加模式会根据背景色来使用正片叠加滤色模式。它保留了原背景色的高光和阴影部分。图 3-18 展示了使用该模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeOverlay常量来使用该模式。

    图 3-18 使用叠加模式的效果

    百度百科解释:

    公式:当A<=128时, 当A>128时,

    在保留底色明暗变化的基础上使用“正片叠底”或“滤色”模式,绘图的颜色被叠加到底色上,但保留底色的高光和阴影部分。底色的颜色没有被取代,而是和绘图色混合来体现原图的亮部和暗部。使用此模式可使底色的图像的饱和度及对比度得到相应的提高,使图像看起来更加鲜亮。

    这种模式以一种非艺术逻辑的方式把放置或应用到一个层上的颜色同背景色进行混 合,然而,却能得到有趣的效果。背景图像中的纯黑色或纯白色区域无法在Overlay模式下 显示层上的Overlay着色或图像区域。背景区域上落在黑色和白色之间的亮度值同Overlay 材料的颜色混合在一起,产生最终的合成颜色。为了使背景图像看上去好像是同设计或文本 一起拍摄的,Overlay可用来在背景图像上画上一个设计或文本。

    变暗模式(Darken Blend Mode)

    选择两种颜色中数值较小的颜色分量,作为新的分量来组成混合后的颜色。因此混合之后的颜色会看起来暗一些。图 3-19 展示了该模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeDarken常量来使用该模式。

    图 3-19 使用变暗模式的效果

    百度百科解释:

    公式:C=Min(A,B)

    与Lighten相反,将两个图像中更暗的那个被选来作为结果。

    用于查找各颜色通道内的颜色信息,并按照像素对比底色和绘图色,那个更暗,便以这种颜色作为此图像最终的颜色,也就是取两个颜色中的暗色作为最终色。亮于底色的颜色被替换,暗于底色的颜色保持不变。

    变亮模式(Lighten Blend Mode)

    选择两种颜色中数值较大的颜色分量,作为新的分量来组成混合后的颜色。因此混合之后的颜色会看起来亮一些。图 3-20 展示了该模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeLighten常量来使用该模式。

    图 3-19 使用变暗模式的效果

    百度百科解释:

    公式:C=Max(A,B)

    与Darken相反,取两个像素中更亮的作为结果。

    查看每个通道的颜色信息,并按照像素对比两个颜色,那个更亮,便以这种颜色作为此像素最终的颜色,也就是取两个颜色中的亮色作为最终色。绘图色中亮于底色的颜色被保留,暗于底色的颜色被替换。

    颜色减淡模式(Color Dodge Blend Mode)

    指定变亮背景色的样本来影响前景色。如果前景色值为黑色,那么不会产生任何效果。图 3-21 展示了使用该模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeColorDodge常量来使用该模式。

    图 3-21 使用颜色减淡模式的效果

    百度百科解释:

    公式:

    查看每个通道的颜色信息,通过降低“对比度”使底色的颜色变亮来反映绘图色,和黑色混合没变化。

    除了指定在这个模式的层上边缘区域更尖锐,以及在这个模式下着色的笔画之外, Color Dodge模式类似于Screen模式创建的效果。另外,不管何时定义color Dodge模式混合 前景与背景像素,背景图像上的暗区域都将会消失。

    颜色加深模式(Color Burn Blend Mode)

    指定变暗背景色的样本来影响前景色。如果前景色值为白色,那么不会产生任何效果。图 3-22 展示了使用该模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeColorBurn常量来使用该模式。

    图 3-22 颜色加深模式效果

    百度百科解释:

    公式:

    查看每个通道的颜色信息,通过增加“对比度”使底色的颜色变暗来反映绘图色,和白色混合没变化。

    除了背景上的较淡区域消失,且图像区域呈现尖锐的边缘特性之外,这种Color Burn模式创建的效果类似于由MuItiply模式创建的效果。

    柔光模式(Soft Light Blend Mode)

    根据要混合的前景色,来变暗或者变亮的颜色。如果前景色比50%灰度要亮,那么背景色会变亮,类似于减淡(dodging);如果前景色比50%灰度要深,那么背景色会变暗,类似于加深(burning);如果前景色等于50%灰度,那么背景色不会产生改变。如果前景色为纯黑或者纯白色,那么背景色仅仅是会变得更暗或更亮,但是,当底色也为纯黑或者纯白时,不会产生这样的效果。图 3-23 展示了柔光模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeSoftLight常量来使用该模式。

    图 3-23 柔光模式效果

    百度百科解释:

    公式:

    当B<=128时, 当B>128时,

    根据绘图色的明暗程度来决定最终色是变亮还是变暗,当绘图色比50%的灰要亮时,则底色图像变亮。当绘图色比50%的灰要暗时,则底色图像就变暗。如果绘图色有纯黑色或纯白色,最终色不是黑色或白色,而是稍微变暗或变亮。如果底色是纯白色或纯黑色,不产生任何效果。此效果与发散的聚光灯照在图像上相似。

    强光模式(Hard Light Blend Mode)

    根据前景色来选择正片叠底(multiply)或者滤色(screen);如果前景色大于50%的灰度,那么背景色就会变得更亮,类似于滤色(screening);反之,如果前景色比50%灰度小,那么背景色就会变暗,类似于正片叠底(multiply);如果前景色的灰度值等于50%,那么前景色不会改变。纯黑或者纯白的前景色会产生纯黑或者纯白的结果。图 3-24 展示了强光模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeHardLight常量来使用该模式。

    图 3-24 强光模式效果

    百度百科解释:

    公式:

    当B<=128时,

    ;

    当B>128时,

    根据绘图色来决定是执行“正片叠底”还是“滤色”模式。当绘图色比50%的灰要亮时,则底色变亮,就执行“滤色”模式一样,这对增加图像的高光非常有帮助;当绘图色比50%的灰要暗时,则底色变暗,就执行“正片叠底”模式一样,可增加图像的暗部。当绘图色是纯白色或黑色时得到的是纯白色和黑色。此效果与耀眼的聚光灯照在图像上相似。像亮则更亮,暗则更暗。

    这种模式实质上同Soft Light模式是一样的。它的效果要比Soft Light模式更强烈一些,同Overlay一样,这种模式 也可以在背景对象的表面模拟图案或文本。

    差值模式(Difference Blend Mode)

    将前景色和背景色的分量差值作为新的颜色,如果前景色是黑色,那么,不会对背景色产生任何效果。 图 3-25 展示了差值模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeDifference常量来使用该模式。

    图 3-25 差值模式效果

    百度百科解释:

    公式:C=|A-B|

    查看每个通道中的颜色信息,比较底色和绘图色,用较亮的像素点的像素值减去较暗的像素点的像素值。与白色混合将使底色反相;与黑色混合则不产生变化。

    排除模式(Exclusion Blend Mode)

    该模式产生的效果和差值模式类似,只是没有那么明显。前景色为纯白时,背景色会变成它的反相;前景色为黑色时,不会对背景色产生影响。图 3-26 展示了排除模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeExclusion常量来使用该模式。

    图 3-26 排除模式的效果

    百度百科介绍:

    公式:

    可生成和差值模式相似的效果,但比差值模式生成的颜色对比度较小,因而颜色较柔和。与白色混合将使底色反相;与黑色混合则不产生变化。

    色相模式(Hue Blend Mode)

    使用背景色的亮度和饱和度以及前景色的色相来创建最终的颜色。图 3-27 展示了色相模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeHue常量来使用该模式。

    图 3-27 色相模式效果
    饱和度模式(Saturation Blend Mode)

    使用背景色的亮度和色相以及前景色的饱和度来创建最终的颜色。对于没有饱和度的背景区域(即是纯灰区域),不会产生影响。图 3-28 展示了使用饱和度模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeSaturation常量来使用该模式。

    图 3-28 饱和度模式效果
    颜色模式(Color Blend Mode)

    该模式使用背景图的亮度和前景图的色相和饱和度来创造新的绘制结果。这种模式保护了图片中的灰阶,你可以使用这种模式为黑白图像或者彩色图像着色。图 3-29 展示了使用颜色模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeColor常量来使用该模式。

    图 2-29 颜色模式效果
    亮度模式(Luminosity Blend Mode)

    该模式使用背景色的色相和饱和度以及前景色的亮度来创建新的结果。这个模式产生的效果与颜色模式相反。 图 3-30 展示了使用亮度模式的效果。调用CGContextSetBlendMode函数时,传入kCGBlendModeLuminosity常量来使用该模式。

    图 3-30 使用亮度模式的效果

    路径的裁剪(Clipping to a Path)

    路径的当前裁剪区域就像是一个遮罩(mask)一样,允许你隔离你不想绘制的区域。例如,如果你仅仅是想展示一个很大位图的一小部分,你就可以通过设置裁剪区域来实现。

    进行绘制的时候,Quartz仅仅绘制了裁剪区域内的内容。绘制后,在裁剪区域内的关闭路径内可见,在裁剪区域外的关闭路径不可见。

    当图形上下文刚刚初始化的时候,裁剪区域包含了整个上下文区域(如,一个PDF的media box)。在设置好当前路径之后,你调用一个裁剪的函数(而不是绘图函数)来设置裁剪区域。裁剪函数使当前路径的填充区域和存在的裁剪区域相交,也就是说,你可以通过它来缩小图片的可见区域,但是你不能增加原本的可见区域。

    裁剪区域是图形状态的一部分,因此你可以保存在添加裁剪区域之前的状态,以便于裁剪之后进行恢复。

    清单 3-1 展示了设置一个圆形的裁剪区域的代码;这些代码使得绘画被裁剪,就像图 3-3 那样。(另一个例子在渐变章节的裁剪上下文中)

    清单 3-1 设置一个圆形的裁剪区域

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

    表 3-6 裁剪图形上下文的函数

    函数(Function) 描述(Description)
    CGContextClip 使用非零绕数规则来计算当前路径和裁剪路径的相交区域,并将其作为新的裁剪区域。
    CGContextEOClip 使用奇偶法则来计算当前路径和裁剪路径的相交区域,并将其作为新的裁剪区域。
    CGContextClipToRect 使用指定矩形和当前裁剪区域的相交区域作为新的裁剪区域。
    CGContextClipToRects 与指定单个矩形相同,指定多个矩形。
    CGContextClipToMask 在你指定的矩形中增加一个遮罩来和当前的裁剪区域相交,之后的一系列操作都会被裁剪(详见: Masking an Image by Clipping the Context)。

    上一章:图形上下文(Graphics Context)
    下一章:颜色与色域 (Color and Color Spaces)

    相关文章

      网友评论

          本文标题:路径(Paths)—— Quartz 2D编程指导翻译 第4篇

          本文链接:https://www.haomeiwen.com/subject/ibscixtx.html