iOS_Quartz 2D繪圖

目  錄:web

1、基礎知識掌握數組

2、Quartz 2D繪圖基礎:CGContextRef實現簡單地繪製圖形網絡

3、CGContextRef實現文字、圖片、基於路徑的圖形繪製框架

4、在內存中繪製位圖函數

5、添加漸變效果性能

6、PDF文檔學習

 

  引言:Quartz 2D繪圖的核心API是CGContextRef,該API專門用於繪製各類圖形。Quartz 2D是一個二維圖形繪製引擎,它支持iOS環境和Mac OS X環境,爲開發者會提供了不少的方便,它在繪圖上功能是很是強大的,如基於路徑的繪圖、透明度、陰影、顏色管理、反鋸齒、PDF文檔生成和PDF元數據訪問等。Quartz 2DAPI做爲Core Graphics框架的一部分,所以其中的不少數據類型和方法都是以CG開頭的。會常常見到Quartz 2D(Quartz)和Core Graphics兩個術語交互使用。字體

1、基礎知識掌握優化

  學習Quartz 2D以前首先先來掌握幾個基礎知識。this

  1.圖形上下文(Graphics Context)——繪製目標

  1)Graphics Context是一個數據類型(CGContextRef),封裝了Quartz繪製圖像到輸出設備的信息。輸出設備能夠是PDF文件、Bitmap、Layer、打印機或者顯示器的窗口上

  2)Quartz中全部的對象都是繪製到一個Graphics Context中

  3)當用Quartz繪圖時,全部設備相關的特性都包含在Graphics Context中。換句話說,咱們能夠簡單地給Quartz繪圖序列指定不一樣的Graphics Context,就可將相同的圖像繪製到不一樣的設備上。而不須要任何設備相關的計算,這些都由Quartz替咱們完成

  2.Quartz 2D座標系

  1)Quartz中默認的座標系統是:原點(0, 0)在左下角。沿着X軸從左到右座標值逐漸增大;沿着Y軸從下到上座標值逐漸增大

  2)有一些技術在設置它們的graphics context時使用了不一樣於Quartz的默認座標系統。最多見的一種修改的座標系統是原點位於左上角,而沿着Y軸從上到下座標值逐漸增大。例如:UIView中的UIGraphicsGetCurrentContext方法返回的圖形上下文就是用的是這種座標系(座標系統的原點位於左上角)

  3.UIKit的座標系

  1)原點(0,0)在屏幕的左上角,X軸向右正向延伸,Y軸向下正向延伸

  2)iOS的像素分辨率會隨設備的硬件而變化,iPhone4第一次引入了視網膜屏幕,像素分辨率爲960* 640,恰好是前一代iPod和iPhone像素分辨率( 480* 320)的兩倍

  3)在繪圖時,須要使用「點」的概念來思考問題,而不是像素。也就是說在點座標系中繪圖,不是硬件的像素座標系

  4)雖然這些設備的像素分辨率不一樣,但用到的座標系保持不變(以點爲單位)。在iPhone4上,一個點會用2像素寬度來繪製

  提示:若是繪圖的上下文,是使用UIGraphicsGetCurrentContext或者其餘以UI開頭的方法獲取到的,在繪圖時無需進行座標轉換

  4.Quartz 2D的繪圖順序

  後面繪製的圖形,會覆蓋先前繪製的圖形。以下圖所示:

 

