Quartz 2D 绘图

#pragma mark - 使用默认的context绘制直线

-(void)drawLine{

    // 1. 取得上下文

    CGContextRef context = UIGraphicsGetCurrentContext();

    

    // 2. 起始点

    CGContextMoveToPoint(context, 50, 50);

    // 1) 起始点到第一个点

    CGContextAddLineToPoint(context, 200, 200);

    // 2) 第一个点到第二个点 如果不封闭图形就是两条线

    CGContextAddLineToPoint(context, 20, 200);

    // 3) 封闭图形后就是三角形

    CGContextClosePath(context);

    

    // 3. 设置属性

    // 设置边线

    [[UIColor redColor] setStroke];

    // 设置填充

    [[UIColor blueColor] setFill];

    // 设置边线和填充

//    [[UIColor greenColor] set];

    

    // 4. 绘制路径 虽然没有直接定义路径,但是第2步操作,就是为上下文指定路径

    CGContextDrawPath(context, kCGPathFillStroke);

    

}

#pragma mark - 使用路径绘制直线

-(void)drawLine2{

    // 提示,使用Ref声明的对象,不需要用*

    // 1. 获取上下文-UIView对应的上下文

    CGContextRef context = UIGraphicsGetCurrentContext();

    

    // 2. 创建可变的路径并设置路径

    /**

     注意:当我们开发动画的时候,通常需要指定对象运动的路线,然后由动画方法负责实现动画效果

     因此,在动画开发中,需要熟练使用路径

     */

    CGMutablePathRef path = CGPathCreateMutable();

    // 划线->

    // 1) 设置起始点

    CGPathMoveToPoint(path, NULL, 50, 50);

    // 2) 设置目标点

    CGPathAddLineToPoint(path, NULL, 200, 200);

    CGPathAddLineToPoint(path, NULL, 50, 200);

    // 3) 封闭路径

    CGPathCloseSubpath(path);

    

    // 3. 将路径添加到上下文

    CGContextAddPath(context, path);

    

    // 4. 设置上下文属性

    /*

     设置线条颜色

     red  0 ~ 1.0  red / 255

     green 0 ~ 1.0 green / 255

     blue 0 ~ 1.0 blue / 255

     alpha 透明度 0 ~ 1.0

     0 - 完全透明

     1.0 - 完全不透名

     提示:

     1) 在使用rgb颜色设置时,最好不要同时指定 rgb alpha,否则会对性能造成一定影响

     2) 默认线条和填充颜色都是黑色

     */

    CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);

    CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 1.0);

    // 设置线条宽度

    CGContextSetLineWidth(context, 5.0);

    // 设置线条的顶点样式

    CGContextSetLineCap(context, kCGLineCapRound);

    // 设置线条的连接点样式

    CGContextSetLineJoin(context, kCGLineJoinRound);

     // 设置线条的虚线样式

    /**

     虚线的参数

     context

     phase 相位,虚线起始的位置,通常使用0即可,从头开始画虚线

     lengths 长度的数组

     count lengths数组的个数

     */

    CGFloat lengths[2] = {20.0,10.0};

    CGContextSetLineDash(context, 0.0, lengths, 2);

    

    // 5. 绘制路径

    /**

     kCGPathStroke: 画线(空心)

     kCGPathFill:   填充(实心)

     kCGPathFillStroke: 即画线又填充

     */

    CGContextDrawPath(context, kCGPathFillStroke);

    

    // 6. 释放路径

    CGPathRelease(path);

}

#pragma mark - 绘制矩形

-(void)drawShapeRect{

    /**

     在程序开发中,无论肉眼看到的是什么形状的对象,其本质都是矩形的

     */

    CGRect rect = CGRectMake(50, 50, 200, 200);

    [[UIColor redColor] set];

    

    // 绘制实心矩形

    UIRectFill(rect);

    // 绘制空心矩形

    UIRectFrame(CGRectMake(50, 300, 100, 100));

}

#pragma mark - 绘制圆形

