Quartz 2D概观

Core Graphics也称为Quartz 2D,是可用于iOS,tvOS和macOS应用程序开发的高级二维绘图引擎。Quartz 2D提供低级、轻量的2D渲染,无论显示或打印设备如何,其输出保真度均无与伦比。Quartz 2D与分辨率和设备无关。

Quartz 2D API易于使用,并提供对强大功能的访问,例如透明层、基于路径的绘图、离屏渲染、高级颜色管理、抗锯齿渲染以及PDF文档的创建、显示和解析。Quartz 2D会尽可能利用图形硬件的功能。

在Mac OS X中,Quartz 2D可以与所有其他图形技术和成像技术(Co​​re ImageCore VideoOpenGLQuickTime)一起配合使用。可以从QuickTime图形导入器中使用QuickTime函数GraphicsImportCreateCGImage在Quartz中创建图像,有关详细信息请参看QuickTime Framework Reference。Mac OS X中的Moving Data Between Quartz 2D and Core Image描述了如何向Core Image提供图像,Core Image是一个支持图像处理的框架。

同样,在iOS中,Quartz 2D可使用所有可用的图形技术和动画技术,例如Core AnimationOpenGL ESUIKit

可以使用Quartz 2D技术来执行以下任务:

  • 在应用程序中提供图形编辑功能;
  • 创建或者显示位图图像(bitmap image);
  • 处理PDF文档;

位图(Bitmap),又称栅格图或点阵图,是使用像素阵列(Pixel-array/Dot-matrix点阵)来表示的图像。

页面(The Page)

Quartz 2D使用painter’s model进行成像。 在painter’s model中,每个连续的绘画操作都会应用一层“涂料”到输出“画布”上,这通常被称为一个页面(page)。 可以通过其他绘图操作覆盖更多的涂料来修改页面上的涂料。 在页面上绘制的对象只能通过覆盖更多的涂料来修改。 这种模式使我们可以从少量强大的原函数中构建极其复杂的图像。

下图显示了painter’s model是如何工作的。为了获得下图上半部分中的Result图像,首先绘制左侧的形状,然后绘制实心形状。实心形状覆盖了第一个形状,除了第一个形状的周边之外,其他所有颜色都被遮盖了。下图下半部分中的Result图像则以相反的顺序绘制形状,其是首先绘制实心形状。 如您所见,在painter’s model中,绘图顺序很重要。

the painter’s model

页面可能是一张真实的纸(如果输出设备是打印机),也可能是一张虚拟的纸(如果输出设备是PDF文件),甚至可能是位图图像。页面的确切本质取决于我们使用的特定图形上下文。

绘图目标:图形上下文

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

可以将图形上下文视为绘图目标,如下图所示。当使用Quartz进行绘制时,所有特定于设备的特征都包含在使用的特定类型的图形上下文中。换句话说,只需向相同的Quartz绘制程序提供不同的图形上下文,就可以将同一图像绘制到不同的设备。Quartz会执行任何特定于设备的计算。

Quartz drawing destinations

有以下这些图形上下文可用于我们的应用程序:

  • 位图图形上下文可以将RGB颜色,CMYK颜色或者灰度绘制到位图中。位图是一个像素矩形阵列(或栅格),每个像素代表图像中的一个点。位图图像也被称为采样图像。请参看Creating a Bitmap Graphics Context

  • PDF图形上下文可以创建PDF文件。在PDF文件中,图形被保存为一系列命令。PDF文件和位图之间存在一些重大差异:

    • 与位图不同,PDF文件可能包含多个页面。
    • 在其他设备上从PDF文件绘制页面时,针对该设备的显示特性,优化了生成的图像。
    • PDF文件本质上与分辨率是无关的,可以无限增大或减小PDF文件的绘制尺寸,而无需牺牲图像细节。 用户感知的位图图像质量与要查看位图的分辨率有关。
  • 窗口图形上下文是可用于在窗口中绘图。注意,由于Quartz 2D是图形引擎而不是窗口管理系统,因此可以使用一种应用程序框架来获取窗口的图形上下文。有关详细信息,请参看Creating a Window Graphics Context in Mac OS X

  • 图层上下文(CGLayerRef)是与另一个图形上下文关联的屏幕外绘图目标。 将图层绘制到创建该图层的图形上下文中可以获得最佳性能。与位图图形上下文相比,图层上下文可能是用于屏幕外绘制的更好选择。请参看Core Graphics Layer Drawing

  • 如果要在Mac OS X中进行打印,则将内容发送到由打印框架管理的PostScript图形上下文。有关更多信息,请参看Obtaining a Graphics Context for Printing

