CoreGraphics(Quartz 2D) | 基础概念篇:

CoreGraphics是"艺名",学名是Quartz 2D,是二维图形绘制引擎,支持 iOS 和 OS X。
Quartz 2D的API使用简单,提供了很多强大的特性,如:透明层,基于路径绘图,离屏渲染,先进的色彩管理,防锯齿渲染,以及PDF文件的创建、展示和解析。
关于CG,工作用到的并不是非常多,但是作为开发者们耳熟能详的框架、其优秀的特性,奈何不了手痒痒。一直关于CG限于阅读博客、官文(官方文档),但“纸上得来终觉浅,绝知此事要躬行”啊。
此文是对于官文的总结和应用。
简介
哪些场景下会用到CoreGraphics
-
1.绘制图形。
-
2.需要提供图像编辑功能。
-
3.创建或者展示bitmap图片。
-
4.与PDF相关的操作。
概览
Page(画布)
Quartz 2D在图像中使用了绘画者模型(painter’s model)。在绘画者模型中,简单说,当前的图层A,在上面添加图层B,A被B遮盖的地方将不会显示出来,而只显示A未被覆盖的地方和B层。
Page可以是一张纸(如果输出设备是打印机),也可以是虚拟的纸张(如果输出设备是PDF文件),还可以是bitmap图像。这根据实际使用的graphics context而定。
Graphics Context(图形上下文)
Graphics Context 是一种不透明数据类型,它封装了Quartz绘制图像到输出设备上所用到的信息,输出设备可以是PDF文件,bitmap内存或者显示器。同一张图片可以通过指定不同的Context,即可输出到不同的设备上。
Quartz提供了以下几种类型的Graphics Context,详细的介绍将在后续章节说明:
- Bitmap Graphics Context
- PDF Graphics Context
- Window Graphics Context
- Layer Context
- Post Graphics Context
其他的图形上下文
除了上面几种Context,Quartz还提供下面这些上下文,他们都以CG开头,Quartz 2D在这些context上创建对象操作对象,从而获得某一特定的输出(大白话这么说,根据你要创建的东西不一样,可以是路径、图片、layer等等,而创建不同的context,从而输出你要的结果,比如一张美美的图片啦)。
常用的
- CGPathRef:用于向量图,可创建路径,并进行填充或描画(stroke)
- CGImageRef:用于表示bitmap图像和基于采样数据的bitmap图像遮罩。
- CGLayerRef:用于表示可用于重复绘制(如背景)和幕后(offscreen)绘制的绘画层
- CGPatternRef:用于重绘图
- CGShadingRef、CGGradientRef:用于绘制渐变
不常用的 详细说明链接
- CGFunctionRef; CGColorRef, CGColorSpaceRef; CGImageSourceRef,CGImageDestinationRef; CGFontRef; CGPDFDictionaryRef, CGPDFObjectRef, CGPDFPageRef; CGPDFStream, CGPDFStringRef, and CGPDFArrayRef;
CGPDFScannerRef, CGPDFContentStreamRef;
CGPSConverterRef;
Quartz 2D 坐标系统
在iOS 3.2以后的版本,当创建一个绘图上下文时,UIKit对上下文进行了额外的修改以匹配UIKit坐标习惯。但,patterns和shadows(不被CTM影响)单独进行调整以匹配UIKit坐标系统。因为需要理解在哪种上下文中进行绘制,并调整行为以匹配上下文的预期。
内存管理
通常,以”Create”或“Copy”单词的函数获取一个对象,当使用完后必须释放,否则将导致内存泄露。如果不是用上面的两种“关键字”定义的,你将不会拥有对象的引用,不需要释放它。
如果你对一个对象没有拥有权却想要引用它,你必须retain它,并在不需要的时候手动释放它,相应的方法。
例如:创建了一个CGColorspace对象,则使用函数CGColorSpaceRetain和CGColorSpaceRelease来retain和release对象。同样,可以使用Core Foundation的CFRetain和CFRelease,但是注意不能传递NULL值给这些函数。
图形上下文(Graphics Contexts)
获取上下文的方式有:Quartz提供的创建函数、Mac OS X框架或IOS的UIKit框架提供的函数。Quartz提供了多种Graphics Context的创建函数,包括bitmap和PDF。
iOS,在View Graphics Context绘制
在iOS应用中,视图显示在屏幕上及它的内容需要更新时会调用被调用drawRect:
方法。你只需要实现drawRect:
方法,并在其中获取上下文(视图对象会配置一个上下文给你),绘制你想要的图像。
调用UIGraphicsGetCurrentContext
获取当前的上下文。
样例代码
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBFillColor(context, 1, 0, 0.5, 1); CGContextFillRect(context, CGRectMake (0, 0, 250, 150));
在Mac OS X中创建一个窗口Graphics Context
内容不多,关于Mac开发,不多占用篇幅了,见参考文档吧。
创建 PDF Graphics Context
Quartz2D API 提供了两个函数来创建 PDF Graphics Context。
-
CGPDFContextCreateWithURL。当你需要用 Core Foundation URL 指定 PDF 输出的位置时使用该函数。
-
CGPDFContextCreate 当需要将pdf输出发送给数据用户时使用该方法。
创建 Bitmap Graphics Context
一个位图Graphics Context接受一个指向内存缓存(包含位图存储空间)的指针,当我们绘制一个位图Graphics Context时,该缓存被更新。在释放Graphics Context后,我们将得到一个我们指定像素格式的全新的位图。
注:位图Graphics Context有时用于后台绘制。CGLayer对象优化了后台绘制,因为Quartz在显卡上缓存了层。
UIGraphicsBeginImageContext([UIScreen mainScreen].bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 1, 0.5, 0.5, 1);
CGContextFillRect(context, CGRectMake (0, 0, 100, 150));
->接下来,获取图片
UIImage *imageOne = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
<->或者
CGImageRef myImage = CGBitmapContextCreateImage(context);
CGContextDrawImage(context, CGRectMake(0, 0, 300, 300), myImage);
char *bitmapData = CGBitmapContextGetData(context);
CGContextRelease (context);
if (bitmapData) free(bitmapData);
CGImageRelease(myImage);
支持的像素格式
位图 Graphics Context支持的像素格式,相关的颜色空间及像素格式支持的Mac OS X最早版本。像素格式用bpp(每像素的位数)和bpc(每个组件的位数)来表示,详细格式表格。
iOS 共支持 8 种像素格式。
- Null 8 bpp, 8 bpc, kCGImageAlphaOnly
- Gray 8 bpp, 8 bpc, kCGImageAlphaNone
- Gray 8 bpp, 8 bpc, kCGImageAlphaOnly
- RGB 16 bpp, 5 bpc, kCGImageAlphaNoneSkipFirst
- RGB 32 bpp, 8 bpc, kCGImageAlphaNoneSkipFirst
- RGB 32 bpp, 8 bpc, kCGImageAlphaNoneSkipLast
- RGB 32 bpp, 8 bpc, kCGImageAlphaPremultipliedFirst
- RGB 32 bpp, 8 bpc, kCGImageAlphaPremultipliedLast
反锯齿
位图 Graphics Context支持反锯齿,当位图的分辩率明显低于人眼的分辩率时就会产生锯齿。使形状看起来更平滑。
我们可以通过调用CGContextSetShouldAntialias来关闭位图Graphics Context的反锯齿效果。反锯齿设置是图形状态的一部分。
可以调用函数CGContextSetAllowsAntialiasing来控制一个特定Graphics Context是否支持反锯齿;
CGContextRef context1 =UIGraphicsGetCurrentContext();
CGContextSetShouldAntialias(context1, YES);
CGContextSetAllowsAntialiasing(context1, YES);
颜色与颜色空间
什么是颜色与颜色空间
Quartz中的颜色是用一组值来表示。而颜色空间用于解析这些颜色信息。例如,下表列出了在全亮度下蓝色值在不同颜色空间下的值。如果不知道颜色空间及颜色空间所能接受的值,我们没有办法知道一组值所表示的颜色。
Values(值) | Color Space(颜色空间) | Components(组件) |
---|---|---|
240 degrees 100% 100% | HSB | Hue, saturation, britness |
0, 0, 1 | RGB | Red, green, blue |
1, 1, 0, 0 | CMYK | Cyan ,magenta, yellow, black |
1, 0, 0 | BGR | Blue, green, red |
alpha值(透明度)
使用 CGContextSetAlpha(context, 0.2)
设置透明度。
使用 CGContextClearRect 清除上下文的 alpha
通道。
创建设备依赖颜色空间
创建设备依赖灰度颜色空间。
CGColorSpaceCreateDeviceGray()
创建设备依赖RGB颜色空间。
CGColorSpaceCreateDeviceRGB()
创建设备依赖CMYK颜色空间。
CGColorSpaceCreateDeviceCMYK()
设置颜色空间。
CGContextSetFillColorSpace(context, colorSpace)
或 CGContextSetStrokeColorSpace(context, colorSpace)
样例代码:
//Device RGB. 设置设备依赖RGB颜色空间并设置颜色值。
CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);
CGContextSetRGBFillColor(context, 1, 0, 0, 1);
//Device CMYK. 设置设备依赖CMYK颜色空间并设置颜色值。
CGContextSetCMYKStrokeColor(context, 1, 0, 0, 0, 1);
CGContextSetCMYKFillColor(context, 1, 0, 0, 0, 1);
//Device Gray.设置设备依赖灰度颜色空间并设置颜色值。
CGContextSetGrayStrokeColor(context, 0.5, 1);
CGContextSetGrayFillColor(context, 0.5, 1);
//使用 CGColor 设置颜色值并使用 CGColor 指定的颜色空间。
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGFloat colors[4] = {1.0, 0.0, 0.0, 1.0};
CGColorRef color = CGColorCreate(colorSpace, colors);
CGContextSetStrokeColorWithColor(context, color);
CGContextSetFillColorWithColor(context, color);
调用如下函数来便捷的设置颜色值并使用正在使用的颜色空间。
CGContextSetStrokeColor(context, colors);
CGContextSetFillColor(context, colors);
设置和创建颜色
通过如下函数设置和创建颜色。
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor));
设置再现意图(Rending Intent)
每个设备都有固定的可复制的颜色范围(gamut),这是设备的物理性质决定的。当图像从一个颜色空间向另一个颜色空间转换时,有些源设备颜色空间中呈现的颜色,不能在目标设备颜色空间中复制出来,这些不能复制的颜色叫色域外(out-of-gamut)颜色。比如 RGB 颜色空间比 CMYK 的颜色空间要大,有些在显示器上能显示的颜色不能在打印机上同样打印出来。因为我们不能在目标设备颜色空间中复制出色域外颜色,我们必须用一些其他颜色来替代他们。颜色空间转换时颜色替换调整的规则就是再现意图。你也可以查阅这里关于“再现意图”(Rendering intent 和 Understanding rendering intents: Which one and why?
再现意图用于指定如何将源颜色空间的颜色映射到图形上下文的目标颜色空间的颜色范围内。
如果不显式的指定再现意图,Quartz 使用“相对色度再现意图”应用于所有绘制(不包含位图图像)。
对于位图图像,Quartz默认使用“感知再现意图”。
调用 CGContextSetRenderingIntent(context, kCGRenderingIntentDefault)
来设置再现意图。
再现意图共有以下 5 种。
typedef CF_ENUM (int32_t, CGColorRenderingIntent) {
kCGRenderingIntentDefault,//默认
kCGRenderingIntentAbsoluteColorimetric,//绝对色度再现意图
kCGRenderingIntentRelativeColorimetric,//相对色度再现意图
kCGRenderingIntentPerceptual,//感知再现意图
kCGRenderingIntentSaturation//饱和度再现意图
};
详细查看官文文档 。
这是CoreGraphic第一篇,基础概念篇,接下来会进入实战阶段,如果你感兴趣,来个❤和关注。我们下期见。