Quartz 2D总览(翻译)

转载自:http://www.sunkehappy.com/2013/02/22/quartz-2d总览(翻译)/

Quartz 2D总览

Quartz 2D是一个在iOS环境中和在Mac OS X内核之外的应用程序环境中可用的二维绘图引擎。你可以用Quartz 2D的应用程序接口(application programming interface, API)来使用例如基于路径的绘图,透明绘图,阴影,绘制引用,透明层,颜色管理,抗锯齿渲染,PDF文档生成和PDF元文件访问的功能。任何时候只要可以,Quartz 2D都会发挥图形硬件的强大能力。
在Mac OS X中,Quartz 2D 能够与所有其它的图形和图片技术–Core Image,Core Video,OpenGL,还有QuickTime。通过使用QuickTime的函数GraphicsImportCreateCGImage,也可以在QuickTime的图形引入器的Quartz中创建一张图片。详情请参见“QuickTime框架参考”。“Mac OS X中在Quartz 2D和Core Image之间传输数据”描述了你怎么样才可以把图片传到Core Image,Core Image是一个支持图片处理的框架。
相似的,在iOS中,Quartz 2D与所有可用的图形和动画技术兼容,例如Core Animation,OpenGL ES,还有UIKit类。

Quartz 2D的图形使用的是打印机模型。在打印机模型中,每一个成功的绘画操作都是把一个“画”的层叠加到一个输出“画布”上,这叫做页。页上的绘画可以通过叠加更多额外的绘画操作来修改。在页上绘制好的对象只能通过叠加更多的绘画来修改。这个模型允许你通过很少的强大指令来构建及其复杂的图形。
图1-1显示了打印机模型是如何工作的。如果想要得到上面的那张绘制结果,左边的图形要先被画上,然后才是右边的那张实心的图形。实心的图形叠加在第一个图形上之后,它会遮住第一个图形最外边边界之外的所有部分。在下面的那个绘画中,两张图形的绘制顺序是相反的,实心的图形是先绘制的。你可以看到,在打印机模型中,绘制顺序是很重要的。

图1-1

页可以使一张真正的纸(如果输出设备是打印机);也可以是一张虚拟的纸(如果输出设备是一个PDF文件);甚至可以是一个位图图片。页的准确的特征取决于你所用的图形上下文。

绘画目的地:图形上下文

一个图形上下文是一个不透明的数据类型(CGContextRef),它封装了Quartz用来绘制图片到一个输出设备,例如一个PDF文件,一个位图,或者显示器上的一个窗口,的信息。一个图形上下文中的信息包括图形绘制参数和设备相关的页上的绘画的表示形式。Quartz中的所有的对象都是被画在,或者被包括在,一个图形上下文上。

你可以把图形上下文想象成一个绘画目的地,就像图1-2中显示的那样。当你用Quartz绘画的时候,所有设备相关的特征都被包括在你所用的图形上下文中。换句话说,你可以通过给Quartz绘画程序提供不同的图形上下文来把一张图片画在不同的设备上。你不需要任何设备相关的计算;Quartz会为你做这些事。

图1-2

下面这些图形上下文是你的程序可以用的:

•    一个位图图形上下文允许你绘制RGB颜色,CMYK颜色,或者灰度图到一个位图中。一个位图是一个像素的矩形数组(或者光栅),每一个像素代表图形中的一个点。位图也叫采样图。参见“创建一个位图图形上下文”。
•    一个PDF图形上下文允许你创建PDF文件。在一个PDF文件中,你的绘画是被保存为一系列的命令。PDF文件和位图有极大不同点:

▫    PDF文件不像位图,它可以有多页。
▫    当你绘制一个PDF文件的一页到不同的设备上的时候,被绘制出来的图片是根据那个设备的显示特点优化过的
▫    PDF文件是分辨率无关的–它们所绘制成结果的大小可以无限的放大和缩小而不损失图片细节。位图图片的用户能够察觉到的质量是与位图想要被查看时的分辨率密切相关的。

参见“创建一个PDF图形上下文”
•    一个窗口上下文是一个你可以用来在一个窗口上绘画的图形上下文。注意Quartz 2D是一个图形引擎而不是一个窗口管理系统,你需要用应用程序框架中的一个来获取一个窗口的图形上下文。参见“在Mac OS X中创建窗口图形上下文”
•    一个层上下文(CGLayerRef)是一个屏幕之外的与另外一个图形上下文关联的绘画目的地。它是被设计用来当绘制这个层到创建它的图形上下文的时候达到最优性能。对于屏幕之外的绘画一个层上下文远比位图图形上下文好得多。参见“Core Graphics层绘画”。
•    当你想要在Mac OS X中打印的时候,你需要把要打印的内容发送给一个被打印框架管理的PostScript图形上下文。参见“获得用来打印的图形上下文”。

Quartz 2D 不透明数据类型