-(void)drawShapeCycle{

    // 1. 取出上下文

    CGContextRef context = UIGraphicsGetCurrentContext();

    UIRectFrame(CGRectMake(50, 50, 200, 100));

    

    // 2. 设置路径

    CGContextAddEllipseInRect(context, CGRectMake(50, 50, 200, 100));

    // 3. 绘制圆形路径

    CGContextDrawPath(context, kCGPathFillStroke);

}

#pragma mark - 绘制圆弧

-(void)drawArc{

    // 1. 取得上下文

    CGContextRef context = UIGraphicsGetCurrentContext();

    // 2. 设置路径

    /**

     1) context 上下文

     2) x,y 是圆弧所在圆的中心点坐标

     3) radius 半径,所在圆的半径

     4) startAngle endAngle 起始角度和截止角度 单位是弧度

     0 对应是圆的最右侧点

     5) clockwise 顺时针 0 或者逆时针 1

     */

    CGContextAddArc(context, 160, 230, 100, -M_PI_4, M_PI_4, 0);

    // 3. 绘制路径

    CGContextDrawPath(context, kCGPathStroke);

}

#pragma mark - 绘制文字  中文竖排

-(void)drawText{

    NSString * str =  @"Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world ";

    NSString * str1 = @"般若波罗蜜多心经";

    // 指定点绘制字符串

//    [str drawAtPoint:CGPointMake(50, 50) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17],NSForegroundColorAttributeName:[UIColor brownColor]}];

    

    // 如果在UILabel中,可以将numbersOfLine设置为0,并且指定足够的高度即可

    [[UIColor lightGrayColor] set];

    UIRectFill(CGRectMake(8, 50, 150, 360));

    

     // 在指定区域绘制字符串 横向

    [str drawInRect:CGRectMake(8, 50, 150, 360) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17],NSForegroundColorAttributeName:[UIColor brownColor]}];

    

    [[UIColor lightGrayColor] set];

    UIRectFill(CGRectMake(162, 50, 30, 360));

    

    // 中文竖排 就是让rect的宽度窄一些  这样字符串就垂直了

    [str1 drawInRect:CGRectMake(162, 50, 30, 360) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17],NSForegroundColorAttributeName:[UIColor brownColor]}];

}

#pragma mark - 绘制图像

-(void)drawImage{

    UIImage * img = [UIImage imageNamed:@"头像1.png"];

    // 提示:绘制之后,就无法改变位置,也没有办法监听手势识别

    

    // 在指定点绘制图像  Point top-left corner of the image

    [img drawAtPoint:CGPointMake(50, 50)];

    // 会在指定的矩形中拉伸绘制

    [img drawInRect:CGRectMake(0, 0, 320, 460)];

    // 在指定矩形区域中平铺图片

    [img drawAsPatternInRect:CGRectMake(0, 0, 320, 460)];

}


#pragma mark - 绘制五角星

分析  我们绘图肯定是要要直线 那么就要计算 画一条直线所走过的圆心角 给五角星的角度编号 0 ,1 ,2, 3, 4   第一条直线应才是0 ->2 那么它走过的角度上 2/5 *360 = 144度(从0->1 为一个内角  五个内角加起来值为360) 同理第二条第三条第四条也是的 ;  假如我们把0刚好放在y坐标正轴上(坐标是 0, r)  那么我们可以算出2这个点的 x  y 坐标  分析的知 x = r * cos((2 * M_PI / 5.0) * 2.0 M_PI_2)   y = r* sin((2 * M_PI / 5.0) * 2.0 M_PI_2)  M_PI表示圆周率 不是表示360  角度转换成弧度的公式 : (角度 * 2π)/ 360  所以144度  144 * M_PI/180=(4/5)* M_PI


@interface DrawFivePointStar() {

    // 是否已经计算过五角星顶点

    BOOL _hasPoint;

    // 记录五角星的五个顶点 数组

    CGPoint points[5];

}


@end


@implementation DrawFivePointStar


#pragma mark - 记录五角星的五个顶点



//  Only override drawRect: if you perform custom drawing.

//  An empty implementation adversely affects performance during animation.

