IOS 画图--2

来源:互联网 发布:面料排版软件 编辑:程序博客网 时间:2024/04/29 21:01

CGPathDrawingMode

我们会根据drawingMode的五个常量讨论
kCGPathFillkCGPathEOFillkCGPathStrokekCGPathFillStroke,or kCGPathEOFillStroke.
(1)kCGPathFill如下图:
[转载]QuartZ例子(2)---绘制Polygons
此fill模式为缺省模式(非零缠绕数原则),大概规则为,在需要填充颜色的区域的一点向画区域外画一条线,g如果是从左向右穿过的,则加1,如果从右向左穿过,则减一,最后结果为0则不fill,大于0则填充,所以line的方向对fill的区域有影响。
Concentric circles filled using different fill rules
还有一种为even-odd(奇偶原则),只计算line穿过path段的个数,为偶数时,不填充,奇数时填充,所以path的方向不会影响填充的结果。
(2) kCGPathEOFill模式
[转载]QuartZ例子(2)---绘制Polygons
此填充模式为奇偶模式
(3)kCGPathStroke模式
[转载]QuartZ例子(2)---绘制Polygons
(4)kCGPathFillStroke模式
[转载]QuartZ例子(2)---绘制Polygons
(5)kCGPathEOFillStroke模式
[转载]QuartZ例子(2)---绘制Polygons

例如:
    CGContextSetLineWidth(context, 2);
//    CGContextSetLineDash(context, 0, NULL, 0);
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, 60.0, 10.0);
    CGPathAddLineToPoint(path, NULL, 100.0, 100.0);
    CGPathAddLineToPoint(path, NULL, 10.0, 50.0);
    CGPathAddLineToPoint(path, NULL, 110.0, 50.0);
    CGPathAddLineToPoint(path, NULL, 30.0, 100.0);
    CGPathAddLineToPoint(path, NULL, 60.0, 10.0);
    
    CGPathMoveToPoint(path, NULL, 260.0, 10.0);
    CGPathAddLineToPoint(path, NULL, 220.0, 50.0);
    CGPathAddLineToPoint(path, NULL, 238.0, 90.0);
    CGPathAddLineToPoint(path, NULL, 282.0, 90.0);
    CGPathAddLineToPoint(path, NULL, 300.0, 50.0);
    CGPathAddLineToPoint(path, NULL, 260.0, 10.0);
    /*1种*/                                                                                   /*2种*/
    CGPathMoveToPoint(path, NULL, 260.0, 20.0);              //CGPathMoveToPoint(path, NULL, 260.0, 20.0);
    CGPathAddLineToPoint(path, NULL, 230.0, 50.0);         //CGPathAddLineToPoint(path, NULL, 290.0, 50.0);
    CGPathAddLineToPoint(path, NULL, 248.0, 80.0);         //CGPathAddLineToPoint(path, NULL, 272.0, 80.0);
    CGPathAddLineToPoint(path, NULL, 272.0, 80.0);         //CGPathAddLineToPoint(path, NULL, 248.0, 80.0);
    CGPathAddLineToPoint(path, NULL, 290.0, 50.0);         //CGPathAddLineToPoint(path, NULL, 230.0, 50.0);
    CGPathAddLineToPoint(path, NULL, 260.0, 20.0);         //CGPathAddLineToPoint(path, NULL, 260.0, 20.0);
    
    CGContextAddPath(context, path);
    CGContextSetFillColorWithColor(context, [UIColor colorWithRGBInt:0x00a400 alpha:1.0].CGColor);
    CGContextSetStrokeColorWithColor(context, [UIColor colorWithRGBInt:0xff0000 alpha:1.0].CGColor);
    CGContextDrawPath(context, kCGPathEOFillStroke);///*1*/描边加两个5边型未重叠区域。/*2*/描边加两个5边型未重叠区域
    //CGContextDrawPath(context, kCGPathEOFillStroke);///*1*/描边加55边型内部区域。/*2*/描边加两个5边型未重叠区域

    CGContextSetLineWidth(context, 2);
    CGPathRelease(path);

Graphics States

在创建context的时候,都会创建一个空的stack用于存储graphics的状态。通过函数CGContextSaveGState和函数CGContextRestoreGState分别将graphics的状态压入和弹出stack。
  graphics的状态不好看path,path数据不会存在stack中。