2、Quartz 2D繪圖基礎:CGContextRef實現簡單地繪製圖形

  使用Quartz 2D繪圖的關鍵步驟有兩步:

  1.獲取CGContextRef;

  2.調用CGContextRef的方法進行繪圖。

  不一樣場景下獲取CGContextRef的方式各不相同,下面介紹iOS開發中最多見的場景下如何獲取CGContextRef.

   (1)自定義UIView獲取CGContextRef

  開發自定義UIView的方法是,開發一個集成UIView的子類,並重寫UIView的drawRect:方法,當該UIVie每次顯示出來時,或該UIView的內容須要更新時,系統都會自動調用UIView的drawRect:方法。在調用UIView的drawRect:方法以前系統會自動配置繪圖環境,所以程序只要經過以下函數便可獲取CGContextRef繪圖API:

  CGContextRef context = UIGraphicsGetCurrentContext();

  (2)建立位圖時獲取CGContextRef

  若是須要在建立位圖時獲取CGContextRef,那麼程序須要先調用UIGraphicsBeginImageContext()函數來建立內存中的圖片。而後調用UIGraphicsGetCurrentContext()獲取繪圖的CGContextRef。

  Quartz 2D時面向過程的API,Quartz 2D提供了大量函數來完成繪圖。

  如今經過一個案例來熟悉一下Quartz 2D的使用過程,以及經常使用的函數使用。首先爲UIView建立一個DemoView類,本案例中全部的繪圖操做都是在DemoView類中進行實現的。

#import "DemoView.h"

@implementation DemoView

- (void)drawRect:(CGRect)rect {
    // 獲取繪圖的上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    //1.繪製三角形
    [self drawTriangle:context];
    //2.繪製矩形
    [self drawRectangle:context];
}

//繪製三角形
-(void)drawTriangle:(CGContextRef)context
{
    //2.添加繪圖路徑
    CGContextMoveToPoint(context, 100, 100);
    CGContextAddLineToPoint(context, 200, 100);
    CGContextAddLineToPoint(context, 150, 200);
    CGContextAddLineToPoint(context, 100, 100);
    //3.設置繪圖的屬性
    CGFloat myColor[4] = {1.0,0.0,0.0,1.0};
    //設置描邊的顏色
    CGContextSetStrokeColor(context, myColor);
    CGFloat myColor1[4]= {0.0,1.0,0.0,1.0};
    //設置填充的顏色
    CGContextSetFillColor(context, myColor1);
    //設置線寬
    CGContextSetLineWidth(context, 5.0);
    
    //設置線的類型:虛線————注意:若是對上下文進行了修改以後的全部連線的類型都默認爲虛線啦!其餘屬性也一併如此。
    CGFloat dash[2] = {1.0,2.0};
    CGContextSetLineDash(context, 0, dash, 2);
    
    //設置鏈接點的類型
    /*
         enum CGLineJoin {
         kCGLineJoinMiter,  鏈接處爲尖角形狀
         kCGLineJoinRound,  鏈接處爲圓角形狀
         kCGLineJoinBevel   鏈接處爲平角形狀
         };
     */
        CGContextSetLineJoin(context, kCGLineJoinRound);
    //4.繪圖
    CGContextDrawPath(context, kCGPathFillStroke);
}
//繪製矩形
-(void)drawRectangle:(CGContextRef)context
{
    //添加一個矩形
    CGContextAddRect(context, CGRectMake(50, 50, 50, 50));
    //添加一個圓形
    CGContextAddEllipseInRect(context, CGRectMake(10, 100, 50, 50));
    //添加一個橢圓
    CGContextAddEllipseInRect(context, CGRectMake(200, 100, 100, 50));
    //設置繪圖屬性
    CGFloat myColor[4] = {1.0,0.0,0.0,1.0};
    //設置描邊顏色
    CGContextSetStrokeColor(context, myColor);
    CGFloat myColor1[4] = {0.0,1.0,0.0,1.0};
    //設置填充顏色
    CGContextSetFillColor(context, myColor1);
    
    //繪圖
    CGContextDrawPath(context, kCGPathFillStroke);
    
}
@end

  運行結果以下圖:

  Quartz 2D繪製的線條默認時實線的。上圖中使用的倒是點線,關於點線模式的設置我作多下詳細的介紹:

  若是須要建立點線可調用CGContextRef的CGContextSetLineDash(CGContextRef c, CGFloat phase, const CGFloat *lengths, size_t count);該函數的第3個參數是點線模式的關鍵,該參數是一個CGFloat型數組(第4個參數通用用於指定該數組的長度),每一個CGFloat值依次控制點線的實現長度、間距。好比該參數以下:

   1)- {2,3}:表明長爲2的實線、距離爲3的間距、長爲2的實線、距離爲3的間距......這種點線模式。
   2)- {2,3,1}:表明長爲2的實線、距離爲3的間距、長爲1的實線、距離爲2的間距、長度爲3的實線、距離爲1的間距......這種點線模式。
   3)- {5,3,1,2}:表明長爲5的實線、距離爲3的間距、長爲1的實線、距離爲2的間距、長爲5的實線、距離爲3的間距、長爲1的實線、距離爲2的間距.....這種點線模式。
   該方法的第2個參數用於指定點線的相位,該參數將會與第3個參數協同起做用,好比以下參數組合。
   - phase=1,lengths={2,3}:表明長爲2的實線、距離爲3的間距、長爲2的實線、距離爲3的間距。但開始繪製起點時只繪製長度爲1的實線,由於phase爲1就是控制該點線「移動」1個點。
   - phase=3,lengths={5,3,1,2}:表明長爲5的實線、距離爲3的間距、長爲1的實線、距離爲2的間距、長爲5的實線、距離爲3的間距、長爲1的實線、距離爲2的間距。但開始繪製起點時只繪製長度爲2的實線,由於phase爲3就是控制該點線「移動」3個點。
     
