參考:
[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)
展開後得:
聯合操作,先旋轉再平移
展開後