標籤:blog http io ar color os 使用 sp for
Quartz是Mac OS X的Darwin核心之上的繪圖層,有時候也認為是CoreGraphics。共有兩種部分組成Quartz:
Quartz Compositor,合成視窗系統,管理和合成幕後視窗影像來建立Mac OS X使用者介面。
Quartz 2D,是iOS和Mac OS X環境下的二維繪圖引擎。
涉及內容包括:基於路徑的繪圖,透明度繪圖,遮蓋,陰影,透明層,顏色管理,防鋸齒渲染,產生PDF,以及PDF中繼資料相關處理。
14.2 繪製基本幾何圖形
視圖繪製
在iOS上,所有的繪製,無論是否採用OpenGL、Quartz、UIKit、或者 Core Animation—都發生在UIView對象的地區內。
視圖定義繪製發生的螢幕地區。如果您使用系統提供的視圖,繪製工作會自動得到處理。然而,如果您定義自己的定製視圖,則必須自行提供繪製代碼。
對於使用OpenGL進行繪製的應用程式,一旦建立了渲染表面,就必須使用OpenGL指定的繪製模型。
視圖繪製周期
描繪系統會調用UIView對象的drawRect:方法,並向它傳入一個包含需要重畫的視圖地區的矩形。觸發視圖更新的動作有如下幾種:
對遮擋您的視圖的其它視圖進行移動或刪除操作。
將視圖的hidden屬性聲明設定為NO,使其從隱藏狀態變為可見。
將視圖滾出螢幕,然後再重新回到螢幕上。
顯式調用視圖的setNeedsDisplay或者setNeedsDisplayInRect:方法。
setNeedsDisplay是更新整個視圖,
setNeedsDisplayInRect是更新視圖的部分地區。
視圖繪製執行個體FirstQuartz2D
自訂視圖的h檔案
@interface MyView : UIView { }@end
自訂視圖的m檔案
@implementation MyView- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextMoveToPoint (context, 75, 10); CGContextAddLineToPoint (context, 10, 150); CGContextAddLineToPoint (context, 160, 150); // Closing the path connects the current point to the start of the current path. CGContextClosePath(context); // And stroke the path [[UIColor blackColor] setStroke]; //CGContextStrokePath(context); [[UIColor redColor] setFill]; CGContextDrawPath(context, kCGPathFillStroke); //kCGPathFillStroke,kCGPathFill,kCGPathStroke }@end
CGContextRef context = UIGraphicsGetCurrentContext();可以獲得圖形上下文。
CGContextMoveToPoint、CGContextAddLineToPoint兩個函數是構建描繪路徑。
CGContextClosePath(context);函數是閉合描繪路徑。
CGContextStrokePath函數是為閉合路徑描邊。
[[UIColor blackColor] setStroke]設定描邊的顏色。
[[UIColor redColor] setFill]設定要填充顏色。
CGContextDrawPath(context, kCGPathFillStroke);設定描繪路徑方式。常用的還有:
kCGPathFill和kCGPathStroke
圖形上下文
在調用您提供的drawRect:方法之前,視圖對象會自動設定其繪製環境,使您的代碼可以立即進行繪製。作為這些
配置的一部分,UIView對象會為當前繪製環境建立一個圖形上下文(對應於CGContextRef封裝類型)。
該圖形上下文包含繪製系統執行後續繪製命令所需要的資訊,定義了各種基本的繪製屬性,比如繪製使用的顏色、
裁剪地區、線的寬度及風格資訊、字型資訊、合成選項、以及幾個其它資訊。
繪製路徑
路徑用於描述由一序列線和Bézier曲線構成的2D幾何形狀。Core Graphics中也有一些用於建立簡單路徑(比如矩形和橢圓形)的便利函數。對於更為複雜的路徑,必須用Core Graphics架構提供的函數自行建立。
Bézier曲線是法國數學家“貝塞爾”在工作中發現,任何一條曲線都可以通過與它相切的控制線兩端的點的位置來定義。
Bézier曲線
Bézier曲線執行個體BezierCurve
- (void)drawRect:(CGRect)rect { CGContextRef cgContext = UIGraphicsGetCurrentContext(); //CGContextBeginPath(cgContext); CGContextMoveToPoint(cgContext, 333, 0); CGContextAddCurveToPoint(cgContext, 333, 0, 332, 26, 330, 26); CGContextAddCurveToPoint(cgContext, 330, 26, 299, 20, 299, 17); CGContextAddLineToPoint(cgContext, 296, 17); CGContextAddCurveToPoint(cgContext, 296, 17, 296, 19, 291, 19); CGContextAddLineToPoint(cgContext, 250, 19); CGContextAddCurveToPoint(cgContext, 250, 19, 241, 24, 238, 19); CGContextAddCurveToPoint(cgContext, 236, 20, 234, 24, 227, 24); CGContextAddCurveToPoint(cgContext, 220, 24, 217, 19, 216, 19); CGContextAddCurveToPoint(cgContext, 214, 20, 211, 22, 207, 20); CGContextAddCurveToPoint(cgContext, 207, 20, 187, 20, 182, 21); CGContextAddLineToPoint(cgContext, 100, 45); CGContextAddLineToPoint(cgContext, 97, 46); CGContextAddCurveToPoint(cgContext, 97, 46, 86, 71, 64, 72); CGContextAddCurveToPoint(cgContext, 42, 74, 26, 56, 23, 48); CGContextAddLineToPoint(cgContext, 9, 47); CGContextAddCurveToPoint(cgContext, 9, 47, 0, 31, 0, 0); CGContextStrokePath(cgContext);}
14.3 繪製映像和文本
UIImages的-drawRect:方法繪製映像:
- [UIImage drawAtPoint:(CGPoint)point]
- [UIImage drawInRect:(CGRect)rect]
- [UIImage drawAsPatternInRect:(CGRect)rect]
NSString的-drawRect:方法繪製文本:
- [NSString drawAtPoint:(CGPoint)point withFont:(UIFont *)font]
執行個體DrawImage
#import "MyView.h"@implementation MyView- (void)drawRect:(CGRect)rect { NSString* imagePath = [[NSBundle mainBundle] pathForResource:@"dog" ofType:@"png"]; UIImage* myImageObj = [[UIImage alloc] initWithContentsOfFile:imagePath]; //[myImageObj drawAtPoint:CGPointMake(0, 0)]; [myImageObj drawInRect:CGRectMake(0, 0, 320, 480)]; NSString *s = @"我的小狗"; [s drawAtPoint:CGPointMake(100, 0) withFont:[UIFont systemFontOfSize:34.0]];}@end
寫字執行個體Draw
Dot對象
//--h@interface Dot : NSObject { CGFloat x; CGFloat y;}@property(assign) CGFloat x;@property(assign) CGFloat y;@end//--m#import "Dot.h"@implementation Dot@synthesize x;@synthesize y;@end
DrawView.h
#import <UIKit/UIKit.h>@interface DrawView : UIView { NSMutableArray *dots;}@property(nonatomic, retain) NSMutableArray *dots;@end
DrawView.m
#import "DrawView.h"#import "Dot.h"@implementation DrawView@synthesize dots;- (NSMutableArray *)dots { if(nil == dots) { self.dots = [NSMutableArray array]; } return dots;}//START:code.DrawView.drawRect- (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(ctx, [[UIColor blueColor] CGColor]); for(Dot *dot in self.dots) { CGContextAddArc(ctx, dot.x, dot.y, 5.0f, 0.0f, 2.0f * M_PI, YES); CGContextFillPath(ctx); } }//END:code.DrawView.drawRect- (void)dealloc { self.dots = nil; [super dealloc];}
drawRect方法中將dots集合中的Dot對象取出,一個一個在螢幕上面畫出來。
CGContextAddArc(ctx, dot.x, dot.y, 5.0f, 0.0f, 2.0f * M_PI, YES);函數是繪製弧形。
CGContextFillPath(ctx);填充路徑。
//START:code.DrawView.touchesBegan- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:self]; Dot *dot = [[[Dot alloc] init] autorelease]; dot.x = location.x; dot.y = location.y; //[self.dots removeAllObjects]; [self.dots addObject:dot]; [self setNeedsDisplay];}//END:code.DrawView.touchesBegan//START:code.DrawView.touchesMoved- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:self]; Dot *dot = [[[Dot alloc] init] autorelease]; dot.x = location.x; dot.y = location.y; [self.dots addObject:dot]; [self setNeedsDisplay];}//END:code.DrawView.touchesMoved
14.4 座標
Quartz座標
Quartz技術最開始為Mac OS X系統設計的圖形技術,它的座標原點位於左下角。
UIKit座標
UIKit座標與Quartz不同,原點位於右上方。在iOS中的UIView等控制項都是基於此座標,由於在UIView使用了Quartz座標有時候需要轉換。
座標變換執行個體
MyView.m檔案
#import "MyView.h"@implementation MyView- (void)drawRect:(CGRect)rect { NSString *path = [[NSBundle mainBundle] pathForResource:@"cat" ofType:@"jpg"]; UIImage *img = [UIImage imageWithContentsOfFile:path]; CGImageRef image = img.CGImage; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); CGRect touchRect = CGRectMake(0, 0, img.size.width, img.size.height); CGContextDrawImage(context, touchRect, image); CGContextRestoreGState(context);}@end
CGContextSaveGState是將當前圖形狀態要入到圖形堆棧。
CGContextDrawImage(context, touchRect, image)在上下文中繪製圖形。 CGContextRestoreGState回複當前圖形狀態。
14.5 變換
運用變換
變換(transformation)修改了圖形上下文中繪製圖形的方式。可以通過移動、旋轉或縮放實現變換。
Quartz提供了多種形式的變換,其中主要:CTM(當前變換矩陣)變換和仿射(affine)變換。
CTM(current transformation matrix)變換,這種變換比較簡單,函數有:
CGContextRotateCTM,旋轉座標
CGContextScaleCTM,縮放座標
CGContextTranslateCTM,移動原點
移動變換
CGContextTranslateCTM (myContext, 100, 50)
從對象角度沿著x軸正向移動100單位,沿著y軸正向移動50單位。
旋轉變換
static inline double radians (double degrees) {return degrees * M_PI/180;}
CGContextRotateCTM (myContext, radians(–45.));
從對象角度:
在Quartz座標下正數為逆時針旋轉,負數為順時針旋轉。
在UIKit座標下正數為順時針旋轉,負數為逆時針旋轉。
縮放變換
CGContextScaleCTM (myContext, .5, .75);
從對象角度:所有x座標縮小0.5,所有y座標縮小0.75。
修改MyView.m檔案
#import "MyView.h"@implementation MyView- (void)drawRect:(CGRect)rect { NSString *path = [[NSBundle mainBundle] pathForResource:@"cat" ofType:@"jpg"]; UIImage *img = [UIImage imageWithContentsOfFile:path]; CGImageRef image = img.CGImage; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); CGContextRotateCTM(context, M_PI); CGContextTranslateCTM(context, -img.size.width, -img.size.height); CGRect touchRect = CGRectMake(0, 0, img.size.width, img.size.height); CGContextDrawImage(context, touchRect, image); CGContextRestoreGState(context);}@end
仿射(affine)變換
仿射(affine)變換也是一種直角座標變換,重
用變換,經過多次變換(多次的矩陣相乘),
每一種變換都可以用矩陣表示,通過多次矩陣
相乘得到最後結果。仿射變換函數:
CGAffineMakeRotation,建立旋轉矩陣仿射對象
CGAffineMakeScale,建立縮放矩陣仿射對象
CGAffineMakeTranslation,建立移動矩陣仿射對象
CGAffineTransformRotate,旋轉矩陣仿射對象
CGAffineTransformScale,縮放矩陣仿射對象
CGAffineTransformTranslate,移動矩陣仿射對象
CGContextConcatCTM,串連到CTM變換
使用仿射變換MyView.m
#import "MyView.h"@implementation MyView- (void)drawRect:(CGRect)rect { NSString *path = [[NSBundle mainBundle] pathForResource:@"cat" ofType:@"jpg"]; UIImage *img = [UIImage imageWithContentsOfFile:path]; CGImageRef image = img.CGImage; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); CGAffineTransform myAffine = CGAffineTransformMakeRotation(M_PI); myAffine = CGAffineTransformTranslate(myAffine, -img.size.width, -img.size.height); CGContextConcatCTM(context, myAffine); CGContextRotateCTM(context, M_PI); CGContextTranslateCTM(context, -img.size.width, -img.size.height); CGRect touchRect = CGRectMake(0, 0, img.size.width, img.size.height); CGContextDrawImage(context, touchRect, image); CGContextRestoreGState(context);}@end
14.6 映像拾取器
映像拾取器(Image Picker)是可以協助你從圖片庫中選取圖片,也可以捕獲照相機圖片。
PhotoViewViewController.h
//START:code.PhotoViewController.h@interface PhotoViewViewController : UIViewController<UIImagePickerControllerDelegate> { UIImageView *imageView; UIImagePickerController *imagePicker;}@property(nonatomic, retain) IBOutlet UIImageView *imageView;@property(nonatomic, retain) IBOutlet UIImagePickerController *imagePicker;@end//END:code.PhotoViewController.h
需要實現UIImagePickerControllerDelegate協議。
需要定義UIImagePickerController控制器成員變數。
PhotoViewViewController.m
#import "PhotoViewViewController.h"@implementation PhotoViewViewController@synthesize imageView;@synthesize imagePicker;//START:code.PhotoViewController.touchesEnded:withEvent:- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { if([[touches anyObject] tapCount] > 1) { // bring up image grabber if([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) { self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera; } else { self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; } //self.imagePicker.allowsImageEditing = YES; //iOS 3之前 self.imagePicker.allowsEditing = YES; [self presentModalViewController:self.imagePicker animated:YES]; }}//END:code.PhotoViewController.touchesEnded:withEvent:
映像選取器的sourceType屬性有:
UIImagePickerControllerSourceTypePhotoLibrary,圖片來源於“相簿”
UIImagePickerControllerSourceTypeCamera,來源於相機
UIImagePickerControllerSourceTypeSavedPhotosAlbum,來源於“相機菲林”。
PhotoViewViewController.m
//START:code.PhotoViewController.didFinish- (void)imagePickerController:(UIImagePickerController *)pickerdidFinishPickingMediaWithInfo:(NSDictionary *)info { imageView.image = [info objectForKey:UIImagePickerControllerEditedImage]; [self dismissModalViewControllerAnimated:YES]; }//END:code.PhotoViewController.didFinish//START:code.PhotoViewController.didCancel- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { [self.imagePicker dismissModalViewControllerAnimated:YES];}//END:code.PhotoViewController.didCancel- (void)dealloc { self.imageView = nil; self.imagePicker = nil; [super dealloc];}
imagePickerController:didFinishPickingMediaWithInfo:委託實現方法,當選擇完成時候調用。
imageView.image = [info objectForKey:UIImagePickerControllerEditedImage];語句可以從圖片拾取器中獲得一個Image對象。
imagePickerControllerDidCancel:是委託實現方法當點擊取消時候調用。
繪圖詳解(轉摘)