What is Quartz2D
UIView及其子類的應(yīng)用目前比較熟悉了,下面開始學(xué)習(xí)一下Quartz2D。我們從名字上來大致猜測一下這個(gè)東西是干嗎的,2D好說應(yīng)該是說的2維和3D不同。那么Quartz又是個(gè)啥呢?Quartz的本意是石英石,也有石英表的意思。在Java中有個(gè)叫Quartz的開源的作業(yè)調(diào)度框架,估計(jì)是取其石英表的含義。但是在蘋果開發(fā)中,這個(gè)名字到底怎么解釋,還真猜不到。本來想望文知意的,結(jié)果不太靠譜,那我們直接先看一看蘋果對Quartz 2D的描述
Quartz 2D is an advanced, two-dimensional drawing engine available for iOS application development and to all Mac OS X application environments outside of the kernel. Quartz 2D provides low-level, lightweight 2D rendering with unmatched output fidelity regardless of display or printing device. Quartz 2D is resolution- and device-independent; you don’t need to think about the final destination when you use the Quartz 2D application programming interface (API) for drawing.
The Quartz 2D API is easy to use and provides access to powerful features such as transparency layers, path-based drawing, offscreen rendering, advanced color management, anti-aliased rendering, and PDF document creation, display, and parsing.
The Quartz 2D API is part of the Core Graphics framework, so you may see Quartz referred to as Core Graphics or, simply, CG
這么一大段話,我們找?guī)讉€(gè)關(guān)鍵字:drawing engine, resolution, device-independent, API。
這幾個(gè)關(guān)鍵詞加起來就是說,我們可以調(diào)用Quartz 2D的接口來繪圖。至于后面的簡單易用,功能強(qiáng)大這一類的描述,看看就好,不必較真。
我們已經(jīng)知道了Quartz2D是什么,也知道它能干什么,接下來就是學(xué)習(xí)它是怎么做的。
When to use Quartz2D
討論怎么用之前,我們先了解一下什么時(shí)候用,即應(yīng)用場景。還是看蘋果給的東西吧,畢竟這玩意都是他們搞出來的。
Draw graphics
Provide graphics editing capabilities in an application
Create or display bitmap images
Work with PDF documents
對這上面這幾種翻譯一下:
1 )畫圖
這里說的畫圖,應(yīng)該是指在界面上畫線條,多邊形,弧形等。如股票軟件中的各種線條。
2)提供圖形編輯功能
圖片編輯功能復(fù)雜一點(diǎn),如照片處理一類的。
3)創(chuàng)建或者顯示位圖
4)處理PDF文檔
How to use Quartz2D
concept
我們先理解一些概念,不然理解后面說的東西比較費(fèi)勁。
1)Painter's model
看圖1來理解這個(gè)所謂的粉刷模型,就是一個(gè)粉刷效果,后面的掩蓋前面的。
2)The Graphics Context
這個(gè)可以理解為繪畫環(huán)境,比如涂鴉繪畫環(huán)境就是墻壁,油畫的繪畫環(huán)境就是畫布。開發(fā)中的繪畫環(huán)境有:位圖,PDF,窗口,圖層。
Creating a Window Graphics Context,API本身不能獲取window的Context,需要在Cocoa framework中獲取一個(gè)。
CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];//
Creating a PDF Graphics Context
CGPDFContextCreateWithURL
CGPDFContextCreate
Creating a Bitmap Graphics Context
UIGraphicsBeginImageContextWithOptions//iOS環(huán)境中用這個(gè),避免坐標(biāo)系統(tǒng)的不同
3)Opaque Data Types
數(shù)據(jù)類型很多,我們用到的時(shí)候在詳細(xì)了解。下面列一下這些數(shù)據(jù)類型和用處:
CGPathRef, used for vector graphics to create paths that you fill or stroke. SeePaths.
CGImageRef, used to represent bitmap images and bitmap image masks based on sample data that you supply. SeeBitmap Images and Image Masks.
CGLayerRef, used to represent a drawing layer that can be used for repeated drawing (such as for backgrounds or patterns) and for offscreen drawing. SeeCore Graphics Layer Drawing
CGPatternRef, used for repeated drawing. SeePatterns.
CGShadingRefandCGGradientRef, used to paint gradients. SeeGradients.
CGFunctionRef, used to define callback functions that take an arbitrary number of floating-point arguments. You use this data type when you create gradients for a shading. SeeGradients.
CGColorRefandCGColorSpaceRef, used to inform Quartz how to interpret color. SeeColor and Color Spaces.
CGImageSourceRefandCGImageDestinationRef, which you use to move data into and out of Quartz. SeeData Management in Quartz 2DandImage I/O Programming Guide.
CGFontRef, used to draw text. SeeText.
CGPDFDictionaryRef,CGPDFObjectRef,CGPDFPageRef,CGPDFStream,CGPDFStringRef,andCGPDFArrayRef, which provide access to PDF metadata. SeePDF Document Creation, Viewing, and Transforming.
CGPDFScannerRefandCGPDFContentStreamRef, which parse PDF metadata. SeePDF Document Parsing.
CGPSConverterRef, used to convert PostScript to PDF. It is not available in iOS. SeePostScript Conversion.
4)Coordinate Systems
在二維中繪圖,坐標(biāo)系的概念必不可少。指標(biāo)系統(tǒng)大家還是比較熟悉的,過多的解釋沒有必要,值得注意的是在iOS的顯示中坐標(biāo)原點(diǎn)的位置不在左下角而在左上角。
5)Path
我們想要畫一個(gè)三角形或一個(gè)圓,在現(xiàn)實(shí)中我們可以根據(jù)抽象的思維,隨意畫出三角形和圓,但是計(jì)算機(jī)怎樣能夠準(zhǔn)確的畫出我們想要的圖案呢。Path就是用來定義圖形的??梢岳斫鉃镻ath表示了圖形的輪廓,按照這個(gè)輪廓,通過填充,描繪就可以準(zhǔn)確的得到我們想要的圖案。
直接在Context上畫
創(chuàng)建可復(fù)用的Path
CGPathCreateMutable, which replacesCGContextBeginPath
CGPathMoveToPoint, which replacesCGContextMoveToPoint
CGPathAddLineToPoint, which replacesCGContextAddLineToPoint
CGPathAddCurveToPoint, which replacesCGContextAddCurveToPoint
CGPathAddEllipseInRect, which replacesCGContextAddEllipseInRect
CGPathAddArc, which replacesCGContextAddArc
CGPathAddRect, which replacesCGContextAddRect
CGPathCloseSubpath, which replacesCGContextClosePath
將Path加到Context上CGContextAddPath.
有了Path了我們就可以涂鴉啦,哦不對,是Paint.有兩種方式,填充(filling)和筆畫(stroking)。
Parameters That Affect Stroking
Parameter:Function to set parameter value
Line width:CGContextSetLineWidth//線寬度
Line join:CGContextSetLineJoin//連接處的風(fēng)格設(shè)置
Line cap:CGContextSetLineCap//兩端的風(fēng)格
Miter limit:CGContextSetMiterLimit //
Line dash pattern:CGContextSetLineDash
Stroke color space:CGContextSetStrokeColorSpace
Stroke color:CGContextSetStrokeColorCGContextSetStrokeColorWithColor
Stroke pattern:CGContextSetStrokePattern
Functions that fill paths
CGContextEOFillPath
Fills the current path using the even-odd rule.
CGContextFillPath
Fills the current path using the nonzero winding number rule.
CGContextFillRect
Fills the area that fits inside the specified rectangle.
CGContextFillRects
Fills the areas that fits inside the specified rectangles.
CGContextFillEllipseInRect
Fills an ellipse that fits inside the specified rectangle.
CGContextDrawPath
Fills the current path if you pass kCGPathFill(nonzero winding number rule) or kCGPathEOFill(even-odd rule). Fills and strokes the current path if you pass kCGPathFillStroke or kCGPathEOFillStroke.
6)Color and Color Space
顏色的相關(guān)內(nèi)容。
7) Transform
如圖,Transform說的就是這樣的一些變換??s放、移動(dòng),旋轉(zhuǎn)等。有坐標(biāo)系作為基礎(chǔ),這些變化對應(yīng)相應(yīng)的數(shù)學(xué)知識就很好理解了。簡單的直接調(diào)用API即可,復(fù)雜的變換可能要涉及到數(shù)學(xué)內(nèi)容,比如矩陣變換等,這些東西不在討論范圍。明白可能用到這些就好了
8)Partterns
9)Shadows
陰影可以讓2D的圖形有3D的視覺效果。
10)Gradient
有時(shí)候一種顏色,或者簡單疊加的顏色看起來很枯燥乏味,我們用漸變讓圖形更豐富。
理解了這些東西了,也很無聊的了,來個(gè)例子吧,看看這些東西到底是怎么玩的。
@implementation MyQuartzView
- (id)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
return self;
}
- (void)drawRect:(NSRect)rect
{
CGContextRef myContext = [[NSGraphicsContext
currentContext] graphicsPort]; // 1
// ********** Your drawing code here **********// 2
CGContextSetRGBFillColor (myContext, 1, 0, 0, 1);// 3
CGContextFillRect (myContext, CGRectMake (0, 0, 200, 100 ));// 4
CGContextSetRGBFillColor (myContext, 0, 0, 1, .5);// 5
CGContextFillRect (myContext, CGRectMake (0, 0, 100, 200));// 6
}
@end
得到的效果如圖2
1.獲取Context
2.準(zhǔn)備繪圖
3.設(shè)置填充顏色(涉及到Color相關(guān)內(nèi)容)
4.填充矩形區(qū)域(涉及到path相關(guān)內(nèi)容)
5.再次設(shè)置顏色(透明相關(guān))
6.填充矩形區(qū)域(根據(jù)Painter's Model 覆蓋,重疊區(qū)域的覆蓋)
Demo
1)QuartzLines
簡單畫線
-(void)drawInContext:(CGContextRef)context
{
// Drawing lines with a white stroke color
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
// Draw them with a 2.0 stroke width so they are a bit more visible.
CGContextSetLineWidth(context, 2.0);
// Draw a single line from left to right
CGContextMoveToPoint(context, 10.0, 30.0);
CGContextAddLineToPoint(context, 310.0, 30.0);
CGContextStrokePath(context);
// Draw a connected sequence of line segments
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),
};
// Bulk call to add lines to the current path.
// Equivalent to MoveToPoint(points[0]); for(i=1; i < count,++i) AddLineToPoint(points[i]);
CGContextAddLines(context, addLines, sizeof(addLines)/sizeof(addLines[0]));
CGContextStrokePath(context);
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),
};
// Bulk call to stroke a sequence of line segments.
CGContextStrokeLineSegments(context, strokeSegments, sizeof(strokeSegments)/sizeof(strokeSegments[0])); ?
cap and join
-(void)drawInContext:(CGContextRef)context
{
// Drawing lines with a white stroke color
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
// Preserve the current drawing state
CGContextSaveGState(context);
// Setup the horizontal line to demostrate caps
CGContextMoveToPoint(context, 40.0, 30.0);
CGContextAddLineToPoint(context, 280.0, 30.0);
// Set the line width & cap for the cap demo
CGContextSetLineWidth(context, self.width);
CGContextSetLineCap(context, self.cap);
CGContextStrokePath(context);
// Restore the previous drawing state, and save it again.
CGContextRestoreGState(context);
CGContextSaveGState(context);
// Setup the angled line to demonstrate joins
CGContextMoveToPoint(context, 40.0, 190.0);
CGContextAddLineToPoint(context, 160.0, 70.0);
CGContextAddLineToPoint(context, 280.0, 190.0);
// Set the line width & join for the join demo
CGContextSetLineWidth(context, self.width);
CGContextSetLineJoin(context, self.join);
CGContextStrokePath(context);
// Restore the previous drawing state.
CGContextRestoreGState(context);
// If the stroke width is large enough, display the path that generated these lines
if (self.width >= 4.0) // arbitrarily only show when the line is at least twice as wide as our target stroke
{
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextMoveToPoint(context, 40.0, 30.0);
CGContextAddLineToPoint(context, 280.0, 30.0);
CGContextMoveToPoint(context, 40.0, 190.0);
CGContextAddLineToPoint(context, 160.0, 70.0);
CGContextAddLineToPoint(context, 280.0, 190.0);
CGContextSetLineWidth(context, 2.0);
CGContextStrokePath(context);
}
}
-(void)setCap:(CGLineCap)c
{
if(c != _cap)
{
_cap = c;
[self setNeedsDisplay];
}
}
-(void)setJoin:(CGLineJoin)j
{
if(j != _join)
{
_join = j;
[self setNeedsDisplay];
}
}
-(void)setWidth:(CGFloat)w
{
if(w != _width)
{
_width = w;
[self setNeedsDisplay];
}
}
2)QuartzPoly
3)QuartzGradient
4)QuartzDash
5)QuartzPolygons
6)QuartzCurves
7)QuartzImages
8)QuartzRendering
9) QuartzClipping
2到9的內(nèi)容就不一一貼代碼和貼圖了。這些內(nèi)容不用記得太清楚,用的時(shí)候有個(gè)印象能快速查詢到相關(guān)文檔既可以了。