关闭

Quartz 2D基础

175人阅读 评论(0) 收藏 举报
分类:

这里写图片描述

很早就想学quartz 2d了, 特别是贝塞尔曲线画图, 但是每次看到都是C的东西就感觉的头痛, 最近实在没忍住它的诱惑, 搜罗了一下网上的教程, 记录一下

Quartz 2D简介


Quartz 2D,是ios和mac os x环境下的二维绘图引擎。

  • Quartz2D提供了一下几种类型的Graphics Context:
      1. Bitmap Graphics Context
      1. PDF Graphics Context
      1. Window Graphics Context
      1. Layer Graphics Context
      1. Printer Graphics Context

涉及内容包括:基于路径的绘图,透明度绘图,遮盖,阴影,透明层,颜色管理。防锯齿渲染,生成PDF,以及PDF元数据相关处理。

所有的操作都在上下文中进行。所以在绘图之前需要获取该上下文并传入执行渲染的函数内。如果你正在渲染一副在内存中的图片,此时就需要传入图片所属的上下文。获得一个图形上下文是我们完成绘图任务的第一步,你可以将图形上下文理解为一块画布。如果你没有得到这块画布,那么你就无法完成任何绘图操作. 当获得一个Graphics Context后,可以使用Quartz 2D函数在上下文(context)中进行绘制、完成操作(如平移)、修改图形状态参数(如线宽和填充颜色)等

属性 和 方法


CGContextRef context = UIGraphicsGetCurrentContext(); 设置上下文
CGContextMoveToPoint 开始画线
CGContextAddLineToPoint 画直线

CGContextAddEllipseInRect 画一椭圆
CGContextSetLineCap 设置线条终点形状
CGContextSetLineDash 画虚线
CGContextAddRect 画一方框
CGContextStrokRect 指定矩形
CGContextStrokeLineWithWidth 指定矩形线宽度
CGContextStrokeLineSegments 一些直线

CGContextAddArc 画一曲线, 前两点为中心,中间两点为起始弧度,最后一数据位0则顺时针画,1则逆时针
CGContextAddArcToPoint(context,0,0,2,9,40);//线画两条线从point到第一点,从第一点到第2点的线 切割里面的圆。
CGContextSetShadowWithColor 设置阴影
CGContextSetRGBFillColor 这只填充颜色
CGContextSetRGBStrokeColor 画笔颜色设置
CGContextSetFillColorSpace 颜色空间填充
CGContextSetStrokeColorSpace颜色空间画壁设置
CGContextFillRect补充当前填充颜色的rect
CGContextSetAlaha透明度

CGContextTranslateCTM 改变画布的位置
CGContextSetLineWidth设置线的宽度
CGContextAddQuadCurveToPoint画曲线
CGContextStrokePath 开始绘制图片
CGContextDrawPath 设置绘制模式
CGContextClosePath 封闭当前线路
CGContextTranslateCTM(context,0,rect,size.height);
CGContextScaleCTM(context,1.0,-1.0,-1.0);翻转画布
CGContextSetInterpolationQuality背景内置颜色质量等级
CGImageCreateWithImageRect 从原图片中去小图。

字符串的写入可用NSString本身的画图方法 -(CGSize)drawInRect:(CGRect)rect withFont;(UIFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UItextAlignment)alignment;来写进去即可

对图片放大缩小的功能就是慢了点
UIGraphicsBeginImageContext(newSize);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

CGColorGetComponents ()返回颜色的各个值,以及透明度,可用只读const float 来接受是个数组

画图片
CGImageRefimage = CGImageRetain(img.CGImage);
CGContextDrawImage(context.CGRectMake(10.0,height-100.0,90.0,90.0),image);

实现渐变颜色填充方法
CGContextClip(context);
CGFloat color [] =
{
204.0 / 255.0, 224.0 / 255.0, 244.0 / 255.0, 1.00,

29.0 / 255.0, 156.0 / 255.0, 215.0 / 255.0, 1.00,

0.0 / 255.0, 50.0 / 255.0, 126.0 / 255.0, 1.00,

};

CGGradientRef gradient= CGGradientCreateWithColorComponents(rgb,colors,NULL,sizeof(colors)/(sizeof(colors[0])*4));
CGColorSpaceRelease(rgb);
CGContextDrawLinearGradient(context,gradient,CGPointMake(0.0,0.0),CGPointMake(0.0,self.frame.size.height),KCGGradientDrawsBeforStartLocation);

注:画完图后,必须先用CGContextStrokePath来描线,即形状
后用CGContextFillPath来填充形状内的颜色

设置当一个颜色覆盖上另外一个颜色,两个颜色怎么混合

默认方式是

result = (alpha * foreground) + (1 - alpha) * background

CGContextSetBlendMode :设置blend mode.

CGContextSaveGState :保存blend mode.

CGContextRestoreGState:在没有保存之前,用这个函数还原blend mode.

