Quartz 2D编程指南

    2014-08-14 00:00     0 条评论

Quartz 2D编程指南

参考资料:
路径整理

1. Quartz 2D概览

Quartz 2D是iOS环境下的2D绘制引擎你可以使用Quartz 2D API获取比如基于路径的绘制,透明绘制,阴影,绘制阴影,透明层,颜色管理,高保真渲染,生成pdf文档,访问pdf元数据的访问特性。任何可能的时候,Quartz 2D充分利用了硬件的性能。

页(The Page)

Quartz 2D为了实现绘制,使用了绘画者模式(painter's model)。在绘画者模式中,每一个成功的绘制操作应用与层上,并“绘制”输出到一个“画布”(canvas)上。

绘制目的地 : 图形上下文(The Graphics Context)

一个图形上下文是一个复杂数据类型(CGContextRef),它封装了用于绘制图像到另一设备的quartz信息,比如说pdf文档,位图,或者一个窗口(window)的显示。图形上下文里面的信息包含有图形绘制参数,和页面上用于在指定设备中的绘制表示。

在你的应用中你可以使用下面这些图形上下文对象:

  • 一个位图上下文允许你绘制RGB颜色,CMYK颜色,或者将灰度绘制进一个位图。一个位图是一个矩形像素数组(或者光栅),每一个像素代表图片中的一个点。位图图片也叫做取样图片。
  • 一个PDF图形上下文
  • 一个窗口图形上下文
  • 一个图层上下文(Layer context : CGLayerRef) -- 适用于Mac OS X

Quartz 2D 复杂数据类型(Quartz 2D Opaque Data Types)

Quartz 2D中包含以下复杂数据类型:

  • CGPathRef
  • CGImageRef
  • CGLayerRef
  • CGPatternRef
  • CGShadingRef
  • CGFunctionRef
  • CGColorRef
  • CGImageSourceRef和CGImageDestinationRef
  • CGFontRef

图形状态(Graphics States)

Quartz 2D根据当前图形状态(Current graphics state)的参数来影响绘制操作的结果。图形状态包含的参数。

Quartz 2D坐标系统

因为不同的设备拥有不同的基础绘图能力,图形的位置和大小被定义成设备独立的方式。比如显示器可以显示不多于96像素每英尺的能力,但是打印机可能能够显示300像素每英尺的能力。假如你在设备级别定义坐标系统(在这个例子中,96像素或者300像素),在某个空间绘制的对象是不能被无失真的复制到其它设备。这将出现太大或者太小的情况。

Quartz实现了设备无关的单独坐标系统--用户空间--使用当前变换矩阵(Current Trasformation matrix)或者叫CTM映射到设备的装备坐标系统。矩阵是一个用于高效描述一系列相关方程的算术结构。当前转换矩阵是一个叫做仿射变换的特殊矩阵类型,它通过使用变换,旋转,和缩放操作(计算移动,选择,和调整坐标系统的大小)从一个坐标空间到另一个空间来达到映射点的目的。

CTM有第二个目的:它允许你转换对象被绘制的方式。是比如说,绘制一个旋转45度角的盒子,你可以在绘制盒子之前旋转当前页(page)的坐标系统.Quartz使用选座坐标系统来绘制到外部设备。

因为UIKit使用的是ULO坐标系(upper - left -origin coordinate system),和Quartz使用的LLO(low - left - origin coordinate system)是不一样的,所以需要对上下文进行转换。比如说,假如你想要一个图像(image)或者PDF正确的绘制到图形上下文中,你的应用必须临时调整图形上下文的CTM。在iOS中,假如你使用你创建的UIImage对象或者它的包装对象CGImage,你无需修改CTM。UIImage对象自动适应,由UIKit应用修改后坐标系。

内存管理:对象所有者

2. 图形上下文

iOS中向视图的上下文对象中进行绘制

创建位图上下文对象

一个位图上下文对象接受一个指向内存缓冲区的指针,它包含位图的空间存储。当你往位图上下文对象中进行绘制时候,这个缓冲区就会被更新。当你释放了图形上下文之后,你完全使用你指定的像素格式更新了位图。

位图上下文有时用于离屏渲染。在你决定使用位图上下文用于此目的时,请查Core Graphics Layer Drawing.CGLayer对象(CGLayerRef)自适应离屏渲染,因为只要有可能,Quartz层(layers)都是缓存在显卡中。

iOS提醒:iOS应用必须使用UIGraphicsBeginImageContextWithOptions方法,而不是低级别的Quartz方法来使用此处描述的功能。假如你的应用使用Quartz来创建离屏位图,位图上下文对象使用的坐标系是默认的Quartz坐标系。相反的,假如你的应用使用UIGraphicsBeginImageContextWithOptions来创建一个图形上下文时,UIKit对UIView对象的图形上下文坐标系使用统一的转换。这允许你的应用使用统一的绘制代码而无需担心不一样的坐标系。虽然你的应用可以手动的调整坐标系的转换来达到相同的目的,实际上,这样做是没有性能损失的。

你可以试有CGBitmapContextCreate方法创建一个位图上下文对象。这个方法使用了下面的参数

  • data .提供一个指向你想要渲染的内存目的地指针。这个内存块的大小必须只是是(bytesPerRow*height)位bytes
  • width
  • height
  • bitsPerComponent,指定用于在存储器中的像素的每个分量的比特数。比如说,32位像素的RGB颜色空间。
  • bytesPerRow.指定用于在

关于图片绘制的demo:

-  (void)drawImage:(CGContextRef )context
{

    //1. 绘制图片
    UIImage *xcodeIcon = [UIImage imageNamed:@"Demo.png"];
    [xcodeIcon drawAtPoint:CGPointMake(0.0f, 70.0f)];
    [xcodeIcon drawInRect:CGRectMake(70.0f, 80.0f, 140.0f, 135.0f)];

    //2.截取二进制图片
    UIGraphicsBeginImageContext(self.bounds.size);
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *screenSnapImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    [screenSnapImage drawInRect:CGRectMake(70.0f, 230.0f, 320/4, 480/4)];
}

支持的像素格式

高保真

    CGContextSetAllowsAntialiasing(myContext, YES);//是否运行开启高保真模式
    CGContextSetShouldAntialias(myContext, YES);//是否是高保真模式

获取一个图形上下文用于打印

3 路径(Paths)

一个路径定义了一个或者多个形状,或者子路径。一个自路径可以包含直线,曲线,或者两者都包含。它(路径)可以是打开或者关闭的。

路径的创建和绘制

路径的创建和路径的绘制是2个独立的任务。首先,你需要先创建路径。当你想要渲染路径的时候,你请求Quartz来进行路径的绘制。你可以选择对路径进行描边,填充路径,或者既填充又描边。您还可以使用路径用于创建一定范围内的其他物体的绘制,实际效果是,一个剪切区域。

下面是一个简单的demo:

//绘制当前视图的对角线
- (void)drawPath:(CGContextRef)context
{
    /* 创建路径 Create the path */
    CGMutablePathRef path = CGPathCreateMutable();

    CGRect screenBounds = [self bounds];

    /*左上角开始 Start from top-left */
    CGPathMoveToPoint(path, NULL,screenBounds.origin.x, screenBounds.origin.y);

    /*绘制一条从左上角到右下角的线条 Draw a line from top-left to bottom-right of the view */
    CGPathAddLineToPoint(path, NULL,screenBounds.size.width, screenBounds.size.height);

    /*另一条从右上角作为起点的线条 Start another line from top-right */
    CGPathMoveToPoint(path, NULL,screenBounds.size.width, screenBounds.origin.y);

    /* 绘制一条从右上角到左下角的线条 Draw a line from top-right to bottom-left */
    CGPathAddLineToPoint(path, NULL,screenBounds.origin.x, screenBounds.size.height);

    /* 获取图形上下文对象 。Get the context that the path has to be drawn on */
    CGContextRef currentContext = UIGraphicsGetCurrentContext();

    /*将路径添加到当前画布中。 Add the path to the context so we can draw it later */
    CGContextAddPath(currentContext, path);

    /*设置描边色 Set the blue color as the stroke color */
//    [[UIColor blueColor] setStroke];
    CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);

    /*绘制路径 Draw the path with stroke color */
    CGContextDrawPath(currentContext, kCGPathStroke);

    /* Finally release the path object */
    CGPathRelease(path);
}