Drawing to a View Graphics Contextin iOS

 在iOS中绘画是在UIView中通过UIView的函数drawRect:来实现的。drawRect:函数在view在当前的屏幕上可见并且view的部分需要更新的时候才会被调用。
  注意:
 1、drawRect:函数并不会自动被调用,一般在view可见的情况下,加载view的时候被调用一次,之后如果需要调用需要调用view的函数setNeedsDisplay或setNeedsDisplayRect(函数名忘了)的时候才会被调用。
 2、调用drawRect:的时候,系统会自动的对绘画的环境进行设置,其中包括为当前的UIView建立一个context,也就是说在drawRect:函数外调用UIGraphicsGetCurrtentContext函数,无法获取当前的context
  3、Quartz是core graphics的总称,跟coregraphics采用的坐标系为LLO,UIView采用的是UIKit框架坐标轴为ULO,变换的时候通过CTM
Anti-Aliasing(消除锯齿)
  消除锯齿的工作需要两步骤:
  1、将graphicscontext的状态设置为anti-aliasing。通过函数CGContextSetShouldAntialias
 2、将context设置为anti-aliasing。通过函数CGContextSetAllowsAntialiasing。true:allowinganti-aliasing; false: not to allow it。
Creating a Path
 在一个context中绘画,通过函数CGContextBeginPath开始。之后通过函数CGcontextMoveToPoint设置第一个点,在之后通过CGContextAddLine等函数添加更多的图形,最后通过fill或stroke函数将path画在context上。
 例如:CGContextDrawPath(contextRef,kCGPathStroke)或CGContextStrokePath(context)
  注意:
  1、之前的一系列函数仅仅是构造path,并没有将path画在context上。
 2、调用CGContextClip之前,path是不能fill或者stoke的,否则出不来clip的效果
 与context构造path对应的,还可以通过CGPathRef的函数构造path,原理是相同的。画path的时候调用CGContextAddPath。
 具体的path的参数请参考原文:https://developer.apple.com/library/ios/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_paths/dq_paths.html
  例如:画虚线,可以通过CGContextSetLineDash完成。
 除此之外,画矩形、椭圆、线段还有一些更直接的函数,不需要先add,在stroke,可以直接调用下面的函数:
  CGContextStrokePath
  CGContextStrokeRect
  CGContextStrokeRectWithWidth
  CGContextStrokeEllipseInRect
  CGContextStrokeLineSegments(参数的形式:线段一起始点,线段一结束点,线段二起始点,线段二结束点···)
Filling a Path
  此部分与上一部分差不多,直接参考原文。
Setting Blend Modes
  Blendmodes表示的是在一个背景上画画的时候,前后颜色是如何叠加的。正常情况下,绘图时Qutarz采用的时候默认的模式,显现的效果是通过下面的计算得到的:
result = (alpha * foreground) + (1 - alpha) * background
  blend modes属于contextstates,可以通过CGContextSaveGState和CGContextRestoreGState在stack中保存和推出context的states。设置blendmode的方法是CGContextSetBlendMode。
Clipping to a Path
 此部分的意义在于将path作为mask来用,通过两个函数:CGContextClip和函数CGContextDrawImage,实现path经过的部分的图片被显现出来,未经过的部分则不显示。
 此处与画线的不同之处在于用CGContextClip代替了画线的fill和stroke
Transforms
  第一种方法:通过CTM
  CGContextTranslateCTM
  CGContextScaleCTM:x,y有负值,就代表了反方向
  CGContextRotateCTM:-值代表了顺时针,正值代表了逆时针。弧度制
  其他方法原理相似,参考源文档
Pattern
  pattern在我看来就是图样、或叫模板。主要作用是设置context的fill或者strokepattern之后,context中调用fill或者stroke的时候用该pattern填充。
  首先,pattern分为两种:带色和不带色的。它们两个的区别主要体现在一下几个方面:
  1、建立callbackfunction的时候。color:指出fill或者stroke的颜色。stencil:不指出颜色,直接调用fill和stroke建立对应的cell,建立color的时候需要指出使用RGB的colorspace,这样方便后面用rgb对pattern着色。当然,针对color的pattern,完全可以采用一个图片来作为patterncell,那么直接将这个图片画在context就算是建立cell了,具体代码在后。
  2、color space的时候,stencile:指出color为RGB colorspace
 3、设置采用当前的pattern填充的时候,调用CGContextSetFillPattern或者CGContextSetStrokePattern,对于stencile,需要指出采用的颜色的RGB值,意在着色。
 4、在patterncreate,isColored设置为false对于stencile
  两种pattern使用的时候都是分为一下5个步骤:
  1、write a callback function that draw a coloredpattern cell
  2、set up the colored pattern color space
  3、set up the anatomy of the coloredpattern
  4、specify the colored pattern as a fill orstroke pattern
  5、draw with the colored pattern
