【概念釋疑】CoreGraphics API 介紹

參考文章

設(shè)置

  • 設(shè)置勾畫(huà)色CGContextSetRGBStrokeColor
void CGContextSetRGBStrokeColor (
   CGContextRef c,
   CGFloat red,
   CGFloat green,
   CGFloat blue,
   CGFloat alpha
);  
  • 設(shè)置填充色CGContextSetRGBFillColor
void CGContextSetRGBFillColor (
   CGContextRef c,
   CGFloat red,
   CGFloat green,
   CGFloat blue,
   CGFloat alpha
)  
  • 設(shè)置勾畫(huà)寬度CGContextSetLineWidth
void CGContextSetLineWidth (
   CGContextRef c,
   CGFloat width
)  
  • 設(shè)置端點(diǎn)樣式CGContextSetLineCap
void CGContextSetLineCap ( CGContextRef c, CGLineCap cap )  
  • 設(shè)置連接點(diǎn)樣式CGContextSetLineJoin
void CGContextSetLineJoin ( CGContextRef c, CGLineJoin join )  
  • 設(shè)置虛線樣式CGContextSetLineDash
void CGContextSetLineDash ( CGContextRef c, CGFloat phase, const CGFloat *lengths, size_t count );  

phase設(shè)置第一段實(shí)線開(kāi)始的長(zhǎng)度,lengths是一個(gè)浮點(diǎn)型數(shù)組,設(shè)置一個(gè)重復(fù)段中實(shí)線虛線的長(zhǎng)度,count用以說(shuō)明lengths的個(gè)數(shù).

虛線樣式1.png
虛線樣式2.png

如上圖虛線樣式1,phase為0,說(shuō)明它一個(gè)實(shí)線段的起點(diǎn)為0,lengths數(shù)組表明它的重復(fù)段是這樣的:長(zhǎng)10的實(shí)線,長(zhǎng)20的虛線,長(zhǎng)10的實(shí)線,長(zhǎng)30的虛線,count為4.

上圖虛線樣式2與1唯一的不同的是,它的phase為5,它的第一個(gè)實(shí)線段從5開(kāi)始.

  • 設(shè)置混合模式
void CGContextSetBlendMode ( CGContextRef c, CGBlendMode mode );  

混合模式是由CGBlendMode枚舉來(lái)設(shè)置,詳情見(jiàn)官方文檔中的枚舉說(shuō)明.這里解釋下幾個(gè)參數(shù):

R is the premultiplied result

S is the source color, and includes alpha

D is the destination color, and includes alpha

Ra, Sa, and Da are the alpha components of R, S, and D;

比如,kCGBlendModeDestinationOver,它的混合模式是這樣來(lái)計(jì)算的: R = S*(1 - Da) + D.其中,前一種顏色是destination,后一種顏色是source.在官方Demo中,代碼是這樣的

    // Start with a background whose color we don't use in the demo
    CGContextSetGrayFillColor(context, 0.2, 1.0);
    CGContextFillRect(context, self.bounds);
    // We want to just lay down the background without any blending so we use the Copy mode rather than Normal
    CGContextSetBlendMode(context, kCGBlendModeCopy);
    // Draw a rect with the "background" color - this is the "Destination" for the blending formulas
    CGContextSetFillColorWithColor(context, self.destinationColor.CGColor);
    CGContextFillRect(context, CGRectMake(110.0, 20.0, 100.0, 100.0));
    // Set up our blend mode
    CGContextSetBlendMode(context, self.blendMode);
    // And draw a rect with the "foreground" color - this is the "Source" for the blending formulas
    CGContextSetFillColorWithColor(context, self.sourceColor.CGColor);
    CGContextFillRect(context, CGRectMake(60.0, 45.0, 200.0, 50.0)); 

代碼中混合了兩次,先是self.destinationColor.CGColor與一開(kāi)始設(shè)置的gray,用kCGBlendModeCopy混合一次(這里,self.destinationColor.CGColor是source,gray是destination),然后,self.sourceColor.CGColor與self.destinationColor.CGColor,用self.blendMode混合一次.

創(chuàng)建Path

  • 創(chuàng)建Path起始點(diǎn)CGContextMoveToPoint
void CGContextMoveToPoint (
   CGContextRef c,
   CGFloat x,
   CGFloat y
)  
  • 添加線段CGContextAddLineToPoint
