logo头像

小玉的技术博客

Quartz2D编程之概述

Quartz 2D概述

Quartz 2D是一个二维图形绘制引擎,支持iOS环境和Mac OS X环境。我们可以使用Quartz 2D API来实现许多功能,比如基本路径的绘制、透明度、描影、绘制阴影、透明层、颜色管理、反锯齿、PDF文档生成和PDF元数据访问。在需要的时候,Quartz 2D还可以借助图形硬件的功能。
在Mac OS X中,Quartz 2D可以与其它图形图像技术混合使用,如Core Image、Core Video、OpenGL、QuickTime。例如,通过使用 QuickTime的GraphicsImportCreateCGImage函数,可以用 Quartz从一个 QuickTime图形导入器中创建一个图像。

The Page

Quartz 2D在图像中使用了绘画者模型。在绘画者模型中,每个连续的绘制操作都是将一个绘制层放置于一个画布,我们通常称这个画布为Page。 Page上的绘图可以通过额外的绘制操作来叠加更多的绘图。Page上的图形对象只能通过叠加更多的绘图来改变。这个模型允许我们使用小的图元来构建复杂的图形。
图1-1展示了绘画者模型如何工作。从图中可以看出不同的绘制顺序所产生的效果不一样。

Page可以是一张纸(如果输出设备是打印机),也可以是虚拟的纸张(如果输出设备是PDF文件),还可以是bitmap图像。这根据实际使用的graphics context而定

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

图形上下文(Graphics Context)是一一种不透明的数据类型(CGContextRef),它封装了Quartz用于绘制图像到输出设备(如PDF文件,位图或显示器上的窗口)的信息。图形上下文(Graphics Context)中的信息包括在Page中的图像的图形绘制参数和设备相关的特定表示。Quartz中所有的对象都是绘制到或包含在图形上下文中。
您可以将图形上下文视为一个绘图目标,如图1-2所示。 使用Quartz进行绘制时,所有设备特定的特征都包含在您使用的的图形上下文中。 换句话说,您可以简单地通过提供不同的图形上下文,就可以将相同的图像绘制到不同的设备。 您不需要执行任何设备特定的计算;这些都由Quartz替我们完成。

Quartz提供了以下几种类型的Graphics Context

  1. Bitmap Graphics Context(位图图形上下文)
  2. PDF Graphics Context(PDF图形上下文)
  3. Window Graphics Context(窗口图形上下文)
  4. Layer Context(层上下文CGLayerRef)
  5. Post Graphics Context(PostScript图形上下文)

    Quartz 2D 数据类型

    除了图形上下文之外,Quartz 2D API还定义了各种数据类型。由于API是Core Graphics框架的一部分,因此数据类型和对它们进行操作的例程使用CG前缀。
    Quartz 2D使用这些数据类型创建对象,通过操作这些对象来获取特定的图形。
    图1-3显示了当您将绘图操作应用于Quartz 2D提供的三个对象时,您可以实现的各种结果。例如:
  • 您可以通过创建PDF页面对象来旋转和显示PDF页面,对图形上下文应用旋转操作,并要求Quartz 2D将页面绘制到图形上下文中。
  • 您可以通过创建一个图案对象来绘制图案,定义构成图案的形状,并设置Quartz 2D将图案作为绘制时,绘制到图形上下文。
  • 您可以通过创建着色对象来填充具有轴向或径向着色的区域,提供一个函数来确定着色中每个点的颜色,然后要求Quartz 2D使用着色作为填充颜色。

    下面列出了Quartz 2D包含的数据类型:
  1. CGPathRef:用于矢量图形,可以创建路径,并进行填充(fill)或描画(stroke)
  2. CGImageRef:用于根据您提供的示例数据来表示位图图像和位图图像蒙版
  3. CGLayerRef:用于重复绘图(例如用于背景或图案)和用于离屏绘制的绘图层
  4. CGPatternRef:用于重复绘图
  5. CGShadingRef、CGGradientRef:用于绘制渐变
  6. CGFunctionRef:用于定义采用任意数量的浮点参数的回调函数。在为阴影创建渐变时使用此数据类型
  7. CGColorRef, CGColorSpaceRef:用于通知Quartz如何解释颜色
  8. CGImageSourceRef,CGImageDestinationRef:用于将数据移入和移出Quartz
  9. CGFontRef:用来绘制文本
  10. CGPDFDictionaryRef, CGPDFObjectRef, CGPDFPageRef, CGPDFStream, CGPDFStringRef, and CGPDFArrayRef:它们提供对PDF元数据的访问
  11. CGPDFScannerRef, CGPDFContentStreamRef:用于解析PDF元数据
  12. CGPSConverterRef:用于将PostScript转化成PDF。在iOS中不能使用。

    图形状态(Graphics States)

    Quartz根据当前图形状态下的参数修改绘图操作的结果。图形状态包含用于绘制程序的参数。绘制程序根据这些绘图状态来决定如何渲染结果。例如,当您调用函数来设置填充颜色时,您正在修改存储在当前图形状态中的值。当前图形状态的其他常用元素包括线宽,当前位置和文本字体大小。
    图形上下文包含一堆图形状态。当Quartz创建一个图形上下文时,栈是空的。保存图形状态时,Quartz将当前图形状态的副本压入栈。当你恢复图形状态时,Quartz弹出栈顶部的图形状态。弹出的状态成为当前的图形状态。
    可使用函数CGContextSaveGState来保存图形状态,CGContextRestoreGState来还原图形状态。

【注意】并非当前绘图环境的所有方面都是图形状态的元素。例如,当前路径不被视为图形状态的一部分,因此在调用函数CGContextSaveGState时不会保存。调用此函数时保存的图形状态参数如表1-1所示