代码示例:
color:
void MyPatternDraw(void *info,CGContextRef contextRef)//1、patterncell callback function
{
    UIImage*image = [UIImage imageNamed:@"2.png"];
    CGImageRefimageRef = image.CGImage;
    CGRect rect= CGRectMake(0, 0, CGImageGetWidth(imageRef),CGImageGetHeight(imageRef));
   
   CGContextDrawImage(contextRef, rect, imageRef);
}
void MyColoredPatternDraw(CGContextRef contextRef,CGRectrect)//2,3,4,5
{
    CGPatternRefpatternRef;
   CGColorSpaceRef patternSpace;
    float alpha= 1;
    static constCGPatternCallbacks callbacks ={0,&MyPatternDraw,NULL};//参数:版本,开始话pattern的函数和最后释放空间的函数
   
   CGContextSaveGState(contextRef);
    patternSpace=CGColorSpaceCreatePattern(NULL);//这里为null,若为stencile,需简历一个rgb的colorspace,并作为这个函数的参数
   CGContextSetFillColorSpace(contextRef, patternSpace);
   CGColorSpaceRelease(patternSpace);
   
    patternRef =CGPatternCreate(NULL,
                                CGRectMake(0, 0, 41, 50), //pattern 的大小
                                CGAffineTransformMakeScale(1, -1),//通过这个可以对单个cell进行旋转,放大、缩小操作
                                60, 60,//pattern之间的上下间隔
                                kCGPatternTilingConstantSpacing,
                                true, //若为stencile,此处为false
                                &callbacks);
   CGContextSetFillPattern(contextRef, patternRef,&alpha);//此处仅仅是alpha,若为stencile,则为一个四维数组代表了rgba的值
   CGContextFillRect(contextRef, CGRectMake(0, 0, 1024,768));//用已经建立的pattern填充整个屏幕
   
   CGPatternRelease(patternRef);
   CGContextRestoreGState(contextRef);
}
Shadows
  投影有三个变量:
  x-offset:表明了投影在水平方向相对于图片的偏移量
  y-offset:表明了投影在竖直方向相对于原图片的偏移量
  blur value:投影的边缘部分是虚幻的还是实的
Quartz <wbr>2D <wbr>Programming <wbr>Guide--笔记
 默认情况下,投影的RGBA为(0,0,0,1/3),如果采用默认的色彩投影调用函数CGContextSetShadow。如果希望修改色彩,可以通过函数CGContextSetShadowWithColor,参数为context和CGColor。
  注意,shadow是context graphicsstate,可以通过restore来恢复之前状态,或者通过将投影的颜色设置为NULL也可以。
  实现投影的步骤如下:
  1、CGContextSaveGState
  2、调用CGContextSetShadow
  3、调用函数进行绘图
  4、CGContextRestoreGState
  针对彩色投影步骤如下:
  1、CGContextSaveGState
  2、建立一个CGColor对象
  3、调用CGContextSetShadowWithColor
  4、绘图
  5、CGContextRestoreGState
Gradients
Using a CGGradientObject
 CGGradient类型数据是对一个梯度的抽象定义,它采用直接的方式,通过指出颜色和对应的位置,由系统自动的计算出各个位置的颜色值。CGGradient类型的数据可以重复使用,在真正绘画的时候才会指出梯度是轴向的还是径向的。
  通过CGGradient对象创建梯度的步骤如下:
 1、通过函数CGGradientCreateWithColorComponents或者函数CGGradientCreateWithColors创建一个CGGradient对象