void CGContextAddLineToPoint (
   CGContextRef c,
   CGFloat x,
   CGFloat y
)  
  • 添加一系列線段CGContextAddLines
void CGContextAddLines (
   CGContextRef c,
   const CGPoint *points,
   size_t count
)  

相當(dāng)于

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

for (k = 1; k < count; k++) {
    CGContextAddLineToPoint (c, points[k].x, points[k].y);
}  
示例1:勾畫(huà)路徑
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextSetLineWidth(context, 2.0);
CGContextMoveToPoint(context, 10.0, 30.0);
CGContextAddLineToPoint(context, 310.0, 30.0);
CGContextStrokePath(context);  
示例2:勾畫(huà)路徑
CGPoint addLines[] =
    {
        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, addLines, sizeof(addLines)/sizeof(addLines[0]));
CGContextStrokePath(context);  
  • 添加矩形CGContextAddRect
void CGContextAddRect ( CGContextRef c, CGRect rect );  

相當(dāng)于

CGContextMoveToPoint (c, CGRectGetMinX(rect), CGRectGetMinY(rect));
 
CGContextAddLineToPoint (c, CGRectGetMaxX(rect), CGRectGetMinY(rect));
 
CGContextAddLineToPoint (c, CGRectGetMaxX(rect), CGRectGetMaxY(rect);
 
CGContextAddLineToPoint (c, CGRectGetMinX(rect), CGRectGetMaxY(rect));

CGContextClosePath (c);  
  • 添加一系列矩形CGContextAddRects
void CGContextAddRects ( CGContextRef c, const CGRect *rects, size_t count );  

相當(dāng)于

for (k = 0; k < count; k++) {
    CGContextAddRect (c, rects[k]);
}  
  • 添加橢圓CGContextAddEllipseInRect
void CGContextAddEllipseInRect ( CGContextRef c, CGRect rect );  
  • 添加弧線
void CGContextAddArc ( CGContextRef c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise );  
  • 添加弧線2
void CGContextAddArcToPoint ( CGContextRef c, CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, CGFloat radius );  
示例3:添加弧線2
CGPoint p[3] =
    {
        CGPointMake(210.0, 30.0),
        CGPointMake(210.0, 60.0),
        CGPointMake(240.0, 60.0),
    };
    CGContextMoveToPoint(context, p[0].x, p[0].y);
    CGContextAddArcToPoint(context, p[1].x, p[1].y, p[2].x, p[2].y, 30.0);
    CGContextStrokePath(context);  
  • 二階貝塞爾曲線
void CGContextAddQuadCurveToPoint ( CGContextRef c, CGFloat cpx, CGFloat cpy, CGFloat x, CGFloat y );  
示例4:二階貝塞爾曲線
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
    s = CGPointMake(30.0, 300.0);
    e = CGPointMake(270.0, 300.0);
    cp1 = CGPointMake(150.0, 180.0);
    CGContextMoveToPoint(context, s.x, s.y);
    CGContextAddQuadCurveToPoint(context, cp1.x, cp1.y, e.x, e.y);
    CGContextStrokePath(context);  
  • 三階貝塞爾曲線
void CGContextAddCurveToPoint ( CGContextRef c, CGFloat cp1x, CGFloat cp1y, CGFloat cp2x, CGFloat cp2y, CGFloat x, CGFloat y );  
示例5:三階貝塞爾曲線
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextSetLineWidth(context, 2.0);
CGPoint s = CGPointMake(30.0, 120.0);
CGPoint e = CGPointMake(300.0, 120.0);
CGPoint cp1 = CGPointMake(120.0, 30.0);
CGPoint cp2 = CGPointMake(210.0, 210.0);
CGContextMoveToPoint(context, s.x, s.y);
CGContextAddCurveToPoint(context, cp1.x, cp1.y, cp2.x, cp2.y, e.x, e.y);
CGContextStrokePath(context);  
貝塞爾曲線[知識(shí)補(bǔ)充]
二階貝塞爾曲線.png
三階貝塞爾曲線.png

繪制Path

  • 勾畫(huà)當(dāng)前路徑CGContextStrokePath,調(diào)用此函數(shù)后,會(huì)清除當(dāng)前路徑
void CGContextStrokePath (
   CGContextRef c
)  
  • 填充路徑CGContextFillPath,非零繞組規(guī)則,調(diào)用此函數(shù)后,會(huì)清除當(dāng)前路徑
void CGContextFillPath ( CGContextRef c )  
  • 勾畫(huà)間隔的線段CGContextStrokeLineSegments,調(diào)用此函數(shù)后,會(huì)清除當(dāng)前路徑
void CGContextStrokeLineSegments (
   CGContextRef c,
   const CGPoint *points,
   size_t count
)  

相當(dāng)于

CGContextBeginPath (context);
for (k = 0; k < count; k += 2) {
    CGContextMoveToPoint(context, s[k].x, s[k].y);
    CGContextAddLineToPoint(context, s[k+1].x, s[k+1].y);
}
CGContextStrokePath(context);  
示例1:勾畫(huà)間隔線段
CGPoint strokeSegments[] =
    {
        CGPointMake(10.0, 150.0),
        CGPointMake(70.0, 120.0),
        CGPointMake(130.0, 150.0),
        CGPointMake(190.0, 120.0),
        CGPointMake(250.0, 150.0),
        CGPointMake(310.0, 120.0),
    };

CGContextStrokeLineSegments(context, strokeSegments, sizeof(strokeSegments)/sizeof(strokeSegments[0]));  
  • 勾畫(huà)矩形CGContextStrokeRect
void CGContextStrokeRect ( CGContextRef c, CGRect rect );  

相當(dāng)于

CGContextAddRect ( CGContextRef c, CGRect rect );
CGContextStrokePath(context);    

  • 按指定寬度勾畫(huà)矩形CGContextStrokeRectWithWidth
void CGContextStrokeRectWithWidth ( CGContextRef c, CGRect rect, CGFloat width );  

相當(dāng)于

CGContextSetLineWidth ( CGContextRef c, CGFloat width );
    
CGContextAddRect ( CGContextRef c, CGRect rect );
CGContextStrokePath(context);  
  • 填充矩形CGContextFillRect
void CGContextFillRect ( CGContextRef c, CGRect rect );  

相當(dāng)于

CGContextAddRect ( CGContextRef c, CGRect rect );
CGContextFillPath(context);  
  • 填充一系列矩形CGContextFillRects
void CGContextFillRects ( CGContextRef c, const CGRect *rects, size_t count );  

相當(dāng)于

for (k = 0; k < count; k++) {
    CGContextFillRect (c, rects[k]);
}  
  • 以指定的模式繪制路徑CGContextDrawPath
void CGContextDrawPath ( CGContextRef c, CGPathDrawingMode mode );  

介紹下這幾個(gè)枚舉值:

kCGPathFill,           // 非零繞組填充
kCGPathEOFill,         // 奇偶填充
kCGPathStroke,         // 勾邊
kCGPathFillStroke,     // 非零繞組填充并勾邊
kCGPathEOFillStroke    // 奇偶填充并勾邊
  • 勾畫(huà)橢圓CGContextStrokeEllipseInRect
void CGContextStrokeEllipseInRect ( CGContextRef c, CGRect rect );  

相當(dāng)于

CGContextAddEllipseInRect ( CGContextRef c, CGRect rect );  
CGContextStrokePath(context);   
  • 填充橢圓CGContextFillEllipseInRect
void CGContextFillEllipseInRect ( CGContextRef c, CGRect rect );  
非零繞組規(guī)則和奇偶規(guī)則[補(bǔ)充知識(shí)]

圖形學(xué)的兩個(gè)規(guī)則

非零繞組和奇偶.png

如上圖,左下角是按照奇偶規(guī)則填充,右下角按非零繞組規(guī)則填充。
(據(jù)我理解,這條曲線應(yīng)該是一條閉合曲線)
奇偶規(guī)則:從一點(diǎn)射出任意一條指向無(wú)窮遠(yuǎn)的射線,曲線和射線的交點(diǎn)個(gè)數(shù)為奇數(shù),則該點(diǎn)在曲線內(nèi),否則,在曲線外。

非零繞組規(guī)則:給這條曲線標(biāo)注方向,從一點(diǎn)射出任意一條指向無(wú)窮遠(yuǎn)的射線,定義一個(gè)方向的交點(diǎn)(比如從左到右,或從上到下)為1,它的反向的交點(diǎn)(從右到左,或從下到上)為-1,如果繞組總數(shù)為0,表示該點(diǎn)在曲線外,非零,則在曲線內(nèi)。

上圖中,判定區(qū)里的點(diǎn),按照奇偶規(guī)則,它與曲線有偶數(shù)個(gè)交點(diǎn),所以在曲線外,按照非零繞組規(guī)則,如圖中所標(biāo)方向,并將箭頭作為射線方向,它有兩個(gè)同向(都是從上往下)的交點(diǎn),故而非零,判定該點(diǎn)在曲線內(nèi)。

存取上下文環(huán)境

  • 存儲(chǔ)當(dāng)前繪制狀態(tài)的備份到繪制狀態(tài)棧中CGContextSaveGState
void CGContextSaveGState ( CGContextRef c )  
  • 將當(dāng)前繪制狀態(tài)切換到繪制棧頂?shù)臓顟B(tài),棧頂?shù)臓顟B(tài)被刪除CGContextRestoreGState