- (void)drawRect:(CGRect)rect {  // 这里其实只调用了一次

    if (!_hasPoint) {  // 没有计算过角度 第一次 初始的时候

        [self loadPoints];

        _hasPoint = YES;

    }

    static int times = 0 ;

    NSLog(@"%d",++times);

    CGContextRef context = UIGraphicsGetCurrentContext();

    [self drawRandomStarWithContext:context count:16];

}


#pragma mark - 通过第一个点 计算出五角星的五个顶点坐标

-(void)loadPoints{

   // 半径

    CGFloat r = 100 ;

    // 第一个点的坐标是 中心点(0,0) 第一个点坐标为( 0, 0-r )

    points[0] = CGPointMake(0, -r);

    // 每画一条直线转过的角度 每次旋转 (2 * M_PI / 5.0) * 2.0 = 144   M_PI表示圆周率 不是表示360

    CGFloat angle = (4.0/5.0) * M_PI ;

    

    // 计算出画四条线每条线的坐标是

    for (int i = 1; i<5; i++) {

        // 计算出下一个点的坐标 相对的(0,0)计算的

        CGFloat x = r * cosf(i*angle - M_PI_2);

        CGFloat y = r * sinf(i*angle - M_PI_2) ;

        points[i]=CGPointMake(x, y);

    }

}

#pragma mark - 对画的五角星进行位置 角度 大小的随机设置

-(void)drawRandomStarWithContext:(CGContextRef )context count:(NSInteger) count{

    for (NSInteger i = 0 ; i<count; i++) {

        // 保存上下文 最初的坐标系

        CGContextSaveGState(context);

        

        // 下列操作会改变当前context的坐标系

        // 平移上下文

        CGFloat x = arc4random()%320;

        CGFloat y = arc4random()%480;

        CGContextTranslateCTM(context, x, y);

        // 旋转上下文

        CGFloat angle = (arc4random()%180 * M_PI/180.0);

        CGContextRotateCTM(context, angle);

        // 缩放上下文

        CGFloat scale = arc4random_uniform(5)/10.0 + 0.5 ;

        CGContextScaleCTM(context, scale, scale);

        

        // 绘制五角星

        [self drawStarWithContext:context];

        // 恢复之前的上下文 最初的坐标系

        CGContextRestoreGState(context);

        

    }

}

#pragma mark - 对画的五角星的颜色进行随机赋值

-(UIColor *)randomColor{

    CGFloat r = arc4random_uniform(255)/255.0;

    CGFloat g = arc4random_uniform(255)/255.0;

    CGFloat b = arc4random_uniform(255)/255.0;

    return [UIColor colorWithRed:r green:g blue:b alpha:1.0];

}

#pragma mark - 绘制五角星

-(void)drawStarWithContext:(CGContextRef ) context{

    [[self randomColor] set];

    // 设置起始点

    CGContextMoveToPoint(context, points[0].x, points[0].y);

    

    // 设置路径,计算其他四个点的坐标 技巧, 一个一个计算调试 否则画太多不好调试

    for (int i = 1; i<5; i++) {

        CGContextAddLineToPoint(context, points[i].x, points[i].y);

    }

    // 关闭路径

    CGContextClosePath(context);

    

    // 绘制路径

    CGContextDrawPath(context, kCGPathFillStroke);

}

#pragma mark - 绘制线性渐变  裁剪