CGGradientRef CGGradientCreateWithColorComponents(
   CGColorSpaceRef space,
    constCGFloat components[],
    constCGFloat locations[],
    size_tcount
);
    其中CGFloatlocation[],的取值范围是0到1,分别代表了所处位置到原点的位置在整个距离中所占的比例。如,0.5表示了位于轴线的两端的中点。另外主要注意Quartz最少需要两个点的位置,默认情况下,传递参数NULL代表了起始点和终点。
   参数component的取值范围也是0到1。在iOS中默认的采用设备的colorspace,在iOS中默认采用RGBA四种元素,也就是说component数组的长度为locations的四倍。代码如下:
    CGContextRefcontextRef = UIGraphicsGetCurrentContext();
   CGContextSaveGState(contextRef);
   
    //gredientcreate
   CGGradientRef gredientRef;
   CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGFloatlocations[2] = {0,1};
    CGFloatcomponents[8] = {1,0.4,0.5,1.0,
                               0.8,0.8,0.3,1};
    gredientRef= CGGradientCreateWithColorComponents(colorSpace, components,locations, 2);
    //drawgredient
   CGContextDrawLinearGradient(contextRef,
                               gredientRef,
                               CGPointMake(100, 100),//start point
                               CGPointMake(600, 700),//end point
                               0); //CGGradientDrawingOptions:KCGGradientDrawsBeforeStarLocationor      KCGGradientDrawsAfterEndLocation,当然此处也可以用数字来表示,0代表两头都不超出,1起始点超出,2终点超出,3两头都超出。
   CGContextRestoreGState(contextRef);
            CGContextDrawRadialGradient(contextRef,
                               gredientRef,
                               CGPointMake(100, 100),
                               100, //起始圆点半径
                               CGPointMake(600, 800),
                               100,//终点圆点半径
                               0);
   这段代码画出对应的径向梯度。

通过CGColor创造CGGradientDef对象。
CGGradientRef CGGradientCreateWithColors(    CGColorSpaceRef space,    CFArrayRef colors,    const CGFloat locations[]);  2、通过函数CGContextDrawLineGradient或者CGContextDrawRadialGradient将创建的gredient对象画在对应的context中。通过上面的代码可以明显的看出,创建gredient的时候并没有指出是径向的还是轴向的,仅仅是在画的时候调用不同的径向和轴向的函数。
Using a CGShadingObject
 CGShading与CGGredient的最大的区别是:CGShading需要程序猿自己创建一个用于计算各点色彩的函数。除此之外,CGShading在创建的时候便需要指出shade是轴向还是径向的。
  此部分的其他内容请参考源文档。
Painting to a TransparencyLayer
  transparencylayer的主要作用是将一系列绘制的单元合成成为一个整体,这个整体的单元具有相同的操作,例如有三个矩形,都需要添加shadow,如果这三个矩形有重合,则分开画有可能导致它们的影子覆盖对方,如果这不是你想要的效果可以将这些矩形做一整体画在透明层上。
  两个函数:
  CGContextBeginTransparencyLayer
  CGContextEndTransparencyLayer
  调用前后图片效果如下:
  Quartz <wbr>2D <wbr>Programming <wbr>Guide--笔记
Quartz <wbr>2D <wbr>Programming <wbr>Guide--笔记
Text
  使用Quartz 2D画text的时候,需要经过以下几个步骤:
  1、设置字体和字体大小
    函数CGContextSelectFont,CGContextSetFont。
    (1)CGContextSelectFont原型:
              void CGContextSelectFont (

                     CGContextRef c,

                     const char *name,
//字体名字
                     CGFloat size,//字体大小

                     CGTextEncoding textEncoding

               );
 
     容易发现CGContextSelectFont有一个encoding的属性,其实此处的encoding就两个值可选kCGEncodingFontSpecific和kCGEncodingFontMacRoman。
     (官方文档又说如果字体的encoding不是MacRoman的话,就得用函数CGContextSetFont和函数CGContextSetFontSize。所以我感觉是不是这个textEncoding只能是MacRoman)
      将text绘制在屏幕的函数为CGContextShowTextAtPoint
    (2)CGContextSetFont
    void CGContextSetFont (
       CGContextRef c,
       CGFontRef font
    );
    如果采用这个方法设置字体,还需要通过函数CGContextSetFontSize设置字体大小。绘制函数采用CGContextShowGlyphsAtPoint
  2、设置drawing mode
    通过函数CGContextSetTextDrawingMode。
    mode包括:kCGTextFill,kCGTextStroke,kCGTextFillStroke,kCGTextInvisible,kCGTextFillClip,kCGTextStrokeClip,kCGTextFillStrokeClip,kCGTextClip.
  3、设置其他的一些属性,如果需要fill 设置fill的color,如果需要stroke设置stroke的color
  4、设置字体变换的CTM,否则text画出来是倒过来的
    CGAffineTransformMakeRotation,CGAffineTransformMakeScale,CGAffineTransformMakeTranslate生成对应的CGAffineTransform对象,之后通过CGContextSetTextMartix设置CTM
  5、画text
   函数为CGContextShowTextAtPoint