Core Graphics 概述(二)

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图形导入器创建图像。详细信息请参阅QuickTime框架参考。Moving Data Between Quartz 2D and Core Image in Mac OS X描述了这是一个如何为Core Image提供图像,如何支持图像处理的框架。

类似地,在iOS中,Quartz 2D适用于所有可用的图形和动画技术,如Core animation、OpenGL ES和UIKit类。

The Page

Quartz 2D 使用画家的模型进行成像。在画家的模型中,每一个连续的绘图操作都在输出的“画布”(通常称为页面)上应用一层“颜料”。通过附加的绘图操作,可以通过覆盖更多的颜料来修改页面上的填充。在页面上绘制的对象不能被修改,除非覆盖更多的颜料。这个模型允许您从少量强大的原语中构造非常复杂的图像。

图1-1展示了画家的模型是如何工作的。为了在图形的顶部获得图像,左边的图形首先被绘制,然后是立体图形。实体形状覆盖了第一个形状,模糊了除了第一个形状的周长以外的所有形状。图片底部的图形则以相反的顺序绘制,首先绘制实体形状。如你所见,在画家的模型中,绘制顺序是很重要的。

painters_model.gif

The Page可以是一张真正的纸(如果输出设备是打印机);它可能是一张虚拟的纸(如果输出设备是PDF文件);它甚至可能是位图图像。页面的确切性质取决于您使用的特定图形上下文。

绘制目标:The Graphics Context

图形上下文是一种不透明的数据类型(CGContextRef),它封装了Quartz用于将图像绘制到输出设备(如PDF文件、位图或显示窗口)。图形上下文中的信息包括图形绘图参数和特定于设备的绘图在页面上的渲染。Quartz中的所有对象都是由图形上下文绘制或包含的。

您可以将图形上下文看作绘图目的地,如图1-2所示。使用Quartz时,所有特定于设备的特性都包含在您使用的特定类型的图形上下文中。换句话说,您可以通过为相同的Quartz绘图例程序列提供不同的图形上下文来将相同的图像绘制到不同的设备。您不需要执行任何特定于设备的计算; Quartz会为你做的。

draw_destinations.gif

这些图形上下文可供您的应用程序使用:

1、位图图形上下文允许您将RGB颜色、CMYK颜色或灰度绘制为位图。位图是像素的矩形阵列(或光栅),每个像素代表图像中的一个点。位图图像也称为采样图像。参见Creating a Bitmap Graphics Context.。
2、PDF图形上下文允许您创建PDF文件。在PDF文件中,绘图被保存为命令序列。PDF文件和位图之间有一些显著的区别:
a、与位图不同,PDF文件可能包含不止一个页面。
b、当您从另一个设备上的PDF文件中绘制页面时,生成的图像将针对该设备的显示特性进行优化。
c、PDF文件的分辨率与文件大小无关——绘制文件的大小可以无限增加或减少,而不会牺牲图像的细节。位图图像质量与要查看的位图的分辨率有关。
3、窗口图形上下文是可以用来绘制到窗口的图形上下文。注意,因为Quartz 2D是一个图形引擎,而不是窗口管理系统,所以您可以使用其中一个应用程序框架来获取窗口的图形上下文。有关详细信息,请参阅在Mac OS X中创建窗口图形上下文。
4、层上下文(CGLayerRef)是与另一个图形上下文关联的屏幕外绘图目的地。它是为了获得最佳性能而设计的,当将层绘制到图形上下文时它就会被创建。层上下文比位图图形上下文更适合用于屏幕外绘图。
5、当您想要在Mac OS X中打印时,您需要将内容发送到打印框架管理的PostScript图形上下文。有关更多信息,请参阅获取用于打印的图形上下文。

Quartz 2D不透明数据类型:

Quartz 2D API除了定义图形上下文之外,还定义了各种不透明的数据类型。因为API是核心图形框架的一部分,所以数据类型和对其进行操作的结构体使用CG前缀。