3、CGContextRef實現文字、圖片、基於路徑的圖形繪製

  前面說到CGContextRef不但能提供繪製基本圖形的功能,還能夠提供繪製文字、圖片、基於路徑的圖形的繪製。下面來看下對這三種的繪製時Quartz 2D是如何實現的。

  1.使用路徑

  使用路徑的步驟以下:

   1.調用CGContextBeginPath函數開始定義路徑
  2.調用各類子函數添加路徑
  3.若是路徑添加完成,調用CGContextClosePath函數關閉路徑。
  4.調用CGContextDrawPath(),CGContextEOFillPath(),CGContextFillPath()或CGContextStrokePath()函數來填充路徑或繪製路徑邊框便可。在這些方法中,第一個方法能夠替換後面的幾個方法,第一個方法指定使用特定的模式來繪製圖形。它支持以下幾種繪製方式。
     - kCGPathFill:指定填充路徑。至關於CGContextFillPath()函數。
     - kCGPathEOFill:指定採用even-odd模式填充路徑。至關於CGContextEOFillPath()函數。
     - kCGPathStroke:指定只繪製路徑。至關於CGContextStrkePath()函數。
     -kCGPathFillStroke:同時繪製路徑、也填充路徑。
     - kCGPathEOFillStroke:即繪製路徑,也採用even-odd模式填充路徑。
   2.繪製文字
   使用CGContextRef繪製文本的步驟以下:
   1.獲取繪圖的CGContextRef。
  2.設置繪製文本的相關屬性,例如:繪製文本所用的繪製方式、字體大小、字體名稱等。
  3.若是隻是繪製不須要進行變換的文本,直接調用NSString的drawAtPoint:withAttributes:、drawInAttributes:withFont:等方法繪製便可。若是須要對繪製的文本進行變換,則須要先調用CGContextSetTextMatrix()函數設置變換矩陣,在調用CGContextShowTextAtPoint()方法繪製文本。
   3.繪製位圖
  爲了繪製位圖,UIImage自己已經提供了以下方法。
  (1)- drawAtPoint:將該圖片自己繪製到當前繪圖CGContextRef的指定點。調用該方法必須傳入一個CGPoint參數,指定該圖片的繪製點。
  (2)- drawAtPoint:blendMode:alpha:屬於前一個方法的加強版,它能夠制定繪製圖片的疊加模式和透明度。
  (3)- drawInRect:將該圖片自己繪製到當前繪圖CGContextRef的指定區域內。調用該方法必須傳入一個CGRect參數,指定該圖片的繪製區域。
   4.設置陰影
  CGContextRef爲設置圖形陰影提供了以下兩個參數:
  (1)-  void CGContextSetShadow(CGContextRef context, CGSize offset,CGFloat blur):該函數設置陰影在X、Y方向上的偏移,並設置陰影的模糊程度。該函數的offset包含兩個CGFloat值,第1個CGFloat值控制陰影在X方向的偏移,若是該值爲正,則向右偏移,不然向左偏移;第2個CGFloat值控制陰影在Y方向的偏移,若是該值爲正,則鄉下偏移,不然向上偏移。最後一個blur參數控制陰影的模糊程度,若是參數爲1,代表陰影幾乎不模糊,blur參數越大,陰影越模糊。
  示例: CGContextSetShadow(context, CGSizeMake(-8, -6), 5);
  (2)- void CGContextSetShadowWithColor(CGContextRef context, CGSize offset,CGFloat blur, CGColorRef color):該函數與前一個函數的功能基本類似,只是該函數多了一個屬性用於設置陰影顏色。
  示例: CGContextSetShadowWithColor(context, CGSizeMake(-8, -6), 5, [[UIColor redColor]CGColor]);
  如今經過一個案例代碼,來使用以上的方法實現繪製圖片、文字、使用路徑繪製圖片。不過此處繪製圖片卻沒有使用提供的方法,後面說道在內存中繪製位圖時再詳解介紹。