路径的组成模块(The building blocks)

子路径是由线,弧,和曲线组成的。Quartz也提供了便利的单个方法调用来添加矩形和椭圆。点也是组成路径必不可少的部分,因为点定义了一个形状的起点和终点。

点(Points)

点是在用户空间指定x,y坐标的一个位置。你可以调用CGContextMoveToPoint方法指定一个新的子路径的的起点。Quartz持续跟踪当前的点,这是路径组成的最后位置。比如说,假如你调用CGContextMoveToPoint方法设置一个在(10,10)的点,当前点就移动到(10,10)这个位置。假如你绘制一个50单位长的水平线,这条线的终点是(60,10),就变成了当前点。线,弧和曲线都是从当前点开始进行绘制。

大多数时候,你指定一个包含2个浮点值用于指定x和y坐标的点传递给Quartz方法。一些方法要求你传递一个包含2个浮点值的CGPoint数据结构。

线

一个线条是由它的端点来定义的、它的起点往往被推断为当前点,所以一旦你创建了一条线,你只需要指定它的终点就可以了。你可以使用CGContextAddLineToPoint方法来在自路径上添加一条单线。

你可以使用CGContextAddLines方法添加一系列连接线到路径上。你传递一个点的数组给这个方法。第一个点必须是第一条线的起点,剩下的点是终点。