-(void)drawLinearGradient{

    // 在计算机中直接选RGB即可 其他的颜色空间暂时不做考虑

    // 1. 创建色彩空间上下文 注意这里用的 create 所以后面得要release

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    

    // 2. 创建渐变的色彩组成

    /*

         参数说明:

                1: colorSpace 色彩空间 RGB

                2: components 数组 每四个元素一组  R G B A 

                3: location 表示渐变开始的位置 其值必须是0~1之间 如果不设置或者是无效值  系统会默认用0~1(此情况下components第一组元素为0 最后一组为中间那些为0~1之间主要作用是控制渐变色彩的长度和顺序  相当于把总长度当成1 每组对应的数值是其颜色起始点的位置

     */

    CGFloat components[12] = {

                              1.0,0.0,0.0,1.0,

                              0.0,1.0,1.0,1.0,

                              1.0,1.0,1.0,1.0

                              };

//    CGFloat locations[3] = {0.0,0.2,1.0};

    CGFloat locations[3] = {0.2,0.0,1.0};


    // 3. 创建渐变  注意这里用的 create 所以后面得要release

    CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, 3);

    

    // 渐变的区域裁剪

    /*

     *  提示: 整个渐变实际上是绘制在屏幕上的,通过裁剪区域,可以让指定范围内显示渐变效果 如果不裁剪区域 则在整个屏幕上显示渐变色彩

     */

    CGRect rects[5] = {

        CGRectMake(0, 0, 100, 100),

        CGRectMake(200, 0, 100, 100),

        CGRectMake(100, 100, 100, 100),

        CGRectMake(200, 200, 100, 100),

        CGRectMake(0, 200, 100, 100)

    };

    // 裁剪  后面画图能够显示的返回就是裁剪出来的范围  在图片裁剪上这个应用的很多  很重要 !!!

    CGContextClipToRects(UIGraphicsGetCurrentContext(), rects, 5);

    

    // 4. 通过上下文 绘制线性渐变

    CGContextDrawLinearGradient(UIGraphicsGetCurrentContext(), gradient, CGPointMake(0, 0), CGPointMake(320, 480), kCGGradientDrawsAfterEndLocation);

    

    // 5. 释放对像

    CGColorSpaceRelease(colorSpace);

    CGGradientRelease(gradient);

}

#pragma mark - 绘制径向渐变

-(void)drawRadialGradient{

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    

    CGFloat components[12]={

                            1.0,0.0,0.0,1.0,

                            0.0,1.0,1.0,1.0,

                            0.0,0.0,1.0,1.0

                           };

    CGFloat locations[3] = {0.0,0.6,1.0};

    

    // 这里也可以裁剪区域 本处没有裁剪

    

    CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, 3);

    

    // 绘制渐变

    /*

     1) context

     2) gradient

     3) startCenter 起始中心点

     4 startRadius 起始半径,如果指定为0,就从圆心开始渐变,否则,会空出指定半径的位置,不填充

     5 endCenter 截止点(通常和起始中心点重合,即便偏移,也不会太大)

     6 endRadius 截止半径

         在起始点和终止点重合的时候  起始点半径是 确定第一个色彩相对于圆点(起始点和终止点)出现的位置  终止点半径是 确定最后一个色彩出现的位置(最后一个色彩到终止点是纯色)

     7 渐变填充方式

     */

    CGContextDrawRadialGradient(UIGraphicsGetCurrentContext(), gradient, CGPointMake(160, 240), 160, CGPointMake(160, 240), 50, kCGGradientDrawsAfterEndLocation);

    

    CGColorSpaceRelease(colorSpace);

    CGGradientRelease(gradient);

    

}



注意:以上方法都是在一个继承自UIView的子类中操作的  也就是说 UIViewController里面这样 画图是画不出任何东西的(线,字符串,图片都画不出来) 但是其实他的操作还是进行了 


#pragma mark - ViewController  绘制图片水印

@interface ImageWaterMarkVC (){

    UIImageView * imgV;

}

@end


@implementation ImageWaterMarkVC


- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view.

    UIButton * btn =[[UIButton alloc] initWithFrame:CGRectMake(100, 0, 150, 50)];

    btn.backgroundColor=[UIColor lightGrayColor];

    [btn setTitle:@"给图片加水印" forState:UIControlStateNormal];

    [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:btn];

    

    UIImage * img = [UIImage imageNamed:@"NatGeo01.png"];

    imgV = [[UIImageView alloc] initWithFrame:CGRectMake(0, 80, 320, 200)];

    imgV.image = img;

    [self.view addSubview:imgV];

    

}

-(void)btnClick:(UIButton*)sender{

//    UIImage * newImage = [self waterMarkImage:imgV.image WithTitle:@"FromWK"];

    UIImage * newImage = [self waterMarkImageView:imgV withTitle:@"FromWK"];

    NSLogSize(newImage.size);

    imgV.image = newImage;

    

}

// 使用这个方法涉及到 像素-->-->像素 返回的像素和原来一样 那么画上的水印在@2x上会缩小一倍(12像素) 因此不如直接都用点来进行操作不涉及像素的问题 也就是直接用imageView自身的点数来进行操作