Quartz 2D不透明数据类型

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

Quartz 2D使用不透明数据类型来创建对象,应用程序可以使用这些对象来实现特定的绘画输出。 下图显示了将绘图操作应用于Quartz 2D提供的三个对象时可以实现的各种结果。例如:

  • 可以通过创建PDF页面对象,将旋转操作应用到图形上下文中并要求Quartz 2D将PDF页面对象绘制到该图形上下文中,来旋转并显示PDF页面。
  • 可以通过创建图案对象,定义构成图案的形状以及在将图案绘制到图形上下文时将图案用作涂料,来绘制图案。
  • 可以通过创建阴影对象,提供确定阴影中每个点颜色的函数,然后要求Quartz 2D将阴影用作填充颜色,来用轴向或径向阴影填充区域。
Opaque data types are the basis of drawing primitives in Quartz 2D

Quartz 2D中可用的不透明数据类型包含以下这些:

  • CGPathRef,用于矢量图形来创建填充和描边的路径,请参看Paths
  • CGImageRef,用于根据提供的样本数据来表示位图图像和位图图像蒙版,请参看Bitmap Images and Image Masks
  • CGLayerRef,用于表示可用于重复绘制(例如用于背景或图案)和屏幕外绘制的绘画图层,请参看Core Graphics Layer Drawing
  • CGPatternRef,用于重复绘制,请参看Patterns
  • CGShadingRefCGGradientRef,用于绘制渐变,请参看Gradients
  • CGFunctionRef,用于定义采用任意数量的浮点参数的回调函数,当为阴影创建渐变时使用此数据类型,请参看Gradients
  • CGColorRefCGColorSpaceRef,用于告知Quartz如何解释颜色,请参看Color and Color Spaces
  • CGImageSourceRefCGImageDestinationRef,用于将数据移入和移出Quartz,请参看Data Management in Quartz 2DImage I/O Programming Guide
  • CGFontRef,用于绘制文本,请参看Text
  • CGPDFDictionaryRefCGPDFObjectRefCGPDFPageRefCGPDFStreamCGPDFStringRefCGPDFArrayRef,提供对PDF元数据的访问,请参看PDF Document Creation, Viewing, and Transforming
  • CGPDFScannerRefCGPDFContentStreamRef,用于解析PDF元数据,请参看PDF Document Parsing
  • CGPSConverterRef,用于将PostScript转换为PDF,在iOS中不可用,请参看PostScript Conversion

图形状态

Quartz根据current graphics state中的参数修改绘图操作的结果。图形状态包含会被应用到绘图例程中去的参数,绘制到图形上下文的例程会参考图形状态以确定如何呈现其结果。例如,当调用一个函数来设置填充颜色时,您正在修改存储在当前图形状态中的填充颜色参数值。当前图形状态的其他常用元素包括线宽,当前位置和文本字体大小。

图形上下文包含一个图形状态堆栈。当Quartz创建图形上下文时,堆栈为空。当我们保存图形状态时,Quartz将当前图形状态的副本压入堆栈。 当我们恢复图形状态时,Quartz将图形状态弹出堆栈顶部。被弹出的状态变为当前图形状态。

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

请注意,并非当前绘图环境的所有方面都是图形状态的元素。例如,当前路径不被视为图形状态的一部分,因此,当您调用函数CGContextSaveGState时,不会保存当前路径。调用此函数时,保存的图形状态参数包括以下这些:

  • Current transformation matrix (CTM)
  • Clipping area
  • Line: width, join, cap, dash, miter limit
  • Accuracy of curve estimation (flatness)
  • Anti-aliasing setting
  • Color: fill and stroke settings
  • Alpha value (transparency)
  • Rendering intent
  • Color space: fill and stroke settings
  • Text: font, font size, character spacing, text drawing mode
  • Blend mode

Quartz 2D 坐标系

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

The Quartz coordinate system

由于不同的设备具有不同的基础成像功能,因此必须以与设备无关的方式定义图形的位置和大小。例如,屏幕显示设备可能能够显示每英寸不超过96像素,而打印机可能能够显示每英寸300像素。如果在设备级别(在此示例中为96像素或300像素)定义坐标系,则在该空间中绘制的对象将无法在没有可见畸变的情况下在其他设备上复制。它们将显得太大或太小。

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