Quartz 2D通过应用程序操作的不透明数据类型创建对象,以实现特定的绘图输出。图1-3显示了当您将绘图操1、作应用于Quartz 2D提供的三个对象时可以获得的结果。例如:
您可以通过创建PDF页面对象、对图形上下文应用旋转操作以及请求Quartz 2D将页面绘制到图形上下文来旋转和显示PDF页面。
2、您可以通过创建模式对象、定义构成模式的形状和设置Quartz 2D来绘制模式,以便在绘制到图形上下文时将该模式用作绘图。
3、您可以通过创建一个着色对象(提供一个确定着色中每个点的颜色的函数)来用轴向或径向着色填充一个区域,然后要求Quartz 2D将该着色用作填充颜色。

图1-3在Quartz 2D中不透明数据类型是维持绘制的基础

drawing_primitives.gif

Quartz 2D中不透明的数据类型包括:

CGPathRef,用于矢量图形创建您填充或描边的路径。
CGImageRef,用于表示基于您提供的示例数据的位图图像和位图图像掩码。
CGLayerRef,用于表示绘图层,可用于重复绘图(例如背景或模式)和屏幕外绘图。
CGPatternRef,用于重复绘图。
CGShadingRef和CGGradientRef,用于绘制梯度。
CGFunctionRef,用于定义接受任意数量浮点参数的回调函数。在实现渐变着色时,可以使用此数据类型。
CGColorRef和CGColorSpaceRef,用于通知Quartz如何解释颜色。
CGImageSourceRef和CGImageDestinationRef,用于在Quartz中来回移动数据。
CGFontRef,用于绘制文本。
CGPDFDictionaryRef、CGPDFObjectRef、CGPDFPageRef、CGPDFStream、CGPDFStringRef和CGPDFArrayRef,提供对PDF元数据的访问。
CGPDFScannerRef和CGPDFContentStreamRef,它们解析PDF元数据。
CGPSConverterRef,用于将PostScript转换为PDF。它在iOS中不可用。

Graphics States

Quartz根据当前图形状态下的参数修改绘图操作的结果。图形状态包含参数,否则这些参数将作为绘制日常的参数。绘制到图形上下文的例程参考图形状态以确定如何呈现它们的结果。例如,当您调用一个函数来设置填充颜色时,其实是您修改了一个值并存储在当前图形状态中。当前图形状态的其他常用参数包括行宽、当前位置和文本字体大小。

图形上下文包含图形状态的堆栈。当Quartz创建图形上下文时,堆栈是空的。保存图形状态时,Quartz会将当前图形状态的副本推送到堆栈中。当您恢复图形状态时,Quartz会将图形状态弹出到堆栈顶部。弹出状态成为当前图形状态。

要保存当前图形状态,使用CGContextSaveGState函数将当前图形状态的副本推入堆栈。要恢复以前保存的图形状态,使用函数CGContextRestoreGState将当前的图形状态替换为堆栈顶部的图形状态。

注意,图形状态不包含当前绘图环境的所有元素。例如,当前路径不被认为是图形状态的一部分,因此在调用函数CGContextSaveGState时不会保存它。表1-1列出了调用此函数时保存的图形状态参数。

Table 1-1 Parameters that are associated with the graphics state

1ADA2C4F-C5E1-49EC-A09C-DD45A1236481.png

Quartz 2D 坐标系

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

quartz_coordinates.gif

由于不同的设备具有不同的底层成像能力,因此必须以独立于设备的方式定义图形的位置和大小。例如,屏幕显示设备可能每英寸显示不超过96像素,而打印机可能每英寸显示300像素。如果在设备级别定义坐标系统(在本例中,为96像素或300像素),则在该空间中绘制的对象不能在其他设备上复制而不产生可见失真。它们会显得太大或太小。

Quartz使用一个单独的坐标系统(用户空间)来实现设备独立性,它使用当前转换矩阵(或CTM)将其映射到输出设备-设备空间的坐标系统。矩阵是一个数学结构,用来有效地描述一组相关方程。当前变换矩阵是一种特殊类型的矩阵,称为仿射变换,它通过应用平移、旋转和缩放操作(移动、旋转和调整坐标系统大小的计算)将点从一个坐标空间映射到另一个坐标空间。

当前的转换矩阵有一个次要目的:它允许您转换对象的绘制方式。例如,要绘制一个旋转了45度的框,您需要在绘制框之前旋转页面的坐标系统(CTM)。Quartz绘制到输出设备使用旋转后的坐标系。

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