关于线条的绘制方法主要有CGContextAddLineToPointCGContextAddLines以及CGContextStrokeLineSegments方法,下面是关于线条绘制的一个demo:

- (void)drawLine
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    // Drawing lines with a white stroke color
    CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
    // Draw them with a 2.0 stroke width so they are a bit more visible.
    CGContextSetLineWidth(context, 2.0);

    // Draw a single line from left to right
    CGContextMoveToPoint(context, 50.0f, 10.0f);
    CGContextAddLineToPoint(context, 310.0f, 310.0f);
    CGContextStrokePath(context);

    // Draw a connected sequence of line segments
    CGPoint addLines[] =
    {
        CGPointMake(10.0, 90.0),
        CGPointMake(70.0, 60.0),
        CGPointMake(130.0, 90.0),
        CGPointMake(190.0, 60.0),
        CGPointMake(250.0, 90.0),
        CGPointMake(310.0, 60.0),
    };
    // Bulk call to add lines to the current path.
    // Equivalent to MoveToPoint(points[0]); for(i=1; i<count; ++i) AddLineToPoint(points[i]);
    CGContextAddLines(context, addLines, sizeof(addLines)/sizeof(addLines[0]));
    CGContextStrokePath(context);

    // Draw a series of line segments. Each pair of points is a segment
    CGPoint strokeSegments[] =
    {
        CGPointMake(10.0, 150.0),
        CGPointMake(70.0, 120.0),
        CGPointMake(130.0, 150.0),
        CGPointMake(190.0, 120.0),
        CGPointMake(250.0, 150.0),
        CGPointMake(310.0, 120.0),
    };
    // Bulk call to stroke a sequence of line segments.
    // Equivalent to for(i=0; i<count; i+=2) { MoveToPoint(point[i]); AddLineToPoint(point[i+1]); StrokePath(); }
    CGContextStrokeLineSegments(context, strokeSegments, sizeof(strokeSegments)/sizeof(strokeSegments[0]));
}

弧是圆的组成部分。Quartz提供了2个方法用于创建弧。CGContextAddArc方法从一个圆(circle)创建弧元素。你还可以指定圆的中心,半径和和径向的角度(以弧度为单位).你可以指定径向角度为2 PI 来创建一个全圆。

CGContextAddArcToPoint是一个理想的方法,当你想圆一个矩形的四个角。Quartz使用您提供端点来创建两条切线。你还可以提供用于切割弧的圆的半径。

如果当前路径已经包含一个子路径,Quartz从目前的点到圆弧的起点添加直线段。如果当前路径是空的,Quartz在起点为圆弧创建一个新的子路径,并且不添加初始直线段。

曲线(Curves)

二次和三次贝塞尔曲线,可以指定任意数量的有趣形状的曲线。点上这些曲线是通过将多项式公式来开始和结束点,以及一个或多个控制点进行计算。基础矢量图形是通过这种方式来定义的。公式是更加紧凑的存储比特(bits)数组,并这样的曲线具有可以被重新创建的任何分辨率的优点。

多项式的公式,上升到二次和三次Bezier曲线,以及如何从公式曲线的细节,在许多数学文字和描述计算机图形的在线资源进行了讨论。这些细节在此不再赘述。

你可以使用CGContextAddCurveToPoint方法来从当前点开始,添加一个三次贝塞尔曲线,使用你指定的控制点和端点。

你可以使用CGContextAddQuadCurveToPoint方法来从当前点开始,添加一个二次贝塞尔曲线,指定一个控制点和一个终点。

闭合子路径

为了闭合子路径,你的应用必须调用CGContextClosePath方法。这个方法添加一条从当前点到子路径起点的线元素,并且闭合子路径。线条,弧度和曲线,在子路径的起点结束的曲线实际上并不关闭子路径。所以你必须显式调用CGContextClosePath来关闭子路径。

一些Quartz方法对路径的子路径的处理,就好像它们是由你的应用程序关闭的。这些命令对每个子路径都是这样,就好像你的应用程序调用CGContextClosePath将其关闭,含蓄地添加线段的子路径的起点。

在关闭子路之后,假如你的应用额外的调用操作来添加线,弧度或者曲线,Quartz在你刚闭合的子路径的当前起始点(Starting point)开始一个新的子路径的起点。

椭圆

椭圆本质上是一个被压扁的圆.通过定义两个焦点,然后绘制椭圆上的所有距离,使得添加从椭圆上的任意点到一个焦点的距离,以从该相同点到另一个焦点的距离总是为相同的值的点创建一个。

你可以通过调用CGContextAddEllipseInRect方法来添加一个椭圆到当前的路径上。你提供一个矩形来定义椭圆的边界。Quartz使用一系列贝塞尔曲线来近似绘制椭圆。椭圆的中心就是矩形的中心。假如宽和高是相对的(这意味着,是一个正方形),椭圆就是一个圆,圆的半径等于矩形的宽(或者高)。