#import "DemoView.h"

@implementation DemoView

- (void)drawRect:(CGRect)rect {
    // 獲取繪圖的上下文
    CGContextRef context = UIGraphicsGetCurrentContext();

    //3.經過路徑的方式建立三角形
    [self drawTriangleByPath:context];
    //4.繪製文字
    [self drawString:context];
    //5.繪製圖片
    [self drawImage];
    
}
-(void)drawImage
{
    UIImage *image = [UIImage imageNamed:@"6.jpg"];
    //將該圖片自己繪製到當前繪圖CGContextRef的指定區域中。
    [image drawInRect:CGRectMake(100, 300, 200, 150)];
    //將該圖片自己繪製到當前回去CGContextRef的指定點
    [image drawAtPoint:CGPointMake(10, 450)];
}
-(void)drawString:(CGContextRef)context
{
    NSString *string = @"hello world";
    //設置使用描邊模式繪製文字
    CGContextSetTextDrawingMode(context, kCGTextStroke);
    //將文字自己繪製到當前CGContextRef的指定點
    [string drawAtPoint:CGPointMake(100, 250) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:18],NSForegroundColorAttributeName:[UIColor blueColor]}];
    //設置使用填充、描邊繪製文字
    CGContextSetTextDrawingMode(context, kCGTextFillStroke);
    //將文本自己繪製到當前CGContextRef的指定區域中
    [string drawWithRect:CGRectMake(200, 250, 70, 80) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:18],NSForegroundColorAttributeName:[UIColor blueColor]} context:nil];
    
}
-(void)drawTriangleByPath:(CGContextRef)context
{
    //建立路徑
    CGMutablePathRef path = CGPathCreateMutable();
    //向路徑中添加圖形
    CGPathMoveToPoint(path, NULL, 20, 200);//建立起點
    CGPathAddLineToPoint(path, NULL, 100, 300);
    CGPathAddLineToPoint(path, NULL, 60, 400);
    //將path添加到上下文
    CGContextAddPath(context, path);
    //閉合路徑
    CGContextClosePath(context);
    //設置繪圖的屬性
    //設置描邊顏色
    [[UIColor redColor]setStroke];
    //設置填充顏色
    [[UIColor greenColor]setFill];
    
    //同時設置填充顏色,又能設置描邊顏色
//    [[UIColor whiteColor]set];
    //使用默認的陰影顏色,陰影向左上角投影,模糊度爲5
//    CGContextSetShadow(context, CGSizeMake(-8, -6), 5);
    CGContextSetShadowWithColor(context, CGSizeMake(-8, -6), 5, [[UIColor redColor]CGColor]);
    //繪圖
    CGContextDrawPath(context, kCGPathFillStroke);
}
@end

  運行效果圖,以下所示:

 

  通過兩個案例,細心地朋友可能發現了這樣的問題:在案例1中對三角形進行設置了線的類型,設置爲點線模式,可是矩形的線的類型沒有設置但一樣變成了點線模式。在案例2中對三角形設置了陰影模式,可是圖片、文字也均帶有了陰影。如何解決?

  解決辦法,分爲兩步走:

  1.對上下文進行操做以前,使用CGContextSaveGState(CGContextRef c)保存當前上下文狀態

  2.對上下文進行操做以後,使用CGContextRestoreGState(CGContextRef c)能夠恢復以前保存的上下文狀態