void CGContextRestoreGState ( CGContextRef c )  

這兩個(gè)方法的配對(duì)使用,主要用于:該繪制動(dòng)作只想作用于該階段,不想對(duì)繼后的上下文產(chǎn)生影響.這時(shí),先存儲(chǔ)繪制狀態(tài),然后實(shí)行繪制操作A,然后再取出存儲(chǔ)的狀態(tài).這樣A操作不會(huì)對(duì)繪制狀態(tài)產(chǎn)生影響.

可存儲(chǔ)的圖像狀態(tài)[知識(shí)補(bǔ)充]

Each graphics context maintains a stack of graphics states. Note that not all aspects of the current drawing environment are elements of the graphics state. For example, the current path is not considered part of the graphics state and is therefore not saved when you call the CGContextSaveGState function. The graphics state parameters that are saved are:

CTM (current transformation matrix)

clip region

image interpolation quality

line width

line join

miter limit

line cap

line dash

flatness

should anti-alias

rendering intent

fill color space

stroke color space

fill color

stroke color

alpha value

font

font size

character spacing

text drawing mode

shadow parameters

the pattern phase

the font smoothing parameter

blend mode

示例1:切圖操作
CGFloat height = self.bounds.size.height;
CGContextTranslateCTM(context, 0.0, height);
CGContextScaleCTM(context, 1.0, -1.0);

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