椭圆以移动到(move-to)操作开始,以关闭子路径操作结束,沿着顺时针方向移动来添加到路径上。

矩形

你可以调用CGContextAddRect方法来添加一个矩形到当前路径上。你提供一个CGRect结构体包含矩形的起点和它的宽和高。

矩形以移动到(move-to)操作开始,以关闭子路径操作结束,沿着顺时针方向移动来添加到路径上。

你可以使用CGContextAddRects方法,提供一个CGRect数组数据结构,来添加多个矩形到当前的路径上。

下面是一个矩形绘制的demo:

- (void)drawRect
{
    /* Create the path first. Just the path handle. */
    CGMutablePathRef path = CGPathCreateMutable();

    /* Here are our rectangle boundaries */
    CGRect rectangle = CGRectMake(60.0f, 70.0f, 200.0f, 300.0f);

    /* Add the rectangle to the path */
    CGPathAddRect(path, NULL, rectangle);

    /* Get the handle to the current context */
    CGContextRef currentContext = UIGraphicsGetCurrentContext();

    /* Add the path to the context */
    CGContextAddPath(currentContext, path);

    /* Set the fill color to cornflower blue */
//    [[UIColor colorWithRed:0.20f green:0.60f blue:0.80f alpha:1.0f] setFill];
    CGContextSetRGBFillColor(currentContext, 0.2f, 0.6f, 0.8f, 1.0f);


    /* Set the stroke color to brown */
//    [[UIColor brownColor] setStroke];
    CGContextSetStrokeColorWithColor(currentContext, [UIColor brownColor].CGColor);

    /* Set the line width (for the stroke) to 5 */
    CGContextSetLineWidth(currentContext, 5.0f);

    /* Stroke and fill the path on the context */
    CGContextDrawPath(currentContext, kCGPathFillStroke);

    /* Dispose of the path */
    CGPathRelease(path);
}

在一个path中绘制多个矩形demo:

- (void)drawMutiRect
{
    /* Create the path first. Just the path handle. */
    CGMutablePathRef path = CGPathCreateMutable();

    /* Here are our first rectangle boundaries */
    CGRect rectangle1 = CGRectMake(10.0f, 10.0f, 200.0f, 300.0f);

    /* And the second rectangle */
    CGRect rectangle2 = CGRectMake(40.0f, 100.0f, 90.0f, 300.0f);

    /* Put both rectangles into an array */
    CGRect rectangles[2] = {rectangle1, rectangle2 };

    /* Add the rectangles to the path */
    CGPathAddRects(path, NULL, (const CGRect *)&rectangles, 2);

    /* Get the handle to the current context */
    CGContextRef currentContext = UIGraphicsGetCurrentContext();

    /* Add the path to the context */
    CGContextAddPath(currentContext, path);

    /* Set the fill color to cornflower blue */
    [[UIColor colorWithRed:0.20f green:0.60f blue:0.80f alpha:1.0f] setFill];

    /* Set the stroke color to black */
    [[UIColor blackColor] setStroke];

    /* Set the line width (for the stroke) to 5 */
    CGContextSetLineWidth(currentContext, 5.0f);

    /* Stroke and fill the path on the context */
    CGContextDrawPath(currentContext, kCGPathFillStroke);

    /* Dispose of the path */
    CGPathRelease(path);
}

创建一个路径

假如你想要在图形上下文中构造一个路径,你以调用CGContextBeginPath方法作为标志。然后你设置第一个形状或者子路径的启动点,通过调用CGContextMoveToPoint方法来实现。在你建立了第一个断点之后,你可以添加线,弧,或者曲线到路径上,请记住一下要点:

  • 在你启动一个新路径之前,调用CGContextBeginPath方法
  • 线、弧、和曲线从当前点开始进行绘制。一个空的路径没有当前点,你必须调用CGContextMoveToPoint方法来设置第一个子路径的起始点,或者调用一个便利方法来为你隐式实现。
  • 当你想要在一个路径上关闭当前子路径的时候,调用CGContextClosePath方法来连接该子路径的起始点。后续的路径调用开始一个新的子路径,就好像是你没有隐式的设置了一个新的起始点一样。
  • 当你绘制弧、Quartz绘制一条在当前点和起始点之间的弧。
  • Quartz添加椭圆和矩形的时候,按惯例会关闭路径的子路径
  • 你必须调用一个绘制方法来填充或者描边,因为创建一个路径不会绘制路径。

路径的绘制

影响绘制的参数

你可以通过修改下表中的参数来决定路径是如何绘制的。这些参数是绘图状态的一部分,这表示你设置的参数值将会影响接下来的一系列绘制,直到你将参数设置为另一个值。