CGContextSetBlendMode 混合俩种颜色

简单使用


重写 - (void)drawRect:(CGRect)rect;方法

画直线

方法一

    //1. 获取 上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    //2. 设置颜色
    [[UIColor greenColor] setFill];

    //3. 画线
    CGContextMoveToPoint(ctx, 20, 20);
    CGContextAddLineToPoint(ctx, 200, 200);
    CGContextSetLineWidth(ctx, 5);
    CGContextSetRGBStrokeColor(ctx, 0.8, 0.5, 0.8, 1.0);
    //4. 结束上下文
    CGContextStrokePath(ctx);

方法二

在画线的时候,方法的内部默认创建一个path。它把路径都放到了path里面去。
1.创建路径 CGMutablePathRef 调用该方法相当于创建了一个路径,这个路径用来保存绘图信息。
2.把绘图信息添加到路径里边。
以前的方法是点的位置添加到ctx(图形上下文信息)中,ctx 默认会在内部创建一个path用来保存绘图信息。
在图形上下文中有一块存储空间专门用来存储绘图信息,其实这块空间就是CGMutablePathRef。
3.把路径添加到上下文中。

    CGFloat with = rect.size.width;
    CGFloat height = rect.size.height;

/*
     画线,可以创建一条路径(path)用来保存画线的绘图信息,如果又要重新画一个圆,那么就可以创建一条新的路径来专门保存画圆的绘图信息。
     */
     // 1. 获取一个与视图相关联的上下文
    CGContextRef context = UIGraphicsGetCurrentContext();

    // 2. 构建路径
    // 2.1 创建路径
    CGMutablePathRef path = CGPathCreateMutable();
    // 2.2 设置路径起点
    CGPathMoveToPoint(path, NULL, 50, 50);
    // 2.3 增加路径内容...
    CGPathAddLineToPoint(path, NULL, 50, 420);
    CGPathAddLineToPoint(path, NULL, 270, 420);
    CGPathAddLineToPoint(path, NULL, 270, 50);
    // 2.4 关闭路径
    CGPathCloseSubpath(path);

    // 3. 将路径添加到上下文
    CGContextAddPath(context, path);

    // 4. 设置上下文状态
    // 4.1 设置边线颜色
    CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);
    // 4.2 设置填充颜色
    CGContextSetRGBFillColor(context, 0, 0, 1, 1);

    // 4.2 设置线宽
    CGContextSetLineWidth(context, 10);
    // 4.3 设置线段连接样式
    CGContextSetLineJoin(context, kCGLineJoinRound);
    // 4.4 设置线段首位样式
    CGContextSetLineCap(context, kCGLineCapRound);
    // 4.5 设置虚线
    CGFloat lengths[] = {20, 100};
    CGContextSetLineDash(context, 100, lengths, 2);

    // 5. 绘制路径
    CGContextDrawPath(context, kCGPathEOFill);

    // 6. 释放路径(如果创建对象的函数中包含create,copy或者retain字样,就需要释放!)
    CGPathRelease(path);

画圆, 椭圆

    //1. 获取 上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    //2. 设置颜色
    [[UIColor greenColor] setFill];

    //3. 画圆(在矩形中)
    CGContextAddEllipseInRect(ctx, CGRectMake(10, 10, with - 20, height - 20));
    //结束上下文(填充, 不填充)
    CGContextFillPath(ctx);
    //CGContextStrokePath(ctx);

画弧arc

    /* Add an arc of a circle to the context's path, possibly preceded by a
   straight line segment. 
      `(x, y)' is the center of the arc; 
       `radius' is its radius; 
       `startAngle' is the angle to the first endpoint of the arc;
       `endAngle' is the angle to the second endpoint of the arc; and
       `clockwise' is 1 if the arc is to be drawn clockwise(顺时针方向的), 0 otherwise.
   `startAngle' and `endAngle' are measured in radians. */

    CGContextAddArc(CGContextRef __nullable c, CGFloat x, CGFloat y,
    CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)

说明一点:
坐标问题 , 和我们平常的坐标系不一样
这里写图片描述

画矩形

你也可以画四条线

简单点的

    //1. 获取 上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    //2. 矩形
CGContextAddRect(ctx, CGRectMake(0, 0, with, height));

    //3. 结束上下文
    CGContextStrokePath(ctx);
    UIRectFill(CGRectMake(10, 10, 200, 300));

画圆角矩形

先介绍复杂的基础的, 使用UIBezierPath