4、在內存中繪製位圖

  前面介紹的都是經過擴展UIView、重寫drawRect:方法進行繪圖,這種繪圖方式是直接在UIView控件上繪製全部的圖形——因爲每次該控件顯示出來時,drawRect:方法都會被調用,這意味着每次該控件顯示出來時,程序都須要重繪全部的圖形,很明顯,這種方式的性能並很差。除此以外,總有些時候須要在內存中繪製圖片,這樣既可導出到手機本地,也可上傳到網絡上。

  在內存中繪圖的步驟以下:
    (1)調用UIGraphicsBeginImageContext(CGSize size)函數準備繪圖環境。
    (2)調用UIGraphiceGetCurrentContext()函數獲取繪圖CGContextRef
    (3)用前面介紹的繪製集合圖形、使用路徑等方式進行繪圖。
    (4)調用UIGraphicsGetImageFromCurrentImageContext()函數獲取當前繪製的圖形,該方法返回一個UIImage對象。
    (5)調用UIGraphicsEndImageContext()函數結束繪圖,並關閉繪圖環境。
#import "ViewController.h"

@interface ViewController ()<UIImagePickerControllerDelegate,UINavigationControllerDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property(strong,nonatomic)UIImage *image;
@property (weak, nonatomic) IBOutlet UITextField *textField;

@end

@implementation ViewController
- (IBAction)drawClicked:(UIButton *)sender
{
    //開始圖形繪製的上下文
    UIGraphicsBeginImageContext(self.imageView.frame.size);
    
    //獲取圖形繪製的上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    //繪製矩形
    CGContextAddRect(context, CGRectMake(100, 100, 100, 100));
    //設置描邊、填充顏色
    [[UIColor redColor]set];
    //繪製圖形
    CGContextDrawPath(context, kCGPathFillStroke);
    
    //從圖形繪製上下文獲取圖片
    self.image = UIGraphicsGetImageFromCurrentImageContext();
    
    //結束圖形繪製的上下文
    UIGraphicsEndImageContext();
    //設置顯示圖片
    [self.imageView setImage:self.image];
}
- (IBAction)waterMarkClicked:(UIButton *)sender
{
    //開始圖形繪製的上下文
    UIGraphicsBeginImageContext(self.imageView.frame.size);
    
    //先畫圖片
//    self.image = [UIImage imageNamed:@"6.jpg"];
    [self.image drawInRect:self.imageView.bounds];
    //再畫水印
    NSString *string = self.textField.text;
    [string drawAtPoint:CGPointMake(100, 100) withAttributes:@{NSForegroundColorAttributeName:[UIColor blackColor],NSFontAttributeName:[UIFont systemFontOfSize:25]}];
    //從當前上下文獲取圖片
    self.image = UIGraphicsGetImageFromCurrentImageContext();
    
    //結束圖形繪製的上下文
    UIGraphicsEndImageContext();
    
    //顯示帶水印的圖片
    self.imageView.image = self.image;
    
}
- (IBAction)saveClicked:(UIButton *)sender
{
    //保存圖片到外部設備
    /*
     //設置圖片保存的路徑
     NSString *doucuments = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
     NSString *fileName = [doucuments stringByAppendingPathComponent:@"watermark.png"];
     //獲取圖片中的data
     NSData *imageData = UIImagePNGRepresentation(self.image);
     //保存圖片
     [imageData writeToFile:fileName atomically:YES];
     
     NSLog(@"%@",NSHomeDirectory());

     */
    
    //保存圖片到相冊
    UIImageWriteToSavedPhotosAlbum(self.image, nil, nil, nil);
}

