参考:
[1]http://developer.apple.com/library/ios/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_affine/dq_affine.html#//apple_ref/doc/uid/TP30001066-CH204-CJBECIAD
[2]http://www.cnblogs.com/delonchen/archive/2011/08/03/iostransform.html
Quartz 2D 绘制模型定义了两种独立的坐标空间:用户空间(用于表现文档页)和设备空间(用于表现设备的本地分辨率)。用户坐标空间用浮点数表示坐标,与设备空间的像素分辨率没有关系。当我们需要一个点或者显示文档时, Quartz会将用户空间坐标系统映射到设备空间坐标系统。因此,我们不需要重写应用程序或添加额外的代码来调整应用程序的输出以适应不同的设备。
我们可以通过操作 当前变换矩阵CTM(current transformation matrix)来修改默认的用户空间。在创建图形上下文后,CTM是单位矩阵,我们可以使用 Quartz的变换函数来修改CTM,从而修改用户空间中的绘制操作。
当前变换矩阵(current Transform Martrix,CTM)一个重要功能是负责将图形从用户空间映射到系统坐标系,另一个重要功能是方便开发者对图形进行移动,缩放以及旋转变换。CTM将绘图从用户空间映射到设备空间当图形环境刚刚创建时,CTM初始化为一个单位矩阵,对CTM进行平移变换应当调用CGContextTranslateCTM函数,进行旋转变换应当调用CGContextRotateCTM函数,进行缩放变换应当调用CGContextScaleCTM函数。
Quartz 2D的坐标系,原点在左下角,x方向向右为正方向,y方向向上为正方向。
UIKit坐标系,原点在左上角,x方向向右为正方向,y方向向下为正方向。
Quartz 2D 坐标系和UIKit坐标系不同,互为镜像,因此如果在Quartz 2D中绘制图片,在UIKit中的UIview中显示就会出现倒立的情况。Quartz 2D中有两种方式来创建图片Context,1.通过CGBitmapContextCreate 创建Context,然后在画布上绘制图片 2.通过 UIGraphicsBeginImageContext ,系统自动创建Context。其中,通过方法一创建context,然后生成UIImage时,系统为我们自动做了坐标转换。
方法一,绘图
UIImage* imageSrc = [UIImage imageNamed:@"car.png"]; CGColorSpaceRef colorRef = CGColorSpaceCreateDeviceRGB(); CGContextRef contextRef = CGBitmapContextCreate(nil, imageSrc.size.width, imageSrc.size.height, 8, imageSrc.size.width*4, colorRef, kCGImageAlphaPremultipliedFirst); CGContextSetFillColorWithColor(contextRef, [UIColor redColor].CGColor); CGContextFillRect(contextRef, CGRectMake(0, 0, imageSrc.size.width, imageSrc.size.height)); CGContextDrawImage(contextRef, CGRectMake(0, 0, imageSrc.size.width, imageSrc.size.height), imageSrc.CGImage); CGImageRef imageRef = CGBitmapContextCreateImage(contextRef); UIImage* imageDst = [UIImage imageWithCGImage:imageRef scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]; CGImageRelease(imageRef); CGContextRelease(contextRef); CGColorSpaceRelease(colorRef); return imageDst;
方法二,绘图
UIImage* imageSrc = [UIImage imageNamed:@"car.png"]; UIGraphicsBeginImageContext(imageSrc.size); CGContextRef contextRef = UIGraphicsGetCurrentContext(); CGContextDrawImage(contextRef, CGRectMake(0, 0, imageSrc.size.width, imageSrc.size.height), imageSrc.CGImage); UIImage* imageDst = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return imageDst;
因此如果采用方法二绘制图片,会出现图片倒立的情况,那么这时需要 应用当前变换矩阵(CTM)对进行变换实现正确显示。通过如下代码可以将方法二的绘制显示正确,
CGContextTranslateCTM就是将坐标原点往上偏移imageSrc.size.height,CGContextScaleCTM(contextRef,1,-1)将y坐标值取反,x保持不变。这样就通过变换QuartZ 2d坐标系,实现UIKit的坐标系。
CGContextTranslateCTM(contextRef, 0, imageSrc.size.height); CGContextScaleCTM(contextRef, 1, -1);
1.2 仿射变换
已知坐标点A,变换后新坐标系中坐标为B ,则有:
B = AM
A为1*3的矩阵[x,y,1]
B为 1* 3的矩阵[x’,y’,1]
M为3*3仿射矩阵
所以AM=B可以写成:
展开后得到:
以下是常用的变换矩阵:
单位矩阵:
展开后得:
平移矩阵:
CG_EXTERN void CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)
展开后得:
缩放矩阵:
CG_EXTERN void CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy)
展开后得:
旋转矩阵:
CG_EXTERN void CGContextRotateCTM(CGContextRef c, CGFloat angle)
展开后得:
联合操作,先旋转再平移
展开后