IOS-绘图API(超详细)

作者: 树下敲代码的超人 | 来源:发表于2018-01-24 15:46 被阅读5063次

    技 术 文 章 / 超 人


    实践才是学习和理解的最佳途径。请边看文章边动手写代码验证结果,这样才能有效理解。加油!!!


    iOS绘图以及图形处理的API有两套:
    Core Graphics/QuartZ 2D:Core Graphics是基于C的一套框架,使用了Quartz作为绘图引擎,所有基于Core Graphics的API都必须在视图的上下文中进行操作,QuartZ 2D是苹果公司开发的一套API,它是Core Graphics Framework的一部分。
    OpenGL ES:OpenGL ES是跨平台的图形API,属于OpenGL的一个简化版本,OpenGL ES是应用程序编程接口,描述了方法、结构、函数应具有的一些列行为以及应该如何被使用的API。也就是说它只是定义了一套规范,具体的实现由我们自己根据它制定规范去按步骤做,纯C语言。

    Core Graphics和OpenGL ES只是两套绘图框架,但是所有的绘图操作都只能在当前的上下文中进行。所以必须要获取到当前视图的上下文后,在视图上下文中选择两套框架进行绘图操作,才会正确显示在视图中

    获取上下文的方式

    • 1.UIGraphicsBeginImageContextWithOptions和UIGraphicsEndImageContext是成对出现的,函数块内就是在当前上下文中进行绘制的
    UIGraphicsBeginImageContextWithOptions(CGMake(100,100),NO,0);
    //
    //这里执行绘图操作,UIGraphicsBeginImageContextWithOptions与UIGraphicsGetImageFromCurrentImageContext函数块内部就是在当前上下文进行操作的
    //
    
    //当绘制完成后,需要从当前上下文中获取绘制的内容,而这个内容是一个UIImage对象
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();//关闭图形上下文
    

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100),NO,0);
    获得用来处理图片的图形上下文,函数不仅仅是创建了一个适用于图形操作的上下文,并且该上下文也属于当前上下文。
    参数说明:
    第一个参数表示所要创建的图片的尺寸
    第二个参数用来指定所生成图片的背景是否为不透明,如上我们使用YES而不是NO,则我们得到的图片背景将会是黑色,显然这不是我想要的
    第三个参数指定生成图片的缩放因子,这个缩放因子与UIImage的scale属性所指的含义是一致的。传入0则表示让图片的缩放因子根据屏幕的分辨率而变化,所以我们得到的图片不管是在单分辨率还是视网膜屏上看起来都会很好

    • 2.drawRec:方法

    一旦drawRect:方法被调用,Cocoa就会为你创建一个图形上下文,此时你对图形上下文的所有绘图操作都是在当前View的上下文中 。

    //每个继承自View的类都包含该方法,可以进行继承该方法来获取当前视图上下文
    - (void) drawRect: (CGRect) rect {
    //
    //这里可以直接进行绘图操作
    //
    }
    
    • 3.UIGraphicsPushContext和UIGraphicsPopContext是成堆出现的,使用UIGraphicsPushContext来转换已有上下文为当前上下文
    //ctx为已拥有的上下文,必须传入一个CGContextRef的上下文,使用UIGraphicsPushContext把传入的上下文转换为当前View的上下文
    UIGraphicsPushContext(ctx);
    //
    //这里进行绘图操作,所有操作的内容都是在当前View的上下文中执行的
    //
    
    //绘制完成后,需要把转换的上下文恢复,UIGraphicsPopContext函数恢复上下文环境
    UIGraphicsPopContext();
    

    以上三种都是获取当前上下文的方式,而绘图的API有两种(Core Graphics和OpenGL ES)。这样就有6种绘制的方式。

    CGContextSaveGState和CGContextRestoreGState函数对

    CGContextSaveGStateCGContextRestoreGState是成对出现的。
    CGContextSaveGState函数会将传入用于绘制的上下文状态压栈栈顶,并保存传入时的上下文所有状态。
    CGContextRestoreGState函数会将当前的上下文状态恢复到传入的上下文保存时的状态
    在很多时候,我们需要去修改当前上下文绘制的属性,来满足需求。
    例如:假如当前上下文默认绘制是黑色的画笔宽度是2,而我们需要先绘制一个绿色且宽度为10的线,然后需要绘制一个绿色且宽度为5的线。这其中就涉及到来修改上下文绘制的画笔颜色和画笔宽度属性,以及恢复上下文属性。

        __weak typeof(self) weakSelf = self;
        CGRect frame = self.testImageView.frame;
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            
            /* 1.设置当前上下文中绘制的区域 */
            UIGraphicsBeginImageContextWithOptions(frame.size, NO, 0);
            /* 2.获取当前上下文 */
            CGContextRef context = UIGraphicsGetCurrentContext();
            
            /* 2.修改当前上下文的画笔颜色和宽度 */
            CGContextSetLineWidth(context, 2);
            [[UIColor blackColor] setStroke];
            
            /* 3.保存当前上下文的状态 */
            CGContextSaveGState(context);
            
            /* 绘制一个圆 */
            CGContextAddEllipseInRect(context, CGRectMake(0, 0, frame.size.width, frame.size.height));
            /* 设置画笔颜色和宽度 */
            CGContextSetLineWidth(context, 10);
            [[UIColor greenColor] setStroke];
            /* 开始绘制 */
            CGContextStrokePath(context);
            
            
            /* 绘制一个圆 */
            CGContextAddEllipseInRect(context, CGRectMake(10, 10, frame.size.width-20, frame.size.height-20));
            /* 设置画笔颜色和宽度 */
            CGContextSetLineWidth(context, 5);
            [[UIColor orangeColor] setStroke];
            /* 开始绘制 */
            CGContextStrokePath(context);
            
            /* 恢复当前上下文的状态 */
            CGContextRestoreGState(context);
            /* 绘制一个圆 */
            CGContextAddEllipseInRect(context, CGRectMake(20, 20, frame.size.width-40, frame.size.height-40));
            /* 不设置画笔颜色和宽度,因为原本的上下文有颜色和宽度状态 */
            /* 开始绘制 */
            CGContextStrokePath(context);
            
            /* 从当前上下文中获取绘制的内容 */
            UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
            /* 关闭上下文 */
            UIGraphicsEndImageContext();
            dispatch_async(dispatch_get_main_queue(), ^{
                weakSelf.testImageView.image = image;
            });
        });
    
    image.png

    注意点:

    • 1.CGImage的绘制和创建会出现图片颠倒:Core Graphics是源于Mac OS系统的,在IOS中,坐标原点是在左上角,正Y坐标是朝向下方的(这也是为什么我们给控件设置X,Y时相对于坐标原点都用的正数)。而在Mac OS系统下坐标原点是在左下角并且正Y坐标是朝向上方的。在大多数情况下,不会出现问题,因为图形上下文会自动调整,但是创建和绘制CGImageRef对象时就会出现颠倒,因为CGImageRef是源于Mac OS的。

    接口说明

    CGImageCreateWithImageInRect(<#CGImageRef _Nullable image#>, <#CGRect rect#>)
    说明:根据指定范围截图图片区域,获得一个新的图片,获得的图片是CGImageRef类型的CGImageRef newImageRef = CGImageCreateWithImageInRect(imageRef,size);
    参数1:需要截取的原图CGImageRef类型
    参数2:截取的区域
    注意:该接口ARC无效,获得的图片需要手动释放。CGImageRelease(newImageRef)

    CGContextDrawImage(<#CGContextRef _Nullable c#>, <#CGRect rect#>, <#CGImageRef _Nullable image#>)
    说明:在当前的上下文中把图片内容绘制到指定区域
    参数1:内容上下文
    参数2:绘制的区域
    参数3:需要绘制上去的图片,CGImageRef类型

    drawAtPoint:<#(CGPoint)#>
    说明:该方法是UIImage类的对象方法,用于把当前图片按照指定的抛锚点在当前上下文中开始绘制。
    参数1:图片开始绘制的起始点

    例子:

    UIImage *image = [UIImage new];
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(image.size.width, image.size.height), NO, 0);
    [image drawAtPoint:CGPoint(0,0)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    

    drawInRect:<#(CGRect)#>
    说明:该方法是UIImage类的对象方法,用于把当前图片按照指定Rect在当前上下文中绘制,可以缩放可以位移。用法与drawAtPoint一样
    参数1:指定的绘制Rect

    imageWithCGImage:<#(nonnull CGImageRef)#> scale:<#(CGFloat)#> orientation:<#(UIImageOrientation)#>
    说明:该方法是UIImage的类方法,用于把CGImageRef类型的图片 按照scale与方向转换成对应的UIImage对象。
    参数1:需要转换的CGImageRef类型的图片
    参数2:图片的比例
    参数3:图片的方向
    UIImageOrientationUp, //默认方向

    默认方向
    UIImageOrientationDown,// 180 度旋转,向下
    180度旋转向下
    UIImageOrientationLeft,//向左90度旋转
    向左90度旋转
    UIImageOrientationRight,//向右90 度旋转
    向右90 度旋转
    UIImageOrientationUpMirrored, //按照图片镜像样子水平旋转
    按照图片镜像样子水平旋转
    UIImageOrientationDownMirrored, // 水平翻转
    水平翻转
    UIImageOrientationLeftMirrored, //向左垂直翻转
    向左垂直翻转
    UIImageOrientationRightMirrored, //向右垂直翻转
    向右垂直翻转

    1.CGContextSetLineWidth(设置线条的宽度)
    例子:CGContextSetLineWidth(context, 10);
    参数1:设置的上下文
    参数2:设置的线条宽度

    2.CGContextSetLineDash(设置线条是否有虚线)
    例子:
    CGFloat lengths = {10,5};
    CGContextSetLineDash(context, 2,lengths, 2);
    参数1:设置的上下文
    (参数2最后说)
    参数3:lengths = {10,5},先画10点长度,在空5的长度。依次重复
    参数4:参数3的count数
    参数2:因为参数3设置的lengths = {10,5},首先会画10个点的长度,而参数2设置为2后,首个长度会画10-2的长度。后面的正常画不会减2

    3.CGContextSetLineCap(线条两端的样式)
    例子:CGContextSetLineCap(context, kCGLineCapButt);
    参数1:设置的上下文
    参数2:样式
    kCGLineCapButt, //该属性值指定不绘制端点, 线条结尾处直接结束。这是默认值
    kCGLineCapRound, //该属性值指定绘制圆形端点, 线条结尾处绘制一个直径为线条宽度的半圆
    kCGLineCapSquare ,//该属性值指定绘制方形端点。线条结尾处绘制半个边长为线条宽度的正方形。需要说明的是,这种形状的端点与“butt”形状的端点十分相似,只是采用这种形式的端点的线条略长一点而已

    4.CGContextSetLineJoin(设置线条转角的样式)
    例子:CGContextSetLineJoin(context, kCGLineJoinRound);
    参数1:上下文
    参数2:样式,可以与CGContextSetLineCap的样式一样或
    kCGLineJoinMiter,//全部链接
    kCGLineJoinRound,//圆角链接
    kCGLineJoinBevel,//斜角链接

    样式

    5.CGContextSetMiterLimit(设置图像上下文中的连接线的斜接限制)
    参数1:上下文
    参数2:斜接角的限制
    例如:
    //设置一个限制角为20
    CGContextMoveToPoint(context,10,10);
    CGContextAddLineToPoint(context, 50, 50);
    CGContextAddLineToPoint(context, 10, 90);
    CGContextSetLineWidth(context, 10.0);
    CGContextSetLineJoin(context, kCGLineJoinMiter);
    CGContextSetMiterLimit(context,20.0);
    CGContextStrokePath(context);
    //设置一个限制角为1
    CGContextMoveToPoint(context,10,10);
    CGContextAddLineToPoint(context, 50, 50);
    CGContextAddLineToPoint(context, 10, 90);
    CGContextSetLineWidth(context, 10.0);
    CGContextSetLineJoin(context, kCGLineJoinMiter);
    CGContextSetMiterLimit(context,1.0);
    CGContextStrokePath(context);

    例子

    6.CGContextSetRGBStrokeColor(设置RGB的画线颜色)、CGContextSetRGBFillColor(设置RGB的填充颜色)
    例子:CGContextSetRGBStrokeColor(context, 255, 255, 255, 1);
    参数1:上下文
    参数2:red 颜色值
    参数3:green 颜色值
    参数4:blue 颜色值
    参数5:透明度值

    ** CGContextSetStrokeColorWithColor(根据CGColo设置画线颜色)、CGContextSetFillColorWithColor(根据CGColo设置填充颜色)**
    例子:CGContextSetStrokeColorWithColor(context,[UIColor blue].CGColor);
    参数1:上下文
    参数2:颜色值

    8. CGContextSetGrayStrokeColor(设置灰色画线颜色)、CGContextSetGrayFillColor(设置灰色填充颜色)

    例子:CGContextSetGrayStrokeColor(context,1,1);
    参数1:上下文
    参数2:灰色值
    参数3:透明度

    9. CGContextSetStrokePattern(在指定的图形上下文设置描边模版)、CGContextSetFillPattern(在指定的图形上下文设置填充模版)
    参数1:上下文
    参数2:模式
    参数3:如果指定的图案是无色(或蒙版)图案,则传递指定要在绘制图案时使用的颜色的亮度值数组。数组元素的数量必须等于笔画图案颜色空间的基本空间中的组件数量,以及alpha值的附加组件。如果指定的图案是彩色图案,则传递一个alpha值

    #pragma mark - 有颜色填充模式
    #define TILE_SIZE 20
    void drawColoredTile(void *info,CGContextRef context){
        //有颜色填充,这里设置填充色
        CGContextSetRGBFillColor(context, 254.0/255.0, 52.0/255.0, 90.0/255.0, 1);
        CGContextFillRect(context, CGRectMake(0, 0, TILE_SIZE, TILE_SIZE));
        CGContextFillRect(context, CGRectMake(TILE_SIZE, TILE_SIZE, TILE_SIZE, TILE_SIZE));
    }
    -(void)drawBackgroundWithColoredPattern:(CGContextRef)context{
        //1.设置非指定填充区域以外的空间的颜色填充值
        //CGColorSpaceRef rgbSpace= CGColorSpaceCreateDeviceRGB();
        //模式填充颜色空间,注意对于有颜色填充模式,这里传NULL
        CGColorSpaceRef colorSpace=CGColorSpaceCreatePattern(NULL);
        //将填充色颜色空间设置为模式填充的颜色空间
        CGContextSetFillColorSpace(context, colorSpace);
        
        //填充模式回调函数结构体
        CGPatternCallbacks callback={0,&drawColoredTile,NULL};
        /*填充模式
         info://传递给callback的参数
         bounds:瓷砖大小
         matrix:形变
         xStep:瓷砖横向间距
         yStep:瓷砖纵向间距
         tiling:贴砖的方法
         isClored:绘制的瓷砖是否已经指定了颜色(对于有颜色瓷砖此处指定位true)
         callbacks:回调函数
         */
        CGPatternRef pattern=CGPatternCreate(NULL, CGRectMake(0, 0, 2*TILE_SIZE, 2*TILE_SIZE), CGAffineTransformIdentity,2*TILE_SIZE+ 5,2*TILE_SIZE+ 5, kCGPatternTilingNoDistortion, true, &callback);
        
        CGFloat alpha=1;
        //注意最后一个参数对于有颜色瓷砖指定为透明度的参数地址,对于无颜色瓷砖则指定当前颜色空间对应的颜色数组
        CGContextSetFillPattern(context, pattern, &alpha);
        
        UIRectFill(CGRectMake(0, 0, 320, 568));
        
    //    CGColorSpaceRelease(rgbSpace);
        CGColorSpaceRelease(colorSpace);
        CGPatternRelease(pattern);
    }
    
    
    #pragma mark - 无颜色填充模式
    //填充瓷砖的回调函数(必须满足CGPatternCallbacks签名)
    void drawTile(void *info,CGContextRef context){
        CGContextFillRect(context, CGRectMake(0, 0, TILE_SIZE, TILE_SIZE));
        CGContextFillRect(context, CGRectMake(TILE_SIZE, TILE_SIZE, TILE_SIZE, TILE_SIZE));
    }
    -(void)drawBackgroundWithPattern:(CGContextRef)context{
        //设备无关的颜色空间
        CGColorSpaceRef rgbSpace= CGColorSpaceCreateDeviceRGB();
        //模式填充颜色空间
        CGColorSpaceRef colorSpace=CGColorSpaceCreatePattern(rgbSpace);
        //将填充色颜色空间设置为模式填充的颜色空间
        CGContextSetFillColorSpace(context, colorSpace);
        
        //填充模式回调函数结构体
        CGPatternCallbacks callback={0,&drawTile,NULL};
        /*填充模式
         info://传递给callback的参数
         bounds:瓷砖大小
         matrix:形变
         xStep:瓷砖横向间距
         yStep:瓷砖纵向间距
         tiling:贴砖的方法(瓷砖摆放的方式)
         isClored:绘制的瓷砖是否已经指定了颜色(对于无颜色瓷砖此处指定位false)
         callbacks:回调函数
         */
        CGPatternRef pattern=CGPatternCreate(NULL, CGRectMake(0, 0, 2*TILE_SIZE, 2*TILE_SIZE), CGAffineTransformIdentity,2*TILE_SIZE+ 5,2*TILE_SIZE+ 5, kCGPatternTilingNoDistortion, false, &callback);
        
        CGFloat components[]={254.0/255.0,52.0/255.0,90.0/255.0,1.0};
        //注意最后一个参数对于无颜色填充模式指定为当前颜色空间颜色数据
        CGContextSetFillPattern(context, pattern, components);
        //    CGContextSetStrokePattern(context, pattern, components);
        UIRectFill(CGRectMake(0, 0, 320, 568));
        
        CGColorSpaceRelease(rgbSpace);
        CGColorSpaceRelease(colorSpace);
        CGPatternRelease(pattern);
    }
    

    补充说明:CGPatternCreate模版
    例子: CGPatternRef pattern=CGPatternCreate(NULL, CGRectMake(0, 0, 2TILE_SIZE, 2TILE_SIZE), CGAffineTransformIdentity,2TILE_SIZE+ 5,2TILE_SIZE+ 5, kCGPatternTilingNoDistortion, false, &callback);
    说明:一个模板是在一个矩形元中的绘图。我们需要矩形元的尺寸(第二个参数)以及矩形元原始点之间的间隙(第四和第五个参数)。这这种情况下,矩形元是4*4的,每一个矩形元与它的周围矩形元是紧密贴合的。我们需要提供一个应用到矩形元的变换参数(第三个参数);在这种情况下,我们不需要变换做什么工作,所以我们应用了一个恒等变换。我们应用了一个瓷砖规则(第六个参数)。我们需要声明的是颜色模板不是漏印(stencil)模板,所以参数值为true。并且我们需要提供一个指向回调函数的指针,回调函数的工作是向矩形元绘制模板。第八个参数是一个指向CGPatternCallbacks结构体的指针。这个结构体由数字0和两个指向函数的指针构成。第一个函数指针指向的函数当模板被绘制到矩形元中被调用,第二个函数指针指向的函数当模板被释放后调用。第二个函数指针我们没有指定,它的存在主要是为了内存管理的需要。但在这个简单的例子中,我们并不需要。
    参数6:平铺模式
    kCGPatternTilingNoDistortion没有失真: 以细微调整模式单元格之间的间距为代价,但通常不超过一个设备像素。
    kCGPatternTilingConstantSpacingMinimalDistortion最小的失真的恒定间距:设定单元格之间的间距,以细微调整单元大小为代价,但通常不超过一个设备像素。
    kCGPatternTilingConstantSpacing恒定间距:设定单元格之间间距,以调整单元格大小为代价,以求尽快的平铺

    10.CGContextSetShadow(设置阴影)、CGContextSetShadowWithColor(指定阴影颜色设置阴影)
    参数1:图形上下文
    参数2:offset:偏移量
    参数3:blur:模糊度
    参数4:color:阴影颜色
    例子:

        //颜色转化,由于Quartz 2D跨平台,所以其中不能使用UIKit中的对象,但是UIkit提供了转化方法
        CGColorRef color = [UIColor grayColor].CGColor;
        CGContextSetShadowWithColor(context, CGSizeMake(2, 2), 0.8, color);
    

    11.CGContextSetBlendMode(设置混合模式)
    决定你当前绘制的图形与已经存在的图形如何被合成
    例子:CGContextSetBlendMode(context, kCGBlendModeNormal);
    参数1:上下文

    参数2:模式
    kCGBlendModeNormal,//默认的模式。前景图会覆盖背景图
    kCGBlendModeMultiply,//混合了前景和背景的颜色,最终颜色比原先的都暗
    kCGBlendModeScreen,//滤色;把前景和背景图的颜色先反过来,然后混合
    kCGBlendModeOverlay,//覆盖;能保留灰度信息,结合kCGBlendModeSaturation能保留透明度信息,在imageWithBlendMode方法中两次执行drawInRect方法实现我们基本需求
    kCGBlendModeDarken,//变暗
    kCGBlendModeLighten,//变亮
    kCGBlendModeColorDodge,//颜色变淡
    kCGBlendModeColorBurn,//颜色加深
    kCGBlendModeSoftLight,//柔光
    kCGBlendModeHardLight,//强光
    kCGBlendModeDifference,//插值
    kCGBlendModeExclusion,//排除
    kCGBlendModeHue,//色调
    kCGBlendModeSaturation,//饱和度
    kCGBlendModeColor,//颜色
    kCGBlendModeLuminosity,//亮度
    //Apple额外定义的枚举
    //R: premultiplied result, 表示混合结果
    //S: Source, 表示源颜色(Sa对应透明度值: 0.0-1.0)
    //D: destination colors with alpha, 表示带透明度的目标颜色(Da对应透明度值: 0.0-1.0)
    kCGBlendModeClear,/* R = 0 / //
    kCGBlendModeCopy,/
    R = S /
    kCGBlendModeSourceIn,/
    R = SDa /
    kCGBlendModeSourceOut, /
    R = S
    (1 - Da) /
    kCGBlendModeSourceAtop, /
    R = SDa + D(1 - Sa) /
    kCGBlendModeDestinationOver,/
    R = S(1 - Da) + D /
    kCGBlendModeDestinationIn,/
    R = D
    Sa 能保留透明度信息 /
    kCGBlendModeDestinationOut,/
    R = D(1 - Sa) /
    kCGBlendModeDestinationAtop, /
    R = S
    (1 - Da) + DSa /
    kCGBlendModeXOR,/
    R = S
    (1 - Da) + D*(1 - Sa) /
    kCGBlendModePlusDarker, /
    R = MAX(0, (1 - D) + (1 - S)) */
    kCGBlendModePlusLighter,//R = MIN(1, S + D)(最后一种混合模式)

    12.CGContextSetAlpha(设置透明度)
    例子:CGContextSetAlpha(context, 1);
    参数2:透明度

    13.CGContextSetFont(设置字体)
    参数2:字体
    例子:

    CTFontRef ctFont = CTFontCreateWithName(CFSTR("STHeitiSC-Light"), 20.0, NULL);
    CTFontDescriptorRef ctFontDesRef = CTFontCopyFontDescriptor(ctFont);
    CGFontRef cgFont = CTFontCopyGraphicsFont(ctFont,&ctFontDesRef );
    CGContextSetFont(context, cgFont);
    

    14.CGContextSetFontSize(设置字体大小)
    例子:CGContextSetFontSize(context,10);
    参数2:字体大小值

    15.CGContextSetTextDrawingMode(设置当前文本的绘图模式)
    例子:CGContextSetTextDrawingMode(context, kCGTextFill);
    参数2:模式
    kCGTextFill,//填充
    kCGTextStroke,//描边
    kCGTextFillStroke,//描边填充
    kCGTextInvisible,//
    kCGTextFillClip,//
    kCGTextStrokeClip,//
    kCGTextFillStrokeClip,//
    kCGTextClip,//

    16.CGContextSetCharacterSpacing(设置当前字符间距)
    例子:CGContextSetCharacterSpacing(context, 5);
    参数2:间距值

    17.CGContextSetShouldAntialias(设置图形上下文的抗锯齿开启或关闭)
    例子:CGContextSetShouldAntialias(context, YES);
    参数2:是否开启抗锯齿

    18. CGContextSetShouldSmoothFonts(设置字体平滑)
    例子:CGContextSetShouldSmoothFonts(context, YES);
    参数2:是否开启字体平滑

    19. CGContextMoveToPoint(设置一个点)
    例子:CGContextMoveToPoint(context, 5, 5);
    参数2:X坐标
    参数3:Y坐标

    20. CGContextAddLineToPoint(在路径上画一条直线)
    例子:CGContextAddLineToPoint(context,10,10);
    参数2:X坐标
    参数3:Y坐标

    21.CGContextAddLines(添加一组直线)
    参数2:直线每个点的坐标数组
    参数3:数组中点的个数
    例子:

    CGPoint lines[] = {  
          CGPointMake(10.0, 90.0),  
    CGPointMake(70.0, 60.0),  
    CGPointMake(130.0, 90.0),  
    CGPointMake(190.0, 60.0),  
    CGPointMake(250.0, 90.0),  
    CGPointMake(310.0, 60.0),  
      }; 
    CGContextAddLines(context, lines, sizeof(lines)/sizeof(lines[0]));
    

    22.CGContextAddRect(添加一个矩形)、CGContextAddRects(添加一组矩形)
    参数2:矩形数组
    参数3:数组内矩形个数
    例子:

    CGRect rects[] = {
                CGRectMake(0, 0, 100, 100),
                CGRectMake(105, 0, 100, 100),
                CGRectMake(0, 105, 100, 100)
            };
    CGContextAddRects(context,rects,sizeof(rects)/sizeof(rects[0]));
    

    23.CGContextAddEllipseInRect(添加一个椭圆或圆形)
    例子:CGContextAddEllipseInRect(context, CGRectMake(0, 0, 100, 100));
    参数2:椭圆或者圆形的frame

    24.CGContextAddArc(添加一个圆弧)
    例子:CGContextAddArc(context, 160, 160, 100.0, 0.0, M_PI_2, 1);
    参数2:中心点x坐标
    参数3:中心点y坐标
    参数4:radius半径
    参数5:startAngle起始弧度
    参数6:endAngle:终止弧度
    参数7:closewise:是否逆时针绘制,0则顺时针绘制

    25.CGContextAddArcToPoint(绘制曲线)
    例子:CGContextAddArcToPoint(context, 50, 50, 100, 100, 25);
    参数2:波峰点的X值
    参数3:波峰点的Y值
    参数4:结尾点的X值
    参数5:结尾点的Y值
    参数6:曲线半径值

    26.CGContextAddQuadCurveToPoint(绘制二次贝塞尔曲线)
    例子:CGContextAddQuadCurveToPoint(context, 160, 0, 300, 100);
    参数2:控制点x坐标
    参数3:控制点y坐标
    参数4:结束点x坐标
    参数5:结束点y坐标

    27.CGContextAddCurveToPoint(绘制三次贝塞尔曲线)
    例子:CGContextAddCurveToPoint(context, 80, 300, 240, 500, 300, 300);
    参数2:第一个控制点x坐标
    参数3:第一个控制点y坐标
    参数4:第二个控制点x坐标
    参数5:第二个控制点y坐标
    参数6:结束点x坐标
    参数7:结束点y坐标

    贝塞尔曲线

    28.CGContextClosePath(关闭当前路径)
    例子:CGContextClosePath(context);

    29.CGContextStrokePath(给路径画线,当路径都设置好后使用该函数)
    例子:CGContextStrokePath(context);

    30.CGContextFillPath(填充当前路径,当封闭路径设置好后使用该函数填充)
    例子:CGContextFillPath(context);

    31.CGContextEOFillPath(根据奇偶来填充,当有多个封闭空间但是只有部分需要填充时)
    例子:CGContextEOFillPath(context);

    填充

    32.CGContextDrawPath(绘制图像到指定图形上下文)
    说明:对当前路径描边或填充会清除掉路径。如果你只想使用一条命令完成描边和填充任务,可以使用CGContextDrawPath命令,因为如果你只是使用CGContextStrokePath对路径描边,路径就会被清除掉,你就不能再对它进行填充了
    例子:CGContextDrawPath(context, kCGPathFillStroke);
    参数2:CGPathDrawingMode是填充方式,枚举类型

    kCGPathFill:只有填充(非零缠绕数填充),不绘制边框
    kCGPathEOFill:奇偶规则填充(多条路径交叉时,奇数交叉填充,偶交叉不填充)
    kCGPathStroke:只有边框
    kCGPathFillStroke:既有边框又有填充
    kCGPathEOFillStroke:奇偶填充并绘制边框
    

    33.CGContextStrokeLineSegments(绘制一些直线)
    参数2:直线中每个点的数组
    参数3:数组里点的个数
    例子:

    //绘制线段,points是点数组,两个点确定一条线,下面的数组有8个点,可以确定4条线段
        const CGPoint points[] = {CGPointMake(10, 30),CGPointMake(100, 30),CGPointMake(100, 30),CGPointMake(100, 100),CGPointMake(100, 100),CGPointMake(10, 100),CGPointMake(10, 100),CGPointMake(10, 30)};
        //绘制
        CGContextStrokeLineSegments(context, points, 8);
    

    34.CGContextStrokeRect(绘制矩形)
    例子:CGContextStrokeRect(context, CGRectMake(120, 100, 80, 50));
    参数2:矩形的frame

    35.CGContextStrokeRectWithWidth(指定矩形线宽)
    例子:CGContextStrokeRectWithWidth(context, CGRectMake(0, 0, 50, 100), 5);
    参数2:矩形的frame
    参数3:矩形的线宽值

    36.CGContextFillRect(填充矩形)
    例子:CGContextFillRect(context,CGRectMake(0, 0, 50, 100));
    参数2:矩形的frame

    37.CGContextFillRects(填充矩形组)
    参数2:每个矩形frame的数组
    参数3:数组内frame个数
    例子

    CGRect rects[] = {
                CGRectMake(0, 0, 50, 50),
                CGRectMake(55, 55, 105, 105),
                CGRectMake(110, 110, 160, 160);
            };
    CGContextFillRects(context, rects, 3);
    

    38.CGContextStrokeEllipseInRect(根据矩形尺寸绘制矩形内的椭圆);
    例子:CGContextStrokeEllipseInRect(context, CGRectMake(220, 30, 80, 50));
    参数2:矩形frame

    39.CGContextFillEllipseInRect(填充矩形内的椭圆)
    例子:CGContextFillEllipseInRect(context, CGRectMake(220, 30, 80, 50));
    参数2:frame

    40.CGContextBeginPath(开始一个新的路径)
    例子:CGContextBeginPath(context);

    41.CGContextClearRect(清除矩形区域)
    说明:函数的功能是擦除一个区域。这个函数会擦除一个矩形内的所有已存在的绘图;并对该区域执行裁剪。结果像是打了一个贯穿所有已存在绘图的孔。
    CGContextClearRect函数的行为依赖于上下文是透明还是不透明。当在图形上下文中绘图时,这会尤为明显和直观。如果图片上下文是透明的(UIGraphicsBeginImageContextWithOptions第二个参数为NO),那么CGContextClearRect函数执行擦除后的颜色为透明,反之则为黑色。
    例子:CGContextClearRect(context,CGRectMake(220, 30, 80, 50));
    参数2:需要清除区域的frame

    42. CGContextAddPath(添加路径到上下文)
    参数2: CGMutablePathRef路径对象
    例子:

    //创建路径
    CGMutablePathRef path = CGPathCreateMutable();
    CGContextAddPath(context,path);
    

    43.CGPathAddLineToPoint(绘制直线)
    说明:根据起点绘制一个直线
    例子:CGPathAddLineToPoint(path, nil, 20, 100);
    参数1:路径对象
    参数2:用于转移坐标的Transform
    参数3:结束点的X坐标
    参数4:结束点的Y坐标

        //创建用于转移坐标的Transform,这样我们不用按照实际显示做坐标计算
        // CGAffineTransform transform = CGAffineTransformMakeTranslation(50, 50);
        //1.创建路径对象
        CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, nil, 20, 50);//移动到指定位置(设置路径起点)
        CGPathAddLineToPoint(path, nil, 20, 100);//绘制直线(从起始位置开始)
        //CGPathAddLineToPoint(path, &transform, 20, 100);//绘制直线(从起始位置开始)
        CGPathAddLineToPoint(path, nil, 300, 100);//绘制另外一条直线(从上一直线终点开始绘制)
        //2.添加路径到图形上下文
        CGContextAddPath(context, path);
        //3.手动释放路径对象
        CGPathRelease(path);
    

    绘制线性和经向渐变

    typedef CF_OPTIONS (uint32_t, CGGradientDrawingOptions) {
      kCGGradientDrawsBeforeStartLocation = (1 << 0),
      kCGGradientDrawsAfterEndLocation = (1 << 1)
    };// 渐变选项
    
    作者:说了是村长
    链接:https://www.jianshu.com/p/a28bad3aaad1
    來源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    #pragma mark 线性渐变
    -(void)drawLinearGradient:(CGContextRef)context{
        //使用rgb颜色空间
        CGColorSpaceRef colorSpace=CGColorSpaceCreateDeviceRGB();
        
        /*指定渐变色
         space:颜色空间
         components:颜色数组,注意由于指定了RGB颜色空间,那么四个数组元素表示一个颜色(red、green、blue、alpha),
                    如果有三个颜色则这个数组有4*3个元素
         locations:颜色所在位置(范围0~1),这个数组的个数不小于components中存放颜色的个数
         count:渐变个数,等于locations的个数
         */
        CGFloat compoents[12]={
            248.0/255.0,86.0/255.0,86.0/255.0,1,
            249.0/255.0,127.0/255.0,127.0/255.0,1,
            1.0,1.0,1.0,1.0
        };
        CGFloat locations[3]={0,0.3,1.0};
        CGGradientRef gradient= CGGradientCreateWithColorComponents(colorSpace, compoents, locations, 3);
        
        /*绘制线性渐变
         context:图形上下文
         gradient:渐变色
         startPoint:起始位置
         endPoint:终止位置
         options:绘制方式,kCGGradientDrawsBeforeStartLocation 开始位置之前就进行绘制,到结束位置之后不再绘制,
                 kCGGradientDrawsAfterEndLocation开始位置之前不进行绘制,到结束点之后继续填充
         */
        CGContextDrawLinearGradient(context, gradient, CGPointZero, CGPointMake(320, 300), kCGGradientDrawsAfterEndLocation);
        
        //释放颜色空间
        CGColorSpaceRelease(colorSpace);
    }
    
    #pragma mark 径向渐变
    -(void)drawRadialGradient:(CGContextRef)context{
        //使用rgb颜色空间
        CGColorSpaceRef colorSpace=CGColorSpaceCreateDeviceRGB();
        
        /*指定渐变色
         space:颜色空间
         components:颜色数组,注意由于指定了RGB颜色空间,那么四个数组元素表示一个颜色(red、green、blue、alpha),
         如果有三个颜色则这个数组有4*3个元素
         locations:颜色所在位置(范围0~1),这个数组的个数不小于components中存放颜色的个数
         count:渐变个数,等于locations的个数
         */
        CGFloat compoents[12]={
            248.0/255.0,86.0/255.0,86.0/255.0,1,
            249.0/255.0,127.0/255.0,127.0/255.0,1,
            1.0,1.0,1.0,1.0
        };
        CGFloat locations[3]={0,0.3,1.0};
        CGGradientRef gradient= CGGradientCreateWithColorComponents(colorSpace, compoents, locations, 3);
        
        /*绘制径向渐变
         context:图形上下文
         gradient:渐变色
         startCenter:起始点位置
         startRadius:起始半径(通常为0,否则在此半径范围内容无任何填充)
         endCenter:终点位置(通常和起始点相同,否则会有偏移)
         endRadius:终点半径(也就是渐变的扩散长度)
         options:绘制方式,kCGGradientDrawsBeforeStartLocation 开始位置之前就进行绘制,但是到结束位置之后不再绘制,
                 kCGGradientDrawsAfterEndLocation开始位置之前不进行绘制,但到结束点之后继续填充
         */
        CGContextDrawRadialGradient(context, gradient, CGPointMake(160, 284),0, CGPointMake(165, 289), 150, kCGGradientDrawsAfterEndLocation);
        //释放颜色空间
        CGColorSpaceRelease(colorSpace);
    }
    

    设置context上下文属性

    [[UIColor greenColor]setStroke];//设置边框颜色
    [[UIColor greenColor]setFill];//设置填充颜色
    [[UIColor greenColor]set];//同时设置填充和边框色
    

    绘制文字

         /*  绘制文字1 */
        NSString *str=@"文本内容";
        CGRect rect= CGRectMake(20, 50, 280, 300);//绘制到指定的区域内容
        UIFont *font=[UIFont systemFontOfSize:18];//设置字体
        UIColor *color=[UIColor redColor];//字体颜色
        NSMutableParagraphStyle *style=[[NSMutableParagraphStyle alloc]init];//段落样式
        NSTextAlignment align=NSTextAlignmentLeft;//对齐方式
        style.alignment=align;
        [str drawInRect:rect withAttributes:@{NSFontAttributeName:font,NSForegroundColorAttributeName:color,NSParagraphStyleAttributeName:style}]
    
    

    绘制图形

        UIImage *image=[UIImage imageNamed:@"tu10"];
        //从某一点开始绘制
        [image drawAtPoint:CGPointMake(10, 50)];
        //绘制到指定的矩形中,注意如果大小不合适会会进行拉伸
        [image drawInRect:CGRectMake(10, 50, 300, 450)];
        //平铺绘制
        [image drawAsPatternInRect:CGRectMake(0, 0, 320, 568)];
    

    图片滤镜处理

    Core Image 是一个很强大的库,PS图片时用到的各种滤镜就是在这个库中。而我们创建二维码、创建条形码用这里的滤镜,只需要短短几行代码就可以撸出来。具体有那些滤镜可以查看这里看看有那些滤镜,目前IOS11有198种滤镜,Mac OS种更多。

    滤镜的处理流程: 获取需要过滤的图片(当前上下文或者图片) -> 需要过滤的图片转成CIimage -> 渲染成CGImageRef(使用滤镜开始过滤,并在画布中绘制) -> 转换为UIimage -> 释放 CGImageRef -> 使用UIImage

    //这里针对图片进行滤镜,而不是在上下文中
    __weak typeof(self) weakSelf = self;
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
            /* 1.获取需要过滤的图片*/
            UIImage *image = [UIImage imageNamed:@"tu10"];
            /* 2.把图片转换成CIImage类型 */
            CIImage *cImage = [CIImage imageWithCGImage:image.CGImage];
            /* 3.创建一个CIRadialGradient(半径梯度)的滤镜对象 */
            CIFilter *cFilter = [CIFilter filterWithName:@"CIRadialGradient"];
            /* 4.由于用的是CIRadialGradient滤镜,需要确定中心点,所以创建一个CIVector类型来表达半径梯度滤镜等中心点 */
            CIVector *center = [CIVector vectorWithX:image.size.width/2 Y:image.size.height/2];
            /* 5.设置半径梯度等中心点到inputCenter这个值中,使用setValue方法设置滤镜属性 */
            [cFilter setValue:center forKey:@"inputCenter"];
            /* 6.创建第二个滤镜
                参数1.首先需要确定滤镜的类型,使用CIDarkenBlendMode(亮度混合模式,把参数2.3和参数4.5设置后的合成图片进行亮度的混合)
                参数2.确定设置的属性名称
                参数3.从上一个滤镜中过去过滤后的输出图片(参数2和参数3是对应关系,参数3的值是设置到了参数2的属性中)
                参数4.确定设置的属性名称
                参数5.原图
             */
            CIFilter *dark = [CIFilter filterWithName:@"CIDarkenBlendMode" keysAndValues:@"inputImage", cFilter.outputImage, @"inputBackgroundImage", cImage, nil];
            /* 创建一个画布 */
            CIContext *context = [CIContext contextWithOptions:nil];
            /* 从滤镜中获取输出图片,创建到画布中,并从画布中获得CGImageRef类型的图片 */
            CGImageRef cImageRef = [context createCGImage:dark.outputImage fromRect:cImage.extent];
            /* 获取UIImage类型的图片 */
            UIImage *newImage = [UIImage imageWithCGImage:cImageRef scale:image.scale orientation:UIImageOrientationUp];
            /* 释放CGImage */
            CGImageRelease(cImageRef);
            dispatch_async(dispatch_get_main_queue(), ^{
                //回到主线程设置图片
                weakSelf.testImageView.image = newImage;
                weakSelf.testImageView.frame = CGRectMake((V_width-image.size.width)/2, (V_height - image.size.height)/2, image.size.width, image.size.height);
            });
        });
    

    参考文章:
    iOS绘图教程
    iOS开发系列--打造自己的“美图秀秀”

    相关文章

      网友评论

        本文标题:IOS-绘图API(超详细)

        本文链接:https://www.haomeiwen.com/subject/encaoxtx.html