- (IBAction)photoSelect:(UIButton *)sender
{
    //打開相冊
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc]init];
    //設置圖片的來源
    imagePicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    //設置代理
    imagePicker.delegate = self;
    
    //使用模態窗口的方式顯示相冊
    [self presentViewController:imagePicker animated:YES completion:nil];
}
#pragma mark - 實現UIImagePickerControllerDelegate代理方法
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    NSLog(@"%@",info);
    //經過字典方式獲取圖片
    self.image = [info objectForKey:UIImagePickerControllerOriginalImage];
    [self.imageView setImage:self.image];
    
    //關閉模態窗口
    [picker dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidLoad {
    [super viewDidLoad];
    
}


@end

  運行效果圖,以下圖:

5、添加漸變效果

  前面介紹的都是使用一種顏色來填充區域,除此以外,Quartz 2D還容許使用顏色漸變、位圖來填充指定區域。

  Quartz 2D爲咱們提供了兩種漸變填充的函數,分別是:線性漸變填充、圓形徑向漸變填充。

  - void CGContextDrawRadialGradient(CGContextRef context,GradientRef gradient, CGPoint startCenter, CGFloat startRadius,CGPoint endCenter, CGFloat endRadius, CGGradientDrawingOptions options),參數詳解以下:

/* 參數2:gradient參數表明漸變對象,

     參數3:startCenter參數設置起始圓的圓心,

     參數4:startRadius設置起始圓的半徑,

     參數5:endCenter參數表明結束圓的圓心

     參數6:endRadius表明結束圓的半徑

     參數7:options可支持kCGGradientDrawsBeforeStartLocation(可擴展填充起點以前的區域)或kCGGradientDrawsAfterEndLocation(擴展填充結束點以後的區域)*/

  - void CGContextDrawLinearGradient(CGContextRef context,CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint,CGGradientDrawingOptions options):

/* 參數2:gradient參數表明漸變對象,

     參數3:startPoint開始點座標

     參數4:endPoint結束點座標

     參數5:options可支持kCGGradientDrawsBeforeStartLocation(可擴展填充起點以前的區域)或kCGGradientDrawsAfterEndLocation(擴展填充結束點以後的區域)*/

  廢話很少說,直接上代碼分析:

#import "DemoView.h"

@implementation DemoView

- (void)drawRect:(CGRect)rect {
    // 畫漸變:線性漸變、徑向漸變
    
    //獲取繪圖的上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    //畫線性漸變
//    [self drawLinarGradient:context];
    [self drawRadialGradient:context];
}
-(void)drawRadialGradient:(CGContextRef)context
{
    //2.建立漸變
    //2.1建立顏色空間
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    //2.2設置開始顏色、結束時顏色
    UIColor *startColor =[UIColor yellowColor];
    const CGFloat *startColorCompents = CGColorGetComponents([startColor CGColor]);
    UIColor *endColor = [UIColor blackColor];
    const CGFloat *endColorCompents = CGColorGetComponents([endColor CGColor]);
    
    CGFloat components[8] = {startColorCompents[0],startColorCompents[1],
        startColorCompents[2],
        startColorCompents[3],
        endColorCompents[0],
        endColorCompents[1],
        endColorCompents[2],
        endColorCompents[3]};
    CGFloat locations[2] = {0.0,1.0};
    
    CGGradientRef gradien = CGGradientCreateWithColorComponents(colorSpace, components, locations, 2);
    /*
     參數詳解;
     參數1:用於指定該漸變所使用的顏色空間(如:RGB,CMYK,Gray等顏色空間);
     參數2:用於指定根據不一樣的顏色空間設置多種顏色
     參數3:locations參數指定各顏色點得分佈位置(若是將該參數指定爲NULL,各顏色點將會均勻分佈)
     參數4:count參數指定該漸變包含多少種顏色
     */
    //3.繪畫漸變效果(徑向漸變)
    CGContextDrawRadialGradient(context, gradien, CGPointMake(200, 200), 50, CGPointMake(200, 200), 100, kCGGradientDrawsBeforeStartLocation|kCGGradientDrawsAfterEndLocation);
    /*
     參數2:gradient參數表明漸變對象,
     參數3:startCenter參數設置起始圓的圓心,
     參數4:startRadius設置起始圓的半徑,
     參數5:endCenter參數表明結束圓的圓心
     參數6:endRadius表明結束圓的半徑
     參數7:options可支持kCGGradientDrawsBeforeStartLocation(可擴展填充起點以前的區域)或kCGGradientDrawsAfterEndLocation(擴展填充結束點以後的區域)
     */
    //4.清理工做
    CGColorSpaceRelease(colorSpace);
    CGGradientRelease(gradien);
    
}

-(void)drawLinarGradient:(CGContextRef)context
{
    //2.建立漸變
    //2.1建立顏色空間
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    //2.2設置開始顏色、結束時顏色
    UIColor *startColor =[UIColor redColor];
    const CGFloat *startColorCompents = CGColorGetComponents([startColor CGColor]);
    UIColor *endColor = [UIColor blueColor];
    const CGFloat *endColorCompents = CGColorGetComponents([endColor CGColor]);
    
    CGFloat components[8] = {startColorCompents[0],startColorCompents[1],
        startColorCompents[2],
        startColorCompents[3],
        endColorCompents[0],
        endColorCompents[1],
        endColorCompents[2],
        endColorCompents[3]};
    CGFloat locations[2] = {0.0,1.0};
    
    
    CGGradientRef gradien = CGGradientCreateWithColorComponents(colorSpace, components,NULL, 2);
    
    //3.繪畫漸變效果(線性)
    CGContextDrawLinearGradient(context, gradien, CGPointMake(100, 100), CGPointMake(200, 100),kCGGradientDrawsAfterEndLocation | kCGGradientDrawsBeforeStartLocation);
    /*
     options可支持kCGGradientDrawsBeforeStartLocation(可擴展填充起點以前的區域)或kCGGradientDrawsAfterEndLocation(擴展填充結束點以後的區域)
    */
    //4.清理工做
    CGColorSpaceRelease(colorSpace);
    CGGradientRelease(gradien);

}
@end

  運行效果圖,以下所示:

 6、PDF文檔

  1.繪製、讀取PDF文檔

  PDF文檔存儲依賴於分辨率的向量圖形、文本和位圖,並用於程序的一系列指令中。一個PDF文檔能夠包含多頁的圖形和文本。PDF可用於建立跨平臺、只讀的文檔,也可用於繪製依賴於分辨率的圖形。Quartz爲全部應用程序建立高保真的PDF文檔,這些文檔保留應用的繪製操做,如圖下圖所示。PDF文檔的結果將經過系統的其它部分或第三方法的產品來有針對性地進行優化。Quartz建立的PDF文檔在Preview和Acrobat中都能正確的顯示。

 

  案例1:建立pdf文檔(建立並讀取)

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIWebView *webView;

@end

@implementation ViewController
- (IBAction)showPDF:(id)sender
{
    //設置pdf文件的路徑
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSLog(@"%@",documentPath);
    NSString *pdfFileName = [documentPath stringByAppendingPathComponent:@"face.pdf"];
    
    //建立URL
    NSURL *url = [NSURL URLWithString:pdfFileName];
    
    //建立request
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //在webView中顯示
    [self.webView loadRequest:request];
    
}

- (void)viewDidLoad {
    [super viewDidLoad];
    //
    [self createImagePDF];
}
-(void)createImagePDF
{
    //設置pdf文件的路徑
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSLog(@"%@",documentPath);
    NSString *pdfFileName = [documentPath stringByAppendingPathComponent:@"face.pdf"];
    
    //開始pdf的繪圖上下文
    UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectMake(0, 0, 320, 480), nil);
    
    for(int i = 0; i < 9; i++)
    {
        //開始pdf新的一頁
        UIGraphicsBeginPDFPage();
        
        //畫圖像
        UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"%d.png",i]];
        [image drawAtPoint:CGPointMake(320/2, 480/2)];
    }
    
    //結束pdf的繪圖上下文
    UIGraphicsEndPDFContext();

}
//建立pdf
-(void)createPDF
{
    //設置pdf文件的路徑
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSLog(@"%@",documentPath);
    NSString *pdfFileName = [documentPath stringByAppendingPathComponent:@"test.pdf"];

    //開始pdf的繪圖上下文
    UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectMake(0, 0, 320, 480), nil);
    
    //獲取當前的繪圖上下文
    CGContextRef context  = UIGraphicsGetCurrentContext();
    //開始pdf新的一頁
    UIGraphicsBeginPDFPage();
    //畫圓形
    CGContextAddEllipseInRect(context, CGRectMake(100, 100, 100, 100));
    //設置描邊、填充顏色
    [[UIColor redColor]set];
    //將圖形繪製到上下文中
    CGContextDrawPath(context, kCGPathFillStroke);
    
    //畫字符串
    NSString *str = @"this is  a test page.";
    [str drawAtPoint:CGPointMake(200, 200) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:18],NSForegroundColorAttributeName:[UIColor blueColor]}];
    
    //結束pdf的繪圖上下文
    UIGraphicsEndPDFContext();
}