CGFloat with = rect.size.width;
    CGFloat height = rect.size.height / 2.0;

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    [[UIColor colorWithWhite:0.600 alpha:1.000] set];

    //CGContextMoveToPoint(ctx, 0, 20);
    //0, 逆时针, 1顺时针

    //不抗锯齿
    //CGContextSetAllowsAntialiasing(ctx, NO);
    /**
     *  ctx: 上下文

     */
    CGContextAddArc(ctx, radius, radius, radius, M_PI, M_PI_2 *3, 0);
    CGContextAddArc(ctx, with-radius, radius, radius, M_PI_2 *3, 0, 0);
    CGContextAddArc(ctx, with-radius, height-radius, radius, 0, M_PI_2, 0);
    CGContextAddArc(ctx, radius, height-radius, radius, M_PI_2, M_PI, 0);
    CGContextSetLineWidth(ctx, 1.5);
    CGContextClosePath(ctx);
    CGContextStrokePath(ctx);


    CGContextAddArc(ctx, radius, radius+height, radius, M_PI, M_PI_2 *3, 0);
    CGContextAddArc(ctx, with-radius, radius+height, radius, M_PI_2 *3, 0, 0);
    CGContextAddArc(ctx, with-radius, height-radius+height, radius, 0, M_PI_2, 0);
    CGContextAddArc(ctx, radius, height-radius+height, radius, M_PI_2, M_PI, 0);
    CGContextSetLineWidth(ctx, 1.5);
    CGContextClosePath(ctx);
    CGContextStrokePath(ctx);

文字

    NSString *str = @"将文字绘制到指定的范围内, 如果一行装不下会自动换行, 当文字超出范围后就不显示";
    NSDictionary *dic = @{           NSFontAttributeName: [UIFont systemFontOfSize:18]
                          };
    CGRect frame = [str boundingRectWithSize:rect.size options:NSStringDrawingUsesLineFragmentOrigin |NSStringDrawingUsesFontLeading attributes:dic context:nil];

    [str drawInRect:frame withAttributes:dic];

图像

    UIImage *image = [UIImage imageNamed:@"1.jpg"];

     //利用drawAsPatternInRec方法绘制图片到layer, 是通过平铺原有图片
    [image drawAsPatternInRect:rect];
     //利用drawInRect方法绘制图片到layer, 是通过拉伸原有图片
    [image drawInRect:rect];

     //将图片绘制到指定的位置
    //[image drawAtPoint:CGPointMake(100, 100)];

绘制渐变

//1. 定义渐变引用CGGradientRef
    CGGradientRef gradient;
    //2. 定义色彩空间引用
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    //3. 定义渐变颜色组件
    //每四个数一组,分别对应r,g,b,透明度
    CGFloat components[8] = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0};
    //4. 定义颜色渐变位置
    // 第一个颜色开始渐变的位置
    // 第二个颜色结束渐变的位置
    CGFloat locations[2] = {0, 1};
    //5. 创建颜色渐进
    gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, 2);
    //6. 创建贝塞尔路径,是OC的,如果只是制定了渐变,没有指定剪切路径,就是整个视图的渐变
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 200, 200)];
    //7. 添加剪切路径
    [path addClip];

    //8. 绘制线性渐进
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextDrawLinearGradient(context, gradient, CGPointMake(50, 50), CGPointMake(200, 50), kCGGradientDrawsAfterEndLocation);

    //9. 释放颜色空间
    CGColorSpaceRelease(colorSpace);
    //10. 释放渐变引用
    CGGradientRelease(gradient);

pdf

// 1. 上下文
  // 1) 路径
  // 2) 大小,指定为空,那么使用612 * 792大小作为pdf文件的页面大小
  // 3) dict 
  UIGraphicsBeginPDFContextToFile(@"/Users/apple/Desktop/demo.pdf", CGRectZero, nil);

  // 2. 写入内容
  // 在pdf里面是有页面的,一个页面一个页面的写入的
  // 建立PDF页面
  // 一个页面最多能够写入两张图片,因此写入6张图片需要三个页面
  for (NSInteger i = 0; i < 6; i++) {
    if (i % 2 == 0) {
      UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);
    }

    // 生成UIImage
    UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"NatGeo%02d.png", i + 1]];
    // 写入
    [image drawAtPoint:CGPointMake(0, 400 * (i % 2))];
  }

  // 3. 关闭上下文
  UIGraphicsEndPDFContext();

贝塞尔曲线


个人感觉比较重要, 放到下一个文章中吧

注意

UIKit默认的坐标系统与Quartz不同。在UIKit中,原点位于左上角,y轴正方向为向下。UIView通过将修改Quartz的Graphics Context的CTM[原点平移到左下角,同时将y轴反转(y值乘以-1)]以使其与UIView匹配。这些都是系统自动帮我们完成。

参考

  1. iOS开发学习之Quartz2D绘图http://www.tuicool.com/articles/nQVBBn
  2. QUARTZ-2D绘图之图形上下文详解http://www.cnphp6.com/archives/66853
  3. http://www.360doc.com/content/13/1228/16/8310724_340792339.shtml
  4. http://www.cnblogs.com/xdream86/archive/2012/12/12/2814552.html
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:49696次
    • 积分:1374
    • 等级:
    • 排名:千里之外
    • 原创:80篇
    • 转载:15篇
    • 译文:2篇
    • 评论:7条