在应用CGContext时,因为Quartz 2D与UIKit坐标不统一,所以须要对context进行再一次的变动,达到预期的成果。
1. 不同坐标原点介绍
在Quartz 2D中,坐标原点在画布的左下角,而UIKit中,与屏幕坐标统一,以左上角为坐标原点。
如果以(0,0)点为原点绘制F,那么在不同的坐标系就会取得如下的后果。
2. Quartz 2D与UIKit坐标系转化
2.1 UIImage绘制
在iOS的UI开发中,以UIImage为例,绘制一张图片,设置image的frame为(0, 0, 320, 320),会失去上图右的画面。
如果应用如下代码读取Context的transform,能够看到这个transform并不是单位矩阵。
*CGRect frame = CGRectMake(0.0, 0.0, 720, 1280);
UIGraphicsBeginImageContext(frame.size);CGContextRef context = UIGraphicsGetCurrentContext();CGAffineTransform contextTransform = CGContextGetCTM(context);;*
这里的transform设置会使Quartz 2D与UIKit的坐标原点重合,也是不便了UIKit中控件的绘制,坐标系变动能够参考下图。
这也是为什么如果间接在获取到的context上调用CGContextDrawImage时会失去一个反转的图像的起因。
但如果应用UIImage的drawInRect办法,文档是这么写的:
*Instance Method
draw(in:)
Draws the entire image in the specified rectangle, scaling it as necessary to fit.
Declaration
func draw(in rect: CGRect)
Parameters
rect
The rectangle (in the coordinate system of the graphics context) in which to draw the image.
Discussion
This method draws the entire image in the current graphics context, respecting the image’s orientation setting. In the default coordinate system, images are situated down and to the right of the origin of the specified rectangle. This method respects any transforms applied to the current graphics context, however.
This method draws the image at full opacity using the CGBlendMode.normal blend mode.*
也就是说,UIImage绘制时应用的坐标还是UIKit的外部坐标,所以并不需要对坐标系做任何变动,就能够绘制出与rect地位雷同的图片了,当然这个办法也会依据图片的朝向绘制。
2.2 CGContextDrawImage绘制
在扭转context的transform时,实际上在变动的其实是坐标系自身。
而调用绘制办法时,应用的还是坐标系外部坐标,所以当咱们想基于获取到的context绘制一个如UIKit显示的图片,咱们还须要对绘制前的坐标系做调整。
//Y轴翻转
CGContextScaleCTM(context, 1, -1);
//须要图片原点与左上角对齐,还需Y轴向下平移图片高度
CGContextTranslateCTM(context, 0, -imageSize.height);
//绘制图片
CGContextDrawImage(context, frame, image.CGImage);
3 transform锚点变动
比方图片编辑页面,咱们常常能碰到应用手势对图片进行缩放旋转位移等变动,之后生成一张新的图片。
依据不同的手势回调,咱们能够批改view.transform,使得界面上的view产生与手势相应的变动。
在这里,UIKit为了不便咱们批改UI界面,view的transform是以view的center为锚点的。
UIView的transform外面的形容是应用center来批改position。
Use this property to scale or rotate the view's frame rectangle within its superview's coordinate system. (To change the position of the view, modify the center property instead.) The default value of this property is CGAffineTransformIdentity.
而很多其余的办法在调用时,transform都须要以左上角为锚点,所以这里有须要做一次转化,锚点影响如下图。
在UI界面的批改中,咱们能够应用缩放和旋转手势的回调值间接批改view的transform,以及位移的回调来批改center,便能够达到咱们预期的成果。但这个transform无奈应用在context的绘制上,因为坐标系的变动,是以原点为锚点来做的。
所以针对context现有坐标系的地位,锚点在左上角,须要进行一次transform的批改。
依据上图也能够看出,锚点只会对地位信息产生影响,并不会扭转缩放和旋转。
UIImage *image; //初始化图片
UIView *view;//利用变动的view,view的size跟image要统一保障缩放比例是对的。
*CGAffineTransform transform = view.transform;
CGSize imageSize = image.size;transform.tx = view.center.x;transform.ty = view.center.y;transform = CGAffineTransformTranslate(transform, -imageSize.width * 0.5, -imageSize.height * 0.5);*
其中tx,ty为锚点在坐标系的地位
以后的锚点在视图的中心点,咱们须要扭转到视图的左上角,这样就能够和坐标系原点重合。其中(imageSize.width 0.5, imageSize.height 0.5)为锚点在图片中的地位,此时transform为锚点在视图左上角时的变动矩阵。
4. 组合Transform
在CGContext上想得到上图两头的后果,不仅须要利用放大1/2和旋转45度的变动,还须要调整。
之前说过CGContext利用旋转是利用在坐标系上,跟视图利用旋转的形式是本身坐标系是统一的。所以当间接获取到的CGContext,优化后的坐标系也是左上角为原点时,能够间接再CGContext上利用咱们计算出的transform。
之后还是因为坐标系绘制是以本身坐标系计算,再做一轮坐标系的翻转和位移来失去最初的后果,相似下图的操作。
这里须要留神,每一次新的变动都是在之前变动的根底上,所以无论是view还是对context的transform做批改都是有程序的,这一点与矩阵乘法统一,程序会影响后果。