除了图形上下文之外,Quartz 2D API还定义了各种各样的不透明数据类型。因为这些API是Core Graphics的一部分,这些数据类型和操作这些数据的程序使用CG前缀。
Quartz 2D从你的应用程序操作的不透明数据类来创建对象,这样来获得特定的打印结果。图1-3展示了一系列的当你应用绘画操作到三个Quartz 2D提供的对象上时,你可以获得的结果。例如:
•    你可以通过创建一个PDF页对象,加上旋转操作到一个图形上下文,让Quartz 2D来绘制这个页到一个图形上下文上,来旋转和显示一个PDF页。
•    你可以通过创建一个图案对象,定义组成这个图案对象的形状,当Quartz 2D要在一个图形上下文上绘画时设置Quartz 2D用这个图案作为绘画,来绘制图案。
•    你可以通过创建一个着色对象,提供一个能够确定着色中每一个点的颜色的函数,然后让Quartz 2D用这个着色作为填充颜色,来给一个区域用轴向的后者放射形的着色填充。

图1-3

在Quartz 2D中可用的不透明数据类型包括:
•    CGPathRef,用来给矢量图创建你可以填充或者描边的路径。参见“路径”
•    CGImageRef,用来代表基于你提供的采样数据的位图图片和图片掩码。参见“位图图片和图片掩码”。
•    CGLayerRef,用来代表一个可以用来代表重复绘画(例如北京或者着色)和离屏渲染的绘画层。参见“Core Graphics层渲染”。
•    CGPatternRef,用来代表重复绘画。参见“图案”。
•    CGShadingRef和CGGradientRef,用来绘制梯度,参见“梯度”
•    CGFunctionRef,用来定义接收任意数目浮点参数的回调函数。你可以在给一个阴影创建梯度的时候使用这个数据类型。参见“梯度”
•    CGColorRef和CGColorSpaceRef,用来告诉Quartz如何解析颜色。参见“颜色和颜色空间”。
•    CGImageSourceRef和CGImageSpaceRef,当你把数据移入或者移出Quartz的时候你会使用的数据类型。参见“Quartz 2D中的数据管理”和“图片I/O编程指南”。
•    CGFontRef,用来绘制文本。参见文本。
•    CGPDFDictionaryRef,CGPDFObjectRef,CGPDFPageRef,CGPDFStream,CGPDFStringRef和CGPDFArrayRef,提供了访问PDF元数据的方法。参见“PDF文档创建,展示和变换”。
•    CGPDFScannerRef和CGPDFContentStreamRef,解析PDF元数据。参见“PDF文档解析”。
•    CGPSConverterRef,用来把PostScript转换成PDF。在iOS中无法使用。参见“PostScript转换”。

图形状态

Quartz会根据当前图形状态中的参数来修改绘画操作的结果。图形状态包括被绘画程序当做参数的参数。那些将要在图形上下文中绘画的程序会询问图形状态如何渲染它们的结果。例如,当你调用函数来填充颜色的时候,你会修改存储在当前图形状态中的值。其它常用的当前图形上下文中的元素包括线宽,当前位置和文本字体大小。
图形上下文中有个图形状态的栈。当Quartz创建一个图形上下文的时候,栈为空。当你保存图形状态的时候,Quartz会把当前图形状态的拷贝压入栈中。当你恢复图形状态的时候,Quartz会从栈中弹出一个图形状态。被弹出的图形状态成为当前图形状态。
可以用CGContextSaveGState函数来保存当前图形状态,把它的一份拷贝压入栈中。用CGContextRestoreGState来恢复之前保存的图形状态,用栈顶的图形状态代替当前图形状态。
注意不是当前绘画环境的所有方面都是图形状态的元素。例如,当前路径就不是图形状态的一部分,因此当你调用函数CGContextSaveGState的时候也不会被保存。当你调用这个函数的时候被保存的图形状态参数被列在了表1-1
表 1-1  与图形状态关联在一起的参数

参数在本章中讨论的章节名
当前变换矩阵(Current transformation matrix,CTM)“变换”
裁剪区域“路径”
线:宽度,交点,端点,虚线,斜接限制“路径”
曲线估计精确度(平面)“路径”
抗锯齿设置“图形上下文”
颜色:填充和描边设定“颜色和颜色空间”
Alpha值(透明度)“颜色和颜色空间”
映射方式“颜色和颜色空间”
颜色空间:填充和描边设置“颜色和颜色空间”
文本:字体,字体大小,字符间距,文本绘制模式“文本”
混合模式“路径” 和 “位图图片和图片掩码”

Quartz 2D坐标系

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

图1-4