Quartz 2D 坐标系统

如图1-4所示,坐标系定义用于表示要在页面上绘制的对象的位置和大小的位置范围。 您可以在用户空间坐标系中指定图形的位置和大小,或者更简单地指定用户空间。 坐标被定义为浮点值。

由于不同的设备具有不同的底层成像功能,所以图形的位置和大小必​​须以设备。例如,屏幕显示设备可能能够显示每英寸不超过96个像素,而打印机可能能够显示每英寸300个像素。如果在设备级别上定义坐标系统,则在一个设备上绘制的图形无法在其它设备上正常显示。

Quartz使用当前的转换矩阵(current transformation matrix, CTM)将一个独立的坐标系统(user space)映射到输出设备的坐标系统(device space),以此来解决设备依赖问题。矩阵是用来有效描述一组相关方程的数学结构。CTM是一种特殊类型的矩阵(affine transform, 仿射矩阵),通过应用平移,旋转和缩放操作(移动,旋转和调整坐标系的计算)将点从一个坐标空间映射到另一个坐标空间。

当前的转换矩阵(CTM)还有另外一个目的:它允许你通过转换来决定对象如何被绘制。例如,要绘制一个旋转45度的方框,在绘制方框之前,旋转页面的坐标系统。Quartz使用旋转的坐标系统绘制到输出设备。

用户空间中的点用坐标对(x,y)表示,其中x表示沿着水平轴(左侧和右侧)的位置,y表示垂直轴(上和下)。用户坐标空间的原点是点(0,0)。原点位于页面的左下角,如图1-4所示。在Quartz的默认坐标系中,x轴从页面左侧向右侧移动时增加。从页面的底部向顶部移动时,y轴的值会增加。

有一些技术在设置它们的graphics context时使用了不同于Quartz的默认坐标系统。相对于Quartz来说,这些坐标系统是修改的坐标系统(modified coordinate system),当在这些坐标系统中显示Quartz绘制的图形时,必须进行转换。最常见的一种修改的坐标系统是原点位于左上角,而沿着y轴从上到下坐标值逐渐增大。我们可以在如下一些地方见到这种坐标系统:

  • 在Mac OS X中,重写过isFlipped方法以返回yes的NSView类的子类
  • 在iOS中,由UIView返回的绘图上下文。
  • 在iOS中,通过调用UIGraphicsBeginImageContextWithOptions函数创建一个绘图上下文。
    UIKit返回具有修改后的坐标系统Quartz绘图上下文的原因是UIKit使用不同的默认坐标约定;它将转换应用到它创建的Quartz上下文,以便它们与其约定匹配。如果您的应用程序想要使用相同的绘图例程绘制UIView对象和PDF图形上下文(由Quartz创建并使用默认坐标系统),则需要应用转换,以便PDF图形上下文接收相同的修改坐标系。为此,请应用一个转换,将原点转换为PDF上下文的左上角,并将y坐标缩放-1。

使用缩放变换否定y坐标会改变Quartz绘图中的一些约定。例如,如果您调用CGContextDrawImage将图像绘制到上下文中,则该图像将在绘制到目标中时由该变换进行修改。同样,路径绘制例程接受参数,该参数指定是否在默认坐标系中以顺时针或逆时针方向绘制圆弧。如果修改了坐标系,结果也会被修改,就好像图像被反射到镜子中一样。在图1-5中,将相同的参数传递到Quartz将导致默认坐标系中的顺时针圆弧,以及在y坐标被变换否定之后的逆时针圆弧。

我们的应用程序负责调整Quartz调用以确保有一个转换应用到上下文中。例如,如果你想要一个图片或PDF正确的绘制到一个Graphics Context中,你的应用程序可能需要临时调整Graphics Context的CTM。在iOS中,如果使用UIImage对象来包裹创建的CGImage对象,可以不需要修改CTM。UIImage将自动进行补偿以适用UIKit的坐标系统。

【重要】如果你打算在iOS上开发与Quartz相关的程序,了解以上所讨论的是很有用的,但不是必须的。在iOS 3.2及后续的版本中,当UIKit为你的应用程序创建一个绘图上下文时,也对上下文进行了额外的修改以匹配UIKit的约定。特别的,patterns和shadows(不被CTM影响)单独进行调整以匹配UIKit坐标系统。在这种情况下,没有一个等价的机制让CTM来转换Quartz和UIKit的上下文。我们必须认识到在什么样的上下文中进行绘制,并调整行为以匹配上下文的预期。

内存管理:对象所有权

Quartz使用Core Foundation内存管理模型,其中的对象是引用计数的。所以,对象的创建与销毁与通常的方式是一样的。在Quartz中,需要记住如下一些规则:

有几条简单的规则需要牢记:

  • 如果您创建或拷贝对象,则您拥有该对象,因此您必须将其释放。通常,如果使用有”Create”或“Copy”单词的函数获取一个对象,当使用完后必须释放,否则将导致内存泄露。
  • 如果使用不含有”Create”或“Copy”单词的函数获取一个对象,你将不会拥有对象的引用,不需要释放它。
  • 如果你不拥有一个对象而打算保持它,则必须retain它并且在不需要时release掉。可以使用Quartz 2D的函数来指定retain和release一个对象。例如,如果创建了一个CGColorspace对象,则使用函数CGColorSpaceRetain和CGColorSpaceRelease来retain和release对象。同样,可以使用Core Foundation的CFRetain和CFRelease,但是注意不能传递NULL值给这些函数。

    参考文章

    Quartz 2D Programming Guide
支付宝打赏 微信打赏

赞赏是不耍流氓的鼓励