-(UIImage*)waterMarkImage:(UIImage*)img WithTitle:(NSString*)title{

    UIImage * newImage = nil;

   // img.size 是直接把像素点按照11还算成点的  后面的操作都是针对点

    CGSize imageSize = img.size;

    

    // 1. 建立图像的上下文,需要指定新生成的图像大小

    UIGraphicsBeginImageContext(imageSize);

    // 2. 选择要显示图片的类容大小  drawInRect: 最终的图片的大小是此Rect的大小 但是有效(有image图像)的部分 是根据图片本身的大小以及图片相对于此Rect x y 坐标 如下面的 00

    [img drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];

    

    // 3. 画上要添加的水印 注意因为此处用到的是点操作

    [title drawInRect:CGRectMake(20, imageSize.height-30, imageSize.width-40, 30) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17],NSForegroundColorAttributeName:[UIColor redColor]}];

    /*

     * 注意:

     *       在经过 2 3 之后  图片或者title都不会在当前的view中显示出来 但是他们对图片进行的操作还是进行了 

     *       这主要是因为当前的环境是在一个viewController 而导致的  

     *       如果是在一个继承自UIView的子视图中执行这些操作的话 图片或者title都会显示出来

     */

    

    // 4. 取得经过这样画图后的新图片

    newImage = UIGraphicsGetImageFromCurrentImageContext();

    // 5. 关闭图像上下文 释放内存

    UIGraphicsEndImageContext();

    

    // 返回的 newImage 又把点操作1:1的替换成了像素 这样就导致了一个问题 就是你画上去的水印如果显示在@2x屏幕上会缩小一倍 如果是@3x为缩小三倍

    return newImage;

}

// 直接用点数进行操作

-(UIImage*)waterMarkImageView:(UIImageView*)imgView withTitle:(NSString *)title{

    UIImage * newImage = nil;

    // 直接用需要显示在的imageView的点来进行操作

    CGSize imageSize = imgView.frame.size;

    

    UIGraphicsBeginImageContext(imageSize);

    [imgView.image drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];

    [title drawInRect:CGRectMake(20, imageSize.height-30, imageSize.width-40, 30) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17],NSForegroundColorAttributeName:[UIColor redColor]}];

  

    newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    

    return newImage;


}


#pragma mark 模仿备忘录中的背景效果  背景平铺(一行一行的平铺)

@implementation MemoBackgroundVC


- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view.

    [self.view setBackgroundColor:[UIColor colorWithPatternImage:[self createMemoBackgroundImage]]];

}

-(UIImage*)createMemoBackgroundImage{

    UIImage * cellImage = nil;

    

    // 1. 图像上下文

    UIGraphicsBeginImageContext(CGSizeMake(320, 46));

    

    // 2. 画图

    //    1 画背景的矩形

    [[UIColor yellowColor] set];

    UIRectFill(CGRectMake(0, 0, 320, 46));

    //    2 画底部的灰线

    [[UIColor lightGrayColor] set];

    UIRectFill(CGRectMake(0, 44.5, 320, 1.5));

    

    // 3. 取得图片

    cellImage = UIGraphicsGetImageFromCurrentImageContext();

    

    // 4. 关闭上下文  释放内存

    UIGraphicsEndImageContext();

    

    // 5. 返回图像

    return cellImage;

}

@end


#pragma mark PDF格式文件

- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view.

    [self createPDFFile];

}

-(void)createPDFFile{

    // 1. 取得存储路径

    NSString * path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"123.PDF"];

    NSLog(@"%@",path);

    

    // 2. 创建PDF上下文

        /*

         1) path 保存pdf文件的路径

         2) bounds 大小如果指定CGRectZero,则建立612 * 792大小的页面

         3) documentInfo 文档信息

         */

    UIGraphicsBeginPDFContextToFile(path, CGRectZero, NULL);

    

    // 3. 创建PDF内容

    /*

     *  PDF中是分页的,要一个页面一个页面的创建

     *  使用 UIGraphicsBeginPDFPage 方法可以创建一个PDF的页面

     */

    for (int i =0 ; i < 6; i++) {

        // 1 创建PDF页面 每页的装载数量是有限的  此图片的大小为 640 × 400像素 所以在默认的页面中只能装两张图片

        //     每添加两张图片后 需要重新建立一个页面

        if (i%2) {

            UIGraphicsBeginPDFPage();

        }

        

        // 2) Image添加到PDF文件

        NSString * imageName = [NSString stringWithFormat:@"NatGeo%02d",i+1];

        UIImage * img = [UIImage imageNamed:imageName];

        [img drawInRect:CGRectMake(0, (i%2)*396, 612, 396)];

    }

    

    // 4. 关闭PDF上下文 释放内存

    UIGraphicsEndPDFContext();

    

}