Parameter Function to set parameter value
Line width (线宽) CGContextSetLineWidth
Line join (连接模式) CGContextSetLineJoin
Line cap (外观模式) CGContextSetLineCap
Miter limit (倾斜限制) CGContextSetMiterLimit
Line dash pattern (虚线样式) CGContextSetLineDash
Stroke color space (描边的边框色彩空间) CGContextSetStrokeColorSpace
Stroke color (描边颜色) CGContextSetStrokeColorCGContextSetStrokeColorWithColor
Stroke pattern (描边方式) CGContextSetStrokePattern

路径的绘制方法(functions for stroking a path)

方法 描述
CGContextStrokePath trokes the current path.

CGContextStrokeRect | Strokes the specified rectangle.

CGContextStrokeRectWithWidth | Strokes the specified rectangle, using the specified line width.
CGContextStrokeEllipseInRect | Strokes an ellipse that fits inside the specified rectangle.CGContextStrokeLineSegments Strokes a sequence of lines.

CGContextDrawPath | If you pass the constant kCGPathStroke, strokes the current path.

填充路径

当你将要填充当前路径时,Quartz表现得就像当前路径的每一个子路径都是闭合的。然后它使用这些闭合的子路径并且计算像素来进行填充。Quartz有2种方式来计算填充区域。简单路径比如说椭圆和矩形有一个定义良好的区域。但是假如你的路径是由重叠的线条,或者如果路径中包含很多个子路径,这时就有2条你额可以用来决定填充区域的规则。

默认的填充规则被称作非零绕数规则(nonzero winding number rule).为了决定一个指定点是否被绘制,从某点开始c出制超出右穿过,该计数就加1;每次一个路径元素从右到左,该计数就减1.假如该计算结果是0的话,这个点就不会被绘制。否则,这个点就会被绘制。路径元素的方向影响了绘制结果。

notes:CGContextFillPath从某点出发向图形边缘做一条射线,如果射线和图形某条边相交,且该边从坐向右穿过射线,则相交计数+1,如果该边从右向左穿过射线,则相交计数-1。如果最后相交计数为1,则该点在图形内。

你也可以使用可选的奇偶规则(even-odd rule)。为了决定指定的点是否被绘制,从点开始并绘制超出图中的边界线。计算该线穿过该元素(点)的路径数。假如是奇数(odd),该点就不进行绘制。路径元素的方向不会影响绘制结果。

note:CGContextEOFillPath从某点出发向图形边缘做一条射线,如果射线和图形边相交点数为奇数,则该点在图形内。

Quartz提供了下表所示的方法来填充当前路径。有一些是用于绘制矩形和椭圆的便利方法:

方法 描述
CGContextEOFillPath Fills the current path using the even-odd rule.

CGContextFillPath | Fills the current path using the nonzero winding number rule.

CGContextFillRect | Fills the area that fits inside the specified rectangle.

CGContextFillRects | Fills the areas that fits inside the specified rectangles.

CGContextFillEllipseInRect | Fills an ellipse that fits inside the specified rectangle.

CGContextDrawPath | Fills the current path if you pass kCGPathFill (nonzero winding number rule) or kCGPathEOFill (even-odd rule).Fills and strokes the current path if you pass kCGPathFillStroke or kCGPathEOFillStroke.

设置混合模式(setting blend modes)

混合模式指定了Quart如何在背景上进行绘制。Quartz使用默认使用正常(normal)混合模式,它(混合模式)使用下面公式,结合了前景绘制和背景绘制:

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

路径的裁剪(clipping to a path)

当前裁剪区域 是从一个路径创建的一个蒙板,允许你屏蔽掉你不想绘制的部分。假如你需要显示一个很大的位图的一小部分,你可以设置裁剪区域仅仅用于显示你想要显示的部分。

当你进行绘制的时候,Quartz引擎仅仅绘制裁剪区域。闭合路径的内部的裁剪可视区域才会出现绘制的情况;闭合子路径的外部不可视区域是不会出现绘制的。

当图形上下文对象初始化创建之后,裁剪区域包含上下文对象(画布)的所有可绘制区域(比如说pdf上下文的媒体区域)。你通过设置当前路径并且随后使用裁剪方法代替绘制方法来改变裁剪区域。裁剪方法将当前路径的填充区域和已存在的填充区域切断。因此,你可以切断裁剪区域,缩减图片的可视区域,但是你决不可能增加裁剪区域。

裁剪区域是一个图形状态(graphics state)。为了绘制之前的裁剪区域,你可以在裁剪前保存图形状态,在裁剪结束后恢复图形状态。

裁剪图形上下文的方法:

方法名 描述
CGContextClip Uses the nonzero winding number rule to calculate the intersection of the current path with the current clipping path.

CGContextEOClip | Uses the even-odd rule to calculate the intersection of the current path with the current clipping path.

CGContextClipToRect | Sets the clipping area to the area that intersects both the current clipping path and the specified rectangle.

CGContextClipToRects | Sets the clipping area to the area that intersects both the current clipping path and region within the specified rectangles.

CGContextClipToMask | Maps a mask into the specified rectangle and intersects it with the current clipping area of the graphics context. Any subsequent path drawing you perform to the graphics context is clipped.