current transformation matrix还有第二个用处:改变对象的绘制方式。例如,要绘制旋转45度的方框,请在绘制方框之前旋转页面(CTM)的坐标系。Quartz使用旋转后的坐标系绘制到输出设备。

用户空间中的一个点由坐标(x,y)表示,其中x代表该点在水平轴(左和右)上的位置,y代表该点在垂直轴(上和下)上的位置。用户坐标空间的原点是点(0,0)。原点位于页面的左下角,如下图所示。在Quartz的默认坐标系中,x轴上的值随着页面左侧向右侧的移动而增加,y轴上的值随着页面底部向顶部的移动而增加。

某些技术使用与Quartz不同的默认坐标系来设置其图形上下文。相对于Quartz,此类坐标系是已被修改过的坐标系,在执行某些Quartz绘图操作时,必须对这类坐标系进行补偿。最常见的修改过的坐标系将原点放置在上下文的左上角,并将y轴更改为指向页面的底部。您可能会在以下几个地方看到使用此特定坐标系:

  • 在Mac OS X中,NSView的子类重写其isFlipped方法来返回YES
  • 在iOS中,UIView返回的绘图上下文(drawing context)。
  • 在iOS中,通过调用UIGraphicsBeginImageContextWithOptions函数创建的绘图上下文。

UIKit返回具有修改过的坐标系的Quartz绘图上下文的原因是UIKit使用了不同的默认坐标约定。它将transform(变换)应用于它创建的Quartz上下文,以便它们符合其约定。如果您的应用程序希望使用相同的绘图例程来绘制UIView对象和PDF图形上下文(由Quartz创建并使用默认坐标系),则需要应用transform,以便PDF图形上下文收到相同的修改过的坐标系。为了做到这点,需要应用一个将原点平移到PDF上下文的左上角并以-1来缩放y坐标的transform

使用缩放变换取反y坐标会更改Quartz绘图中的某些约定。例如,如果调用CGContextDrawImage将图像绘制到上下文中,则在将图像绘制到目标时,图像会通过transform进行修改。类似地,路径绘制例程接受指定在默认坐标系中沿顺时针或者逆时针方向绘制圆弧的参数。如果修改了坐标系,则结果也会被修改,就像图像在镜子中反射一样。在下图中,将相同的参数传递给Quartz会导致在默认坐标系中是一个顺时针圆弧,以及在y坐标被transform取反后的坐标系中是一个逆时针圆弧。

Modifying the coordinate system creates a mirrored image

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

重要:如果打算编写直接针对iOS上Quartz的应用程序,那么上面的讨论对于理解是至关重要的,但这还不够。在iOS 3.2和更高版本上,当UIKit为应用程序创建绘图上下文时,它还会对该上下文进行其他更改以匹配默认的UIKIt约定。特别是,不受CTM影响的图案和阴影会分别进行调整,以使它们的约定与UIKit的坐标系匹配。在这种情况下,应用程序无法使用CTM的等效机制来更改Quartz创建的上下文以匹配UIKit提供的上下文的行为。应用程序必须识别要绘制的上下文属于哪种类型,并调整其行为以符合上下文的期望。

内存管理:对象所有权

Quartz使用对对象进行引用计数的Core Foundation内存管理模式,创建Core Foundation对象后,其开始的引用计数为1。可以通过调用保留对象的函数来增加引用计数,并通过调用释放对象的函数来减少引用计数。当引用计数减为0时,对象会被释放。该模式允许对象安全共享对其他对象的引用。

需要牢记以下一些简单的规则:

  • 如果我们创建或复制了对象,则说明我们是对象的所有者,因此必须由我们负责释放它。也就是说,如果我们从名称中带有“Create”或“Copy”单词的函数中获取了对象,则在完成处理后必须释放该对象。否则,会导致内存泄漏。
  • 如果我们从名称中不包含“Create”或“Copy”单词的函数中获取了对象,则我们不具有对该对象的引用,也不用我们手动去释放该对象。该对象将在将来的某个时候由其所有者释放。
  • 如果我们不拥有对任何对象的引用,但又需要保留它,则我们必须保留它,并在完成使用后将其释放。可以使用特定于对象的Quartz 2D函数来保留和释放该对象。例如,如果收到对CGColorspace对象的引用,则可以使用CGColorSpaceRetainCGColorSpaceRelease函数根据需要保留和释放该对象。也可以使用Core Foundation函数CFRetainCFRelease,但是必须注意不要将NULL传递给这些函数。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容