#pragma mark 屏幕截图

  1. + (instancetype)captureWithView:(UIView *)view  
  2. {  
  3.     // 1.开启上下文  
  4.     UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 0.0);  
  5.       
  6.     // 2.将控制器viewlayer渲染到上下文  
  7.     [view.layer renderInContext:UIGraphicsGetCurrentContext()];  
  8.       
  9.     // 3.取出图片  
  10.     UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();  
  11.       
  12.     // 4.结束上下文  
  13.     UIGraphicsEndImageContext();  
  14.       
  15.     return newImage;  

如果一个继承自UIView的MyView 显示在了ViewController中   MyView包含了一个 画上去的字符串  需要在ViewController中来改变MyView显示(这个画上去的字符串)的内容和字体大小 那么 

1. MyView需要有连个属性 一个是字符串 另一个是字符串大小  

2. 需要重写MyView的这两个属性的set方法 在方法里加上 [self setNeedsDisplay]; 这个方法的调用 来实时的刷新MyView的显示


CGBitmapContextCreate函数参数详解

函数原型:

CGContextRef CGBitmapContextCreate (

   void *data,      指向要渲染的绘制内存的地址                         

   size_t width,   bitmap的宽度,单位为像素

   size_t height,  bitmap的高度,单位为像素

   size_t bitsPerComponent,            内存中像素的每个组件的位数.例如,对于32位像素格式和RGB 颜色空间,你应该将这个值设为8

   size_t bytesPerRow,                     bitmap的每一行在内存所占的字节数

   CGColorSpaceRef colorspace,     bitmap上下文使用的颜色空间

   CGBitmapInfo bitmapInfo              指定bitmap是否包含alpha通道,像素中alpha通道的相对位置,像素组件是整形还是浮点型等信息的字符串。

)