CGContextDrawImage(context, CGRectMake(10.0, height - 100.0, 90.0, 90.0), self.image);

CGContextSaveGState(context);

CGRect clips[] =
    {
        CGRectMake(110.0, height - 100.0, 35.0, 90.0),
        CGRectMake(165.0, height - 100.0, 35.0, 90.0),
    };

CGContextClipToRects(context, clips, sizeof(clips) / sizeof(clips[0]));
CGContextDrawImage(context, CGRectMake(110.0, height - 100.0, 90.0, 90.0), self.image);
CGContextRestoreGState(context);  

修改剪切Path

在剪切路徑中,需要理解交匯區(qū)(intersection),如CGContextClip函數(shù)中,是 the current path 和 the current clipping path 交匯的地方可以操作,在CGContextClipToRects函數(shù)中,是the clipping path 與 the current clipping path 交匯的地方可以操作.我們經(jīng)常會(huì)需要利用CGContextSaveGState來(lái)存儲(chǔ)當(dāng)前的圖像狀態(tài)(會(huì)存儲(chǔ)clip region) ,利用CGContextRestoreGState來(lái)取出存儲(chǔ)的狀態(tài).

  • 剪切當(dāng)前Path CGContextClip,非零繞組規(guī)則
void CGContextClip ( CGContextRef c );  
  • 剪切當(dāng)前Path CGContextClip,奇偶規(guī)則
void CGContextEOClip ( CGContextRef c );  
  • 矩形框剪切CGContextClipToRect
void CGContextClipToRect ( CGContextRef c, CGRect rect );  
  • 一系列矩形框剪切CGContextClipToRects
void CGContextClipToRects ( CGContextRef c, const CGRect *rects, size_t count );  
  • 獲取剪切路徑frame
CGRect CGContextGetClipBoundingBox ( CGContextRef c );  

注:bounding box是包括了剪切路徑中所有點(diǎn)的矩形.

  • 創(chuàng)建Mask CGContextClipToMask