4 颜色和颜色空间

设备(显示器,打印机,扫描仪,相机)不是使用相同的方式来处理颜色;每一个设备都有它自有的颜色范围,这样一来该设备可以进行忠实的处理。一个颜色可以在一个设备上进行处理,可能并不能在另一台设备进行处理。

在本章中,你可以学会Quartz是如何对颜色和颜色空间进行表示的,alpha通道是什么。本章也讨论如何:
* 创建颜色空间 (color spaces)
* 创建和设置颜色
* 设置渲染意图(rendering intent)

关于颜色和颜色空间

颜色在Quartz中用一个值的集合来进行表示。这些值在没有指明如何解释颜色信息的颜色空间时是无意义的。比如说下表中的值全部都代表着蓝色。

Values Color space Components
240 degrees, 100%, 100% HSB Hue, saturation, brightness
0, 0, 1 RGB Red, green, blue
1, 1, 0, 0 CMYK Cyan, magenta, yellow, black
1, 0, 0 BGR Blue, green, red

颜色空间包含有一定数量的组成分量。

alpha值

alpha值是Quartz用于决定如何组合新绘制对象到已有页(page)的图形状态参数.在全颜色强度下,新绘制的对象是非透明的(opaque)。在零颜色强度下,新绘制的对象是不可见的。

对应透明的对象,设置alpha值为1.0来指定你要绘制的该对象必须被完全非透明的进行绘制。设置0.0来指定该对象完全透明。alpha值在0和1之间用于指定一个部分透明的对象。您可以提供一个alpha值作为最后的颜色分量来接受颜色.你也可以使用CGContextSetAlpha方法来设置全局alpha值。但是请记住,假如你两个都进行了设置,Quartz乘以全局alpha值的颜色分量。

为了允许页自身完全透明,只要图形上下文是一个窗口或者位图上下文的话,你可以使用CGContextClearRect方法明确的清除图形上下文的alpha通道。

创建颜色空间

iOS是不支持设备无关的或者普通的颜色空间。iOS应用必须使用设备颜色空间进行替换。

iOS中创建颜色编号的方法如下:
CGColorSpaceCreateDeviceRGB
CGColorSpaceCreateDeviceGray
CGColorSpaceCreateDeviceCMYK
CGColorSpaceCreateCalibratedGray
CGColorSpaceCreateCalibratedRGB
CGColorSpaceCreateLab
CGColorSpaceCreateWithICCProfile
.... (更多方法,请查看CGColorSpace.h头文件的定义)

创建设备颜色空间

设备颜色空间主要用于iOS应用,因为其它的可选项在iOS是不可用的。在大多数情况下,Mac OS X应用必须使用普通颜色空间而不是使用设备颜色空间。无论如何,一些Quartz的惯例是使用一个设备颜色空间的图像。比如说,假如你调用CGImageCreateWithMask方法并指定一个图像蒙版的话,这个图像必须是定义为设备灰度空间。

你可以通过下面的方法来使用设备颜色空间:

  • CGColorSpaceCreateDeviceGray
  • CGColorSpaceCreateDeviceRGB
  • CGColorSpaceCreateDeviceCMYK

创建索引(indexed)和取样(pattern)颜色空间

索引颜色空间包含256个入口列表,并且基准颜色空间和颜色入口列表进行映射。每一个颜色入口指定了一种在基准颜色空间的颜色。使用CGColorSpaceCreateIndexed方法

设置和创建颜色

Quartz提供了一系列的方法用于填充颜色,描边颜色,颜色空间,或者alpha。每个颜色参数应用于颜色状态,这表示一旦设置,该设置值将会一直保留直到被设置成另一个值。

一个颜色必须有一个相关联的颜色空间。否则,Quartz将不知道如何处理颜色值。更进一步,你必须为绘制目的地提供接近的颜色空间。

你可以使用CGContextSetFillColorSpace或者CGContextSetStrokeColorSpace方法来设置填充
颜色空间,或者你可以使用下表中的便利方法来为设备颜色空间设置颜色:

Function Use to set color for
CGContextSetRGBStrokeColor CGContextSetRGBFillColor Device RGB. At PDF-generation time, Quartz writes the colors as if they were in the corresponding generic color space.

CGContextSetCMYKStrokeColor CGContextSetCMYKFillColor | Device CMYK. (Remains device CMYK at PDF-generation time.)

CGContextSetGrayStrokeColor CGContextSetGrayFillColor | Device Gray. At PDF-generation time, Quartz writes the colors as if they were in the corresponding generic color space.

CGContextSetStrokeColorWithColor CGContextSetFillColorWithColor | Any color space; you supply a CGColor object that specifies the color space. Use these functions for colors you need repeatedly.

CGContextSetStrokeColor CGContextSetFillColor | The current color space. Not recommended. Instead, set color using a CGColor object and the functions CGContextSetStrokeColorWithColor and CGContextSetFillColorWithColor.

