关于iOS图形上下文环境(CGContext)的操作

CGContext是Quartz2D的描画环境,包括了描画参数以及将图渲染到目标页面上需要的所有设备相关的信息,目标页面可能是应用窗口,位图,PDF文档或者打印机。
每个图形上下文环境环境包含一个图形状态栈。

一,基本知识

(一),Quartz 2D 坐标系统
    坐标系统定义是被绘制到Page上的对象的位置及大小范围。我们在用户空间坐标系统(user-space coordination system,简称用户空间)中指定图形的位置及大小。坐标值是用浮点数来定义的。
    Quartz通过使用当前转换矩阵(current transformation matrix, CTM)将一个独立的坐标系统(user space)映射到输出设备的坐标系统(device space),以此来解决设备依赖问题。 CTM是一种特殊类型的矩阵(affine transform, 仿射矩阵),通过平移(translation)、旋转(rotation)、缩放(scale)操作将点从一个坐标空间映射到另外一个坐标空间。
CTM还有另外一个目的:允许你通过转换来决定对象如何被绘制。例如,为了绘制一个旋转了45度的盒子,我们可以在绘制盒子之前旋转Page的坐标系统。Quartz使用旋转过的坐标系统来将盒子绘制到输出设备中。
    用户空间的点用坐标对(x, y)来表示,(0, 0)表示坐标原点。Quartz中默认的坐标系统是:沿着x轴从左到右坐标值逐渐增大;沿着y轴从下到上坐标值逐渐增大。
    有一些技术在设置它们的graphics context时使用了不同于Quartz的默认坐标系统。相对于Quartz来说,这些坐标系统是修改的坐标系统(modified coordinate system),当在这些坐标系统中显示Quartz绘制的图形时,必须进行转换。最常见的一种修改的坐标系统是原点位于左上角,而沿着y轴从上到下坐标值逐渐增大。我们可以在如下一些地方见到这种坐标系统:
1,在Mac OS X中,重写过isFlipped方法以返回yes的NSView类的子类
2,在IOS中,由UIView返回的绘图上下文
3,在IOS中,通过调用UIGraphicsBeginImageContextWithOptions函数返回的绘图上下文
    如果应用程序想以相同的绘制程序在一个UIView对象和PDF Graphics Context上进行绘制,需要做一个变换以使PDF Graphics Context使用与UIView相同的坐标系。要达到这一目的,只需要对PDF的上下文的原点做一个平移(移到左上角)和用-1对y坐标值进行缩放。图一显示了这种变换操作:
图一:CG坐标系跟UI坐标系
关于iOS图形上下文环境(CGContext)的操作_第1张图片
参考:http://www.cocoachina.com/ios/20111111/3486.html

图二:层的position和anchorPoint
关于iOS图形上下文环境(CGContext)的操作_第2张图片

position(30, 35)  anchorPoint(0.5, 0.5) position(50, 60)  anchorPoint(0,0)

二,接口函数举例

创建一个基于位图的图形环境作为当前环境:等价于(UIGraphicsBeginImageContextWithOptions(size, false, 1))

func UIGraphicsBeginImageContext(_ size: CGSize)

通过参数创建给予位图的图形环境:
opaque:是否不透明
scale:缩放比例

func UIGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat)

关键是缩放因子scale的指定,将scale指定为0,意味着将其设定为设备屏幕的缩放因子

保存除path之外的图形元素:

func saveGState()

在上下文环境中改变用户坐标系的原点:

func translateBy(x tx: CGFloat, y ty: CGFloat)

用指定矩阵对用户坐标系进行变换 CTMnew = transform * CTMcontext:

func concatenate(_ transform: CGAffineTransform)

三,使用举例

1,如果通过CGContext的draw(_:in:byTiling:)绘制了图片或者PDF的内容后,图像会变成倒像,需要做如下变换得到与UI坐标一样的图形。如果仅仅使用CALayer的render(in:)方法在context中渲染后通过UIGraphicsGetImageFromCurrentImageContext得到图片的话,则不需要变换。这意味着CALayer的render方法已经帮我们做了变换处理。

// 顺时针旋转180度
context.rotate(by: CGFloat(M_PI))
// 沿X轴对称处理
context.scaleBy(x: -1, y: 1)
// 把偏移掉的位置调整回来
context.translateBy(x: 0, y: CGFloat(-iv.image!.size.height))

上面三步操作用图形示意如下。注意旋转的是坐标系而不是图片本身。
关于iOS图形上下文环境(CGContext)的操作_第3张图片
2,在对图形做变换时,为了保证变换后图形的中心位置不变,需要做以下处理:

// 将CG坐标原点从layer的左下角移动至layer的中心
context.translateBy(x: self.layer.position.x, y: self.layer.position.y)
// 进行移动、旋转、反转等变换
context.concatenate(self.transform)
// 将CG坐标原点移回至layer左下角,变换完成
context.translateBy(x: -self.frame.origin.x - self.bounds.size.width * self.layer.anchorPoint.x, y: -self.frame.origin.y - self.bounds.size.height * self.layer.anchorPoint.y)

你可能感兴趣的:(iOS)