Quartz 2D Programming Guide--笔记

来源:互联网 发布:淘宝秒杀 编辑:程序博客网 时间:2024/06/18 11:36
Graphics States

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

Drawing to a View Graphics Context in 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的总称,跟core graphics采用的坐标系为LLO,UIView采用的是UIKit框架坐标轴为ULO,变换的时候通过CTM

Anti-Aliasing(消除锯齿)

  消除锯齿的工作需要两步骤:
  1、将graphics context的状态设置为anti-aliasing。通过函数CGContextSetShouldAntialias
  2、将context设置为anti-aliasing。通过函数CGContextSetAllowsAntialiasing。true:allowing anti-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

  Blend modes表示的是在一个背景上画画的时候,前后颜色是如何叠加的。正常情况下,绘图时Qutarz采用的时候默认的模式,显现的效果是通过下面的计算得到的:
result = (alpha * foreground) + (1 - alpha) * background
  blend modes属于context states,可以通过CGContextSaveGState和CGContextRestoreGState在stack中保存和推出context的states。设置blend mode的方法是CGContextSetBlendMode。

Clipping to a Path

  此部分的意义在于将path作为mask来用,通过两个函数:CGContextClip和函数CGContextDrawImage,实现path经过的部分的图片被显现出来,未经过的部分则不显示。
  此处与画线的不同之处在于用CGContextClip代替了画线的fill和stroke

Transforms

  第一种方法:通过CTM
  CGContextTranslateCTM
  CGContextScaleCTM:x,y有负值,就代表了反方向
  CGContextRotateCTM:-值代表了顺时针,正值代表了逆时针。弧度制
  其他方法原理相似,参考源文档

Pattern

  pattern在我看来就是图样、或叫模板。主要作用是设置context的fill或者stroke pattern之后,context中调用fill或者stroke的时候用该pattern填充。
  首先,pattern分为两种:带色和不带色的。它们两个的区别主要体现在一下几个方面:
  1、建立callback function的时候。color:指出fill或者stroke的颜色。stencil:不指出颜色,直接调用fill和stroke建立对应的cell,建立color的时候需要指出使用RGB的color space,这样方便后面用rgb对pattern着色。当然,针对color的pattern,完全可以采用一个图片来作为pattern cell,那么直接将这个图片画在context就算是建立cell了,具体代码在后。
  2、color space的时候,stencile:指出color为RGB color space
  3、设置采用当前的pattern填充的时候,调用CGContextSetFillPattern或者CGContextSetStrokePattern,对于stencile,需要指出采用的颜色的RGB值,意在着色。
  4、在patterncreate,isColored设置为false对于stencile
  两种pattern使用的时候都是分为一下5个步骤:
  1、write a callback function that draw a colored pattern cell
  2、set up the colored pattern color space
  3、set up the anatomy of the colored pattern
  4、specify the colored pattern as a fill or stroke pattern
  5、draw with the colored pattern
代码示例:
color:
void MyPatternDraw(void *info,CGContextRef contextRef)//1、pattern cell callback function
{
    UIImage *image = [UIImage imageNamed:@"2.png"];
    CGImageRef imageRef = image.CGImage;
    CGRect rect = CGRectMake(0, 0, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
   
    CGContextDrawImage(contextRef, rect, imageRef);
}
void MyColoredPatternDraw(CGContextRef contextRef,CGRect rect)//2,3,4,5
{
    CGPatternRef patternRef;
    CGColorSpaceRef patternSpace;
    float alpha = 1;
    static const CGPatternCallbacks callbacks = {0,&MyPatternDraw,NULL};//参数:版本,开始话pattern的函数和最后释放空间的函数
   
    CGContextSaveGState(contextRef);
    patternSpace = CGColorSpaceCreatePattern(NULL);//这里为null,若为stencile,需简历一个rgb的color space,并作为这个函数的参数
    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 graphics state,可以通过restore来恢复之前状态,或者通过将投影的颜色设置为NULL也可以。
  实现投影的步骤如下:
  1、CGContextSaveGState
  2、调用CGContextSetShadow
  3、调用函数进行绘图
  4、CGContextRestoreGState
  针对彩色投影步骤如下:
  1、CGContextSaveGState
  2、建立一个CGColor对象
  3、调用CGContextSetShadowWithColor
  4、绘图
  5、CGContextRestoreGState

Gradients

Using a CGGradient Object
  CGGradient类型数据是对一个梯度的抽象定义,它采用直接的方式,通过指出颜色和对应的位置,由系统自动的计算出各个位置的颜色值。CGGradient类型的数据可以重复使用,在真正绘画的时候才会指出梯度是轴向的还是径向的。
  通过CGGradient对象创建梯度的步骤如下:
  1、通过函数CGGradientCreateWithColorComponents或者函数CGGradientCreateWithColors创建一个CGGradient对象
CGGradientRef CGGradientCreateWithColorComponents(
    CGColorSpaceRef space,
    const CGFloat components[],
    const CGFloat locations[],
    size_t count
);
    其中CGFloat location[],的取值范围是0到1,分别代表了所处位置到原点的位置在整个距离中所占的比例。如,0.5表示了位于轴线的两端的中点。另外主要注意Quartz最少需要两个点的位置,默认情况下,传递参数NULL代表了起始点和终点。
    参数component的取值范围也是0到1。在iOS中默认的采用设备的color space,在iOS中默认采用RGBA四种元素,也就是说component数组的长度为locations的四倍。代码如下:
    CGContextRef contextRef = UIGraphicsGetCurrentContext();
    CGContextSaveGState(contextRef);
   
    //gredient create
    CGGradientRef gredientRef;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGFloat locations[2] = {0,1};
    CGFloat components[8] = {1,0.4,0.5,1.0,
                                0.8,0.8,0.3,1};
    gredientRef = CGGradientCreateWithColorComponents(colorSpace, components, locations, 2);
    //draw gredient
    CGContextDrawLinearGradient(contextRef,
                                gredientRef,
                                CGPointMake(100, 100),//start point
                                CGPointMake(600, 700),//end point
                                0); //CGGradientDrawingOptions:KCGGradientDrawsBeforeStarLocation or       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 CGShading Object

  CGShading与CGGredient的最大的区别是:CGShading需要程序猿自己创建一个用于计算各点色彩的函数。除此之外,CGShading在创建的时候便需要指出shade是轴向还是径向的。
  此部分的其他内容请参考源文档。

Painting to a Transparency Layer

  transparency layer的主要作用是将一系列绘制的单元合成成为一个整体,这个整体的单元具有相同的操作,例如有三个矩形,都需要添加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
原创粉丝点击