假如你需要在你的应用中重用颜色,最有效的用于填充和描边颜色的方式是创建一个CGColor对象,这个你可以通过CGContextSetFillColorWithColor和CGContextSetStrokeColorWithColor方法传递参数。只要你需要你可以一直保留这个CGColor对象。你可以通过直接使用CGColor对象来改善你应用的性能。、

你通过调用CGColorCreate方法来创建CGColor对象,传递颜色空间对象和一个浮点指针数组值指定颜色的程度值。数组的最后一个分量是用于指定alpha值的。

设置渲染意向(Setting Rendering Intent)

渲染意向指定如何从Quartz源色彩空间映射到那些图形上下文的目标色彩空间的色域范围内的色彩。假如你没有显式的指定渲染意向,除了位图(取样)图片之外,Quartz使用相对色度渲染意向进行绘制。Quartz使用

5. 变换(Transforms)

Quartz 2D 绘制模型定义了2个完全分类的坐标空间:代表文档页的用户空间,和代表设备一个原始分辨率的设备空间。用户空间坐标系统是和设备像素分辨率无关的浮点指针类型指针。当你想要打印或者显示你的文档,Quartz将用户空间坐标映射到设备空间坐标。因此,你无需重写你的应用,或者编写额外的代码来从你的应用输出到不同显示设备之间。

你可以通过当前转换矩阵(CTM)修改默认的用户空间.当你创建了图形上下文之后,CTM是一个恒等矩阵。你可以使用Quartz变换方法用于修改CTM,因此,在用户空间修改绘制。

本章:
* 提供一个你可以用于实现转换的方法的概览
* 显示如何修改CTM
* 描述如何创建一个彷射矩阵(Affine transform)
* 显示如何决定两个矩阵是否等效
* 描述如何获取用户到设备空间的变换
* 讨论彷射编号背后的数学

关于Quartz转换方法

使用Quartz 2D内建的变换函数,你可以轻易的变换,缩放和旋转你的绘制。仅仅需要少量代码,你就可以以任何顺序或者组合来应用这些变换。

Quartz 2D API 提供了5个方法运行你获取和修改CTM。你可以旋转、变换(translate)和缩放CTM,而且你还可以使用CTM合成一个彷射矩形。

Quartz 也允许你不操作当前用户空间来创建彷射变换,直到你决定应用变换到CTM。你使用另一个方法集合用于创建彷射变换,它可以和CTM进行合并(concatenated).

修改当前的转换矩阵(Modifying the current transformation metric)

变换(Translation)将当前坐标系的原点移动到你指定数量的x轴和y。你可以使用CGContextTranslateCTM方法按指定的数量来改变x和y坐标。比如:

CGContextTranslateCTM (myContext, 100, 50);

旋转(rotation)根据你指定的角度移动坐标空间(注意是坐标空间,而不是你的绘制内容)。你可以调用CGContextRotateCTM方法来指定旋转角度,单位是弧度。正值表示顺时针旋转的角度,负值表示逆时针旋转的角度。

创建彷射变换

彷射变换方法在Quartz中可用于矩阵操作,而不是CTM。你可以使用这些方法用于构造一个你稍后将会应用到CTM中的矩阵,通过调用CGContextConcatCTM方法。彷射变换功能,既可用于操作,也可以返回一个CGAffineTransform数据结构。你可以构造一个简单或者复杂的可重用彷射变换。

彷射变换函数和CTM方法表现出相同的操作--变换、旋转、放大和合并。下表中的方法执行这些操作。需要说明的是每一个变换、旋转、和放大操作都有两种方法。

Function Use
CGAffineTransformMakeTranslation To construct a new translation matrix from x and y values that specify how much to move the origin.
CGAffineTransformTranslate To apply a translation operation to an existing affine transform.
CGAffineTransformMakeRotation To construct a new rotation matrix from a value that specifies in radians how much to rotate the coordinate system.
CGAffineTransformRotate To apply a rotation operation to an existing affine transform.
CGAffineTransformMakeScale To construct a new scaling matrix from x and y values that specify how much to stretch or shrink coordinates.
CGAffineTransformScale To apply a scaling operation to an existing affine transform.

评测彷射变换

你可以调用CGAffineTransformEqualToTransform方法来确定一个彷射矩阵是否和另一个彷射矩阵等效。

CGAffineTransformIsIdentity方法是一个有效的方法用于检测一个矩阵是否是恒等变换。恒等变换矩阵没有任何的变换,放大,或者旋转操作。对输入坐标运用这一变换总是返回输入坐标。Quartz常量CGAffineTransformIdentity代表恒等变换矩阵。