因为不同的设备有不同的成像能力,图形就必须以一种与设备无关的方法来确定位置和大小。例如,一个显示器可以显示最多96像素每英寸,而一个打印接可以显示300像素每英寸。如果你在设备层来定义坐标系(在这个例子中,要么96像素要么300像素),在一个空间中画好的对象没办法无失真的在别的设备上显示。它们会变得很大或者很小。
Quartz通过用另外一个坐标系统–用户空间–把它映射到输出设备的坐标系中–设备空间–使用当前变换矩阵(current transformation matrix, CTM)。一个矩阵是一个被用来有效地描述相关方程式的集合的数学概念。当前变换矩阵是矩阵中的一个特类,叫做仿射变换,通过应用平移,旋转和缩放操作(平移,旋转和变换坐标系大小的计算)来把一个坐标系空间中的点映射到另一个坐标系空间。
当前变换矩阵还有第二个目的:它让你能够改变对象是如何绘制的。例如,画一个旋转45度的盒子,你在画盒子之前旋转页的坐标系(就是CTM)。Quartz会用旋转过的坐标系来在输出设备上绘画。
一个在用户空间中点是用坐标点对(x,y)来代表的,其中x代表在水平轴上的位置(左和右),y代表竖直轴(上和下)。用户坐标空间的起点是点(0,0)。起点是在页的左下角,如图1-4所示。在Quartz的默认坐标系中,x轴上从左到右是增加的,y轴是从下到上增加的。
一些技术通过使用与Quartz用的不同的默认坐标系来初始化图形上下文。相对于Quartz,这样的坐标系是一个修改过的坐标系而且当执行某些Quartz绘画操作的时候也必须被抵消掉。最常见的修改过的坐标系会把起点放到左上角并且把y轴改成朝下的。你可能会见到这种特殊坐标系使用的地方如下:
•    在Mac OS X中,一个覆盖它的isFlipped方法并返回YES的NSView的子类。
•    在iOS中,一个UIView返回的绘画上下文。
•    在iOS中,一个通过调用UIGraphicsBeginImageContextWithOptions函数创建的绘画上下文。
UIKit返回给Quartz带有修改过的坐标系的绘画上下午的原因是因为UIKit用一种不同的默认的坐标约定;它会给它创建的Quartz上下文加上变换这样这些上下文才和它的约定匹配。如果你的程序想要使用与UIview对象和一个PDF图形上希望(被Quartz创建的并且使用默认坐标系)相同的绘画程序,你必须要加上转换,这样PDF图形上希望才能接收相同的修改过的坐标系。想要这样做的话,加上这样的变换:把起点变换到左上角并且把y坐标乘以-1。
用一个缩放变换来把y坐标取反可以改变在Quartz绘画中的约定。例如,如果你调用CGContextDrawImage来绘制一张图片到上下文中,图片会在当它被画到目的地的时候被这个变换所修改。相似的,路径绘画程序接收在默认坐标系中指定一个弧线是顺时针还是逆时针绘制的参数。如果一个坐标系被修改了,绘制结果也会被修改,就好像是这个图片是在镜子中显示的一样。在图1-5中,给Quartz传递相同的参数,在默认坐标系中会是顺时针的弧,在y坐标被取反的坐标系中是逆时针的弧。

图1-5

调整Quartz调用来使用经过变换的上下文是你的程序要做的事情。例如,如果你想要在图形上下文中正确的绘制图片或者PDF,你的程序可能会需要临时的调整图形上下文的CTM。在iOS中,如果你用UIImage对象来包装你创建的CGI妈个对象,你不需要修改CTM。UIKit会帮助UIImage对象自动抵消修改过的坐标系。
重要:如果你打算在iOS中直接以Quartz为目标来写程序,上面的讨论是你必须要明白的,而且这些还不够。在iOS3.2和更新的版中,当UIKit给你的程序创建一个绘画上下文的时候它也会给这个上下文加上额外的操作来让它和默认的UIKit约定匹配。尤其是图案和阴影(它们不受CTM的影响),它们需要别的对上下文的操作来和默认的UIKit约定相匹配。如果是这样的话,就没有相等的你的程序可以用来改变Quartz创建的上下文的,和UIKit提供的上下文的行为相匹配的机制;你的程序必须识别它将要画到的上下文是哪一种,然后调整它的行为来和这个上下文匹配。

内存管理:对象拥有权

Quartz使用Core Foundation内存管理模型,对象的引用是被计数的。当被创建的时候Core Foundation对象的引用计数是1。你可以通过调用一个函数来保留这个对象,这样会增加引用计数。也可以通过调用函数来释放对象,这样会减少引用计数。当引用计数是0的时候,这个对象会被释放掉。这个模型允许对象和其它对象安全的共享引用。
需要记住的几个简单的规则如下:
•    如果你创建或者拷贝一个对象,你拥有它,因此你也必须释放它。那就是,一般来说,如果你通过带有“Create”或者“Copy”单词的函数来获得一个对象的时候,你必须在你做完对这个对象有关的操作之后释放它。否者内存会被泄露。
•    如果你通果不包含“Create”或者“Copy”单词的函数来获得一个对象的时候,你不拥有这个对象的引用,你也禁止释放它。这个对象会被它的拥有者在将来的某处被释放。
•    如果你不用有某个对象但是你又想保留它,你必须获得它的引用,当你做完对它的操作之后释放它。你调用Quartz 2D的特定于一个对象的函数来获得和释放某类对象。例如,如果你接收到一个CGColorSpace对象的引用,你用CGColorSpaceRetain函数和CGColorSpaceRelease来获得和释放这个对象。你也可以用Core Foundation的CFRetain和CFRelease函数,但是你不能给它们传递NULL。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值