@end

  運行效果圖,以下圖所示:

  以上案例中共實現三個功能:

  (1)將圖片繪製到pdf文檔中去,

  (2)將自定義的圖形繪製到pdf文檔中

  (3)經過UIWebView控件進行顯示pdf文檔內容(這種方式只只用於圖形類的內容,若是是電子書文本類的內容,則此方式不可實現)。

  2.使用Quartz 2D的方式讀取PDF文檔內容

#import "PDFView.h"
@interface PDFView()<UIActionSheetDelegate,UIAlertViewDelegate>
{
    CGPDFDocumentRef _pdfDoc;
    size_t _pageNo;//當前頁碼
    size_t _totalPage;//總的頁數
}
@end
@implementation PDFView

- (void)drawRect:(CGRect)rect {
    NSLog(@"重繪");
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    //旋轉座標系
    CGContextTranslateCTM(context, 80, self.frame.size.height-60);
    CGContextScaleCTM(context, 1, -1);
    
    //畫頁面
    [self drawPDFPage:_pageNo context:context];
}
//打開pdf文檔
-(void)openPDF:(NSURL *)url
{
    CFURLRef urlRef = (__bridge CFURLRef)url;
    _pdfDoc = CGPDFDocumentCreateWithURL(urlRef);
    _totalPage = CGPDFDocumentGetNumberOfPages(_pdfDoc);
    _pageNo = 1;
}
//顯示pdf頁面
-(void)drawPDFPage:(size_t)pageNo context:(CGContextRef)context
{
    CGPDFPageRef pdfPage = CGPDFDocumentGetPage(_pdfDoc, pageNo);
    CGContextDrawPDFPage(context, pdfPage);
}

- (IBAction)prePage:(id)sender
{
    if(_pageNo > 1)
    {
        _pageNo--;
        [self setNeedsDisplay];
    }
  }
- (IBAction)nextPage:(id)sender
{
    if(_pageNo < _totalPage)
    {
        _pageNo++;
        [self setNeedsDisplay];
    }
}

@end

  運行效果圖,以下所示:

相關文章
相關標籤/搜索