Quartz提供了一系列变量的方法用于下面从用户到设备空间的几何变换。你可以发现这些方法比应用调用CGContextGetUserSpaceToDeviceSpaceTransform方法返回彷射变换更简单。
* 点. CGContextConvertPointToDeviceSpace和CGContextConvertPointToUserSpace将一个CGPoint数据类型从一个空间转换到另一个空间。
* 尺寸。CGContextConvertSizeToDeviceSpace和CGContextConvertSizeToUserSpace将一个CGSize数据类型一个空间转换到另一个空间
* 矩形(Rectangles).CGContextConvertRectToDeviceSpace 和 CGContextConvertRectToUserSpace将一个CGRect数据类型从一个空间转换到另一个空间。

获取用户到设备空间的变换(Transform)

通常,当你使用Quartz进行绘制的时候,你仅仅是在用户空间上工作。Quartz为你完成了从用户到设备空间的转换。假如你的应用需要获取彷射变换,该变换是Quartz用于从用户到设备空间的转换,你可以调用CGContextGetUserSpaceToDeviceSpaceTransform方法

矩阵背后的数学(The Math behind the matrices)

##6. 图案 (Patterns)

一个图案是一系列重复绘制到图形上下文的绘制操作。你可以和使用颜色一样的方式来使用图案。当你使用pattern进行绘制的时候,Quartz将页分割成一系列pattern单元(cell),每一个块的pattern图像的尺寸,并且使用你提供的回调来绘制每个单元。

pattern 剖析

pattern单元是pattern的基本组件。

当你绘制一个pattern单元的时候,Quartz使用pattern空间作为坐标系。pattern空间是一个抽象的空间,使用当你创建pattern时候的pattern矩阵,用于映射你所指定的变换矩阵到默认的用户空间。

假如你不像要Quartz变换pattern块的话,你可以指定恒等矩阵。无论如何,你可以通过提供转换矩阵来实现有趣的效果。

Colored Patterns and Stencil(uncolored) patterns

平铺(Tiling)

平铺是渲染pattern单元到部分页(portion of page)的操作处理。当Quartz渲染一个Pattern到设备,Quartz需要提供调整pattern来适配设备空间。这就是,当渲染到设备时在用户空间定义的pattern块,有可能不能完美的适应,因为用户空间单元和设备像素之间的不同。

Quartz含有3种平铺选项,当必要时可以对pattern进行调整。Quartz可以维护:

  • pattern,在条件pattern单元
  • 单元直接的空隙

Patterns是如何工作的

patterns的操作和颜色比较类似,你可以设置一个填充或者描边模式然后调用绘制方法。Quartz使用你设置的称作"绘制"的pattern。比如说,假如你需要绘制一个使用纯色填充的矩形,你先调用一个方法,比如说CGContextSetFillColor,来设置填充颜色。然后你使用你指定的颜色参数,调用CGContextFillRect方法来绘制填充矩形。为了使用pattern进行绘制,你首先调用CGContextSetFillPattern来设置pattern。然后你使用你指定的pattern参数,调用CGContextFillRect来实际绘制。

##7. 阴影

阴影是一个绘制在底部的图像,从源偏移,一个图形对象以便形成光源投影到图形对象的
阴影效果.文本也可以被设置成阴影。阴影可以让一个图形展示出3D效果或者好像是浮动的。

阴影包含有三个特性:

  • x偏移,用于指定一个图形的水平方向的阴影偏移有多远。
  • y偏移,用于指定一个图形的垂直方向的阴影偏移有多远。
  • 模糊度,用于指定图像是否有硬边。

阴影是如何工作的

Quartz中阴影是图形状态的一部分。你可以调用CGContextSetShadow方法,传递图形上下文参数,偏移值,和模糊度值。设置阴影之后,你绘制的任何对象都含有黑色,三分之一alpha值的,设备RGB空间的阴影。换句话说,阴影使用设置的{0,0,0,1.0/3.0}RGBA值进行绘制。

当你通过调用CGContextSetShadowWithColor方法绘制阴影时,传递图形上下文,偏移值,和模糊度,和一个CGColor对象。

假如你在调用CGContextSetShadow或者CGContextSetShadowWithColor之前保存了图形状态,你可以通过回复图形状态来关闭阴影。你也可以通过设置阴影的颜色值为NULL来禁用阴影。

##8. 渐变

轴向渐变和线性渐变的例子

CGShading 和 CGGradient对比

延伸渐变边沿外部的颜色

使用CGGradient对象

使用CGShading对象

Quartz提供了一个复杂数据类型难过用于创建渐变--CGShadingRef 和 CGGradientRef。你可以使用这两者中的任意一个用于创建轴向或者径向渐变。渐变是从一种颜色变化到另一种颜色的填充。

一个轴向渐变(也叫线性渐变)沿着2端点之间的一条线条进行变化。所有位于一条线垂直于轴线的点,都具有相同的颜色值。

##9.

http://

本文地址:https://www.yhawaii.net/ios-quartz-2d-guild.html
版权声明:本文为原创文章,版权归  所有,欢迎分享本文,转载请保留出处!

 发表评论


表情