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

  运行效果图,以下所示:

相关文章
相关标签/搜索