void CGContextClipToMask ( CGContextRef c, CGRect rect, CGImageRef mask );  

遮罩分為兩種:image mask 和 mask image.寫(xiě)到這兒,本來(lái)我想展開(kāi)解釋,但是蘋(píng)果在mask方面的函數(shù)命名,和API解釋,感覺(jué)都不統(tǒng)一,把人繞得云山霧罩.所以,我們還是拋開(kāi)蘋(píng)果來(lái)解釋吧.

此函數(shù)就是給指定矩形與當(dāng)前剪切區(qū)的重疊部分增加一個(gè)遮罩.上面提到的兩種遮罩,就是指重疊區(qū)怎么展示,是重疊區(qū)展示,還是非重疊區(qū)展示(通過(guò)alpha通道來(lái)區(qū)分).

我們常用的就是給一個(gè)圖片,圖片中alpha為1的重疊區(qū)是全透過(guò),alpha為0則不透過(guò).

繪圖

  • 繪制圖片
void CGContextDrawImage ( CGContextRef c, CGRect rect, CGImageRef image );  

其中,rect指定圖片尺寸和起始點(diǎn).

  • 平鋪
void CGContextDrawTiledImage ( CGContextRef c, CGRect rect, CGImageRef image );  

其中,rect指定平鋪圖片的尺寸和平鋪起始點(diǎn).

轉(zhuǎn)換用戶空間

  • 合并轉(zhuǎn)換CGContextConcatCTM
void CGContextConcatCTM ( CGContextRef c, CGAffineTransform transform );  
  • 獲取當(dāng)前的轉(zhuǎn)換仿射矩陣CGContextGetCTM
CGAffineTransform CGContextGetCTM ( CGContextRef c );  
  • 旋轉(zhuǎn)CGContextRotateCTM
void CGContextRotateCTM ( CGContextRef c, CGFloat angle );  
  • 縮放CGContextScaleCTM
void CGContextScaleCTM ( CGContextRef c, CGFloat sx, CGFloat sy );  
  • 平移CGContextTranslateCTM
void CGContextTranslateCTM ( CGContextRef c, CGFloat tx, CGFloat ty );  
示例1:繪制PDF
    // 我們期望PDF的繪制是以左下角作為坐標(biāo)原點(diǎn)的,所以先將當(dāng)前坐標(biāo)矩陣下移,然后翻轉(zhuǎn)
    CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    
    // Grab the first PDF page
    CGPDFPageRef page = CGPDFDocumentGetPage(self.pdfDocument, 1);
    // We're about to modify the context CTM to draw the PDF page where we want it, so save the graphics state in case we want to do more drawing
    CGContextSaveGState(context);
    // CGPDFPageGetDrawingTransform provides an easy way to get the transform for a PDF page. It will scale down to fit, including any
    // base rotations necessary to display the PDF page correctly. 
    CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, self.bounds, 0, true);
    // 合并仿射矩陣
    CGContextConcatCTM(context, pdfTransform);
    // Finally, we draw the page and restore the graphics state for further manipulations!
    CGContextDrawPDFPage(context, page);
    CGContextRestoreGState(context);  

繪制文本

示例1:繪制文本
#define kTextString "Hello From Quartz"
#define kTextStringLength strlen(kTextString)  
===========================================================================================
    CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
    CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);


    CGContextSelectFont(context, "Helvetica", 36.0, kCGEncodingMacRoman);

    CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0, -1.0));

    CGContextSetTextDrawingMode(context, kCGTextFill);
    CGContextShowTextAtPoint(context, 10.0, 30.0, kTextString, kTextStringLength);
    CGContextSetTextDrawingMode(context, kCGTextStroke);
    CGContextShowTextAtPoint(context, 10.0, 70.0, kTextString, kTextStringLength);
    CGContextSetTextDrawingMode(context, kCGTextFillStroke);
    CGContextShowTextAtPoint(context, 10.0, 110.0, kTextString, kTextStringLength);
    

    CGFontRef helvetica = CGFontCreateWithFontName((CFStringRef)@"Helvetica");
    CGContextSetFont(context, helvetica);
    CGContextSetFontSize(context, 12.0);
    CGContextSetTextDrawingMode(context, kCGTextFill);  

下載源碼

蘋(píng)果官方Sample

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容