有些技术使用不同于Quartz使用的默认坐标系统来设置图形上下文。相对于Quartz,这样的坐标系是一个经过修改的坐标系,在执行一些Quartz绘图操作时必须进行补偿。最常见的修改坐标系统将原点放在上下文中的左上角,并将y轴改为指向页面底部。在一些地方,你可能会看到这个特定的坐标系使用如下:
1、在Mac OS X中,NSView的一个子类,它重写isFliped方法以返回YES。
2、在iOS中,由UIView返回的绘图上下文。
3、在iOS中,通过调用UIGraphicsBeginImageContextWithOptions函数创建的绘图上下文。

UIKit使用修改后的坐标系统返回Quartz绘图上下文的原因是UIKit使用了不同的默认坐标约定;它将转换应用于它创建的Quartz上下文,以便它们与它的约定相匹配。如果您的应用程序要使用相同的绘图程序画UIView对象和一个PDF图形上下文(由Quartz和使用默认坐标系),您需要应用一个变换,PDF格式的图形上下文接收相同的修改坐标系统。为此,应用一个转换,将原点转换到PDF上下文的左上角,并将y坐标缩放到-1。

使用缩放变换来抵消y坐标改变了Quartz绘图中的一些惯例。例如,如果您调用CGContextDrawImage来将图像绘制到上下文中,那么在将图像绘制到目标中时,该图像将被转换修改。类似地,路径绘制例程接受参数,这些参数指定在默认坐标系中圆弧是顺时针还是逆时针绘制。如果坐标系统被修改,结果也会被修改,就像图像在镜子中被反射一样。在图1-5中,将相同的参数传递到Quartz中,会在默认坐标系中产生顺时针的弧,而在y坐标被转换否定后,会产生逆时针的弧。

Figure 1-5 Modifying the coordinate system creates a mirrored image.


flipped_coordinates.jpg

您的应用程序来调整任何应用于Quartz调用图行上下的转换。例如,如果您希望将图像或PDF正确地绘制到图形上下文中,您的应用程序可能需要临时调整图形上下文的CTM。在iOS中,如果你使用UIImage对象来包装你创建的CGImage对象,你不需要修改CTM。UIImage对象自动补偿UIKit应用的修改坐标系统。

重要提示:如果您计划在iOS上编写直接针对Quartz的应用程序,那么以上讨论对于理解这一点至关重要,但这还不够。在iOS 3.2和更高版本中,当UIKit为你的应用程序创建一个绘图上下文时,它还会对上下文进行额外的更改,以匹配默认的UIKit约定。特别地,不受CTM影响的模式和阴影被单独调整,以便它们的约定与UIKit的坐标系统相匹配。在这种情况下,您的应用程序无法使用与CTM相同的机制来更改Quartz创建的上下文以匹配UIKit提供的上下文的行为;您的应用程序必须识别它所使用的上下文类型,并调整其行为以匹配上下文的期望。

内存管理:Object Ownership

Quartz使用Foundation内存管理模型中的引用计数。创建时,Core Foundation对象从引用计数为1开始。可以通过调用函数来保留对象来增加引用计数,通过调用函数来释放对象来减少引用计数。当引用计数降为0时,对象被释放。这个模型允许对象安全地共享对其他对象的引用。

这里有一些简单的规则需要记住:
1、如果您创建或复制一个对象,那么您拥有它,因此您必须释放它。也就是说,通常情况下,如果从名称中带有“Create”或“Copy”字样的函数中获取对象,那么在处理完对象之后,必须释放该对象。否则,将导致内存泄漏。
2、如果从函数中获取的对象的名称中不包含“Create”或“Copy”,则不拥有对该对象的引用,并且不能释放它。该对象将在未来的某个时候由其所有者释放。
3、如果您不拥有一个对象,并且需要保留它,那么您必须保留它,并在处理完之后释放它。您可以使用特定于对象的Quartz 2D函数来保留和释放该对象。例如,如果您收到对CGColorspace对象的引用,您可以使用CGColorSpaceRetain和CGColorSpaceRelease函数根据需要保留和释放对象。您还可以使用核心基础函数CFRetain和CFRelease,但必须注意不要将NULL传递给这些函数。