描述:创建一个位图的上下文  此上下文向一个位图绘制图像  该位图的宽高是以像素为单位的   

      每个像素的组件个数是通过space来指定的 当然space可能也指定了一个目标颜色的配置文件   

      每个像素的每个组件的位数是通过 bitsPerComponent 来指定的    

      每个像素的字节数 = (每个像素的每个组件的位数   * 每个像素的组件的个数 +7 / 8     (一个字节一般是八位)    

      位图的每一行 bytesPerRow个字节组成  bytesPerRow >=  width * 每个像素的字节数  此外 bytesPerRow 必须是每个 像素字节数的整数倍    

  data 如果不为空  那么他指向的内存块至少是  bytesPerRow * 高度个字节    

                        如果为空 上下文的字节数空间将会自动被创建和销毁  并且 bytesPerRow 应该传递参数0来让系统自动计算内存空间

     bitmapInfo 位图信息 指定是否本位图应该包含一个透明图的通道以及他是如和     生成的 还有就是组件是浮点型还是整型


位图: 是由像素组成要有足够多的不同色彩的像素,就可以制作出色彩丰富的图象,逼真地表现自然界的景象,缩放和旋转容易失真,同时文件容

    量较大, 位图颜色的编码有 RGB(屏幕显示) CMYK等  其图像属性有  索引颜色/颜色表 Alpha通道 色彩深度 

矢量图像:是由数学向量组成文件容量较小,在进行放大、缩小或旋转等操作时图象不会失真,不易制作色彩变化太多的图象


当你调用这个函数的时候,Quartz创建一个位图绘制环境,也就是位图上下文。当你向上下文中绘制信息时,Quartz把你要绘制的信息作为位图数据绘制到指定的内存块。一个新的位图上下文的像素格式由三个参数决定:每个组件的位数,颜色空间,alpha选项。alpha值决定了绘制像素的透明性


  1.  iOS7以前,是使用如下方法创建的  
  2. CG_EXTERN CGContextRef CGBitmapContextCreate(voidvoid *data, size_t width,  
  3.   size_t height, size_t bitsPerComponent, size_t bytesPerRow,  
  4.   CGColorSpaceRef space,CGImageAlphaInfo bitmapInfo)  

注意最后一个参数类型是 CGImageAlphaInfo 枚举类型中的kCGImageAlphaPremultipliedLast值。其整型值为1

  1. typedef CF_ENUM(uint32_t, CGImageAlphaInfo)   
  2.  
  3.   kCGImageAlphaNone,               /* For example, RGB. */  
  4.   kCGImageAlphaPremultipliedLast,  /* For example, premultiplied RGBA */  
  5.   kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */  
  6.   kCGImageAlphaLast,               /* For example, non-premultiplied RGBA */  
  7.   kCGImageAlphaFirst,              /* For example, non-premultiplied ARGB */  
  8.   kCGImageAlphaNoneSkipLast,       /* For example, RBGX. */  
  9.   kCGImageAlphaNoneSkipFirst,      /* For example, XRGB. */  
  10.   kCGImageAlphaOnly                /* No color data, alpha data only */  
  11. };


  1. 但是在iOS7版本中,这个最后的参会类型发生了变化。看一下定义:  
  2. CGContextRef CGBitmapContextCreate(voidvoid *data, size_t width,  
  3.   size_t height, size_t bitsPerComponent, size_t bytesPerRow,  
  4.   CGColorSpaceRef space, CGBitmapInfo bitmapInfo)  
  5. 很明显最后一个参数由CGImageAlphaInfo 变化为 CGBitmapInfo看一下这个类型的定义 
  1. typedef CF_OPTIONS(uint32_t, CGBitmapInfo)  
  2.  {  
  3.   kCGBitmapAlphaInfoMask = 0x1F,  
  4.   kCGBitmapFloatComponents = (1 << 8),  
  5.   kCGBitmapByteOrderMask = 0x7000,  
  6.   kCGBitmapByteOrderDefault = (0 << 12),  
  7.   kCGBitmapByteOrder16Little = (1 << 12),  
  8.   kCGBitmapByteOrder32Little = (2 << 12),  
  9.   kCGBitmapByteOrder16Big = (3 << 12),  
  10.   kCGBitmapByteOrder32Big = (4 << 12)    
  11. } CF_ENUM_AVAILABLE(10_4, 2_0);  
  12. 头到尾没有发现值为1的枚举量值故在使用的时候会出现如下警告: 

Implicit conversion from enumeration type 'enum CGImageAlphaInfo' to different enumeration type 'CGBitmapInfo' (aka 'enum CGBitmapInfo')  

  1. 意思很明显不过,类型不匹配非法。  
  2. 以下给出解决方法: 

  第一种方法,定义宏: 

   #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1  

  1.      #define kCGImageAlphaPremultipliedLast  (kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast)  
  2.    #else   
  3.      #define kCGImageAlphaPremultipliedLast  kCGImageAlphaPremultipliedLast  
  4.    #endif  

这样就会直接映射出一个值为1的宏,原有方法不用改变


  1.  第二种方法:原理和第一个一样,目的 还是为了生产出一个为1的值,直接修改代码。  
  2.    #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1  
  3.          int bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast;  
  4.    #else  
  5.          int bitmapInfo = kCGImageAlphaPremultipliedLast;  
  6.    #endif    
  7.     CGContextRef context = CGBitmapContextCreate(nilCGContexWith*2, 290.0*2, 8, 4*CGContexWith*2, colorSpace, bitmapInfo);  
  8. 其实所有的做法,不外乎为了使这里的值为1,类型匹配。你也直接可以传1,不用麻烦的各种写代码。也可以直接进行类型强制转换,这个你随便。只是每个人的习惯不一样,故,如何解决,自己参考决定 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值