IOS之Quartz


14.1 Quartz概述

14.2 繪制基本幾何圖形

14.3 繪制圖像和文本

14.4 坐標

14.5 變換

14.6 圖像拾取器

 

14.1 Quartz概述

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

wps_clip_image-14312

自定義視圖的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曲線

wps_clip_image-26605

Bézier曲線實例BezierCurve

wps_clip_image-32456

- (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

wps_clip_image-11683

#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

wps_clip_image-23850

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系統設計的圖形技術,它的坐標原點位於左下角。

wps_clip_image-1616

UIKit坐標

UIKit坐標與Quartz不同,原點位於右上角。在iOS中的UIView等控件都是基於此坐標,由於在UIView使用了Quartz坐標有時候需要轉換。

wps_clip_image-5807

坐標變換實例

wps_clip_image-29340

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)

wps_clip_image-23595

從對象角度沿着x軸正向移動100單位,沿着y軸正向移動50單位。

旋轉變換

static inline double radians (double degrees) {return degrees * M_PI/180;}

CGContextRotateCTM (myContext, radians(–45.));

wps_clip_image-9368

從對象角度:

在Quartz坐標下正數為逆時針旋轉,負數為順時針旋轉。

在UIKit坐標下正數為順時針旋轉,負數為逆時針旋轉。

縮放變換

CGContextScaleCTM (myContext, .5, .75);

wps_clip_image-14003

從對象角度:所有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)是可以幫助你從圖片庫中選取圖片,也可以捕獲照相機圖片。

wps_clip_image-22106

wps_clip_image-8654

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 *)picker
didFinishPickingMediaWithInfo:(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:是委托實現方法當點擊取消時候調用。

注:
1 本教程是基於關東升老師的教程
2 基於黑蘋果10.6.8和xcode4.2
3 本人初學,有什么不對的望指教
4 教程會隨着本人學習,持續更新
5 教程是本人從word筆記中拷貝出來了,所以格式請見諒


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM