標籤:style blog http color os 使用 io strong 檔案
一個Graphics Context表示一個繪製目標。它包含繪製系統用於完成繪製指令的繪製參數和裝置相關資訊。Graphics Context定義了基本的繪製屬性,如顏色、裁減地區、線條寬度和樣式資訊、字型資訊、混合模式等。
我們可以通過幾種方式來擷取Graphics Context:Quartz提供的建立函數、Mac OS X架構或IOS的UIKit架構提供的函數。Quartz提供了多種Graphics Context的建立函數,包括bitmap和PDF,我們可以使用這些Graphics Context建立自訂的內容。
本章介紹了如何為不同的繪製目標建立Graphics Context。在代碼中,我們用CGContextRef來表示一個Graphics Context。當獲得一個Graphics Context後,可以使用Quartz 2D函數在上下文(context)中進行繪製、完成操作(如平移)、修改圖形狀態參數(如線寬和填充顏色)等。
在iOS中的視圖Graphics Context進行繪製
在iOS應用程式中,如果要在螢幕上進行繪製,需要建立一個UIView對象,並實現它的drawRect:方法。視圖的drawRect:方法在視圖顯示在螢幕上及它的內容需要更新時被調用。在調用自訂的drawRect:後,視圖對象自動設定繪圖環境以便代碼能立即執行繪圖操作。作為配置的一部分,視圖對象將為當前的繪圖環境建立一個Graphics Context。我們可以通過調用UIGraphicsGetCurrentContext函數來擷取這個Graphics Context。
UIKit預設的座標系統與Quartz不同。在UIKit中,原點位於左上方,y軸正方向為向下。UIView通過將修改Quartz的Graphics Context的CTM[原點平移到左下角,同時將y軸反轉(y值乘以-1)]以使其與UIView匹配。
在Mac OS X中建立一個視窗Graphics Context
在Mac OS X中繪製時,我們需要建立一個視窗Graphics Context。Quartz 2D API 沒有提供函數來擷取視窗Graphics Context。取而代之的是用Cocoa架構來擷取一個視窗上下文。
我們可以在Cocoa應用程式的drawRect:中擷取一個Quartz Graphics Context,如下代碼所示:
複製代碼
- CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];
|
currentContext方法在當前線程中返回NSGraphicsContext執行個體。graphicsPort方法返回一個低層級、平台相關的Graphics Context(Quartz Graphics Context)。
在擷取到Graphics Context後,我們可以在Cocoa應用程式中調用任何Quartz 2D的繪製函數。我們同樣可以將Quartz 2D與Cocoa繪製操作混合使用。2-1是一個在Cocoa視圖中用Quartz 2D繪製的執行個體。繪圖由兩個長方形組成(一個不透明的紅色長方形和半透明的藍色長方形)。
為了實現圖2-1執行個體,需要先建立一個Cocoa應用程式。在Interface Builder中,拖動一個Custom View到視窗中,並子類化。然後實現子類別檢視的,如代碼清單2-1所示。視圖的drawRect:包含了所有的Quartz繪製代碼。
引用註:NSView的drawRect:方法在每次視圖需要繪製時自動調用。
複製代碼
- Listing 2-1 Drawing to a window graphics context
- @implementation MyQuartzView
- - (id)initWithFrame:(NSRect)frameRect
- {
- self = [super initWithFrame:frameRect];
- return self;
- }
-
- - (void)drawRect:(NSRect)rec
- {
- 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
|
代碼說明:
1.為視圖擷取一個Graphics Context
2.插入繪圖代碼的地方。以下四行是使用Quartz 2D函數的例子
3.設定完全不透明的紅色填充色。
4.填充一個長方形,其原點為(0, 0), 大小為(200, 100)
5.設定半透明的藍色填充色。
6.填充一個長方形,其原點為(0, 0), 大小為(100, 200)
建立一個PDF Graphics Context
當建立一個PDF Graphics Context並繪製時,Quartz將繪製操作記錄為一系列的PDF繪製命令並寫入檔案中。我們需要提供一個PDF輸出的位置及一個預設的media box(用於指定頁面邊界的長方形)。圖2-2顯示了在PDF Graphics Context中繪製及在preview開啟PDF的結果。
Quartz 2D API提供了兩個函數來建立PDF Graphics Context:
- CGPDFContextCreateWithURL:當你需要用Core Foundation URL指定pdf輸出的位置時使用該函數。代碼清單2-2顯示了該函數的使用方法(代碼2-2及後面代碼的詳細解釋略):
複製代碼
- Listing 2-2 Calling CGPDFContextCreateWithURL to create a PDF graphics context
- CGContextRef MyPDFContextCreate (const CGRect *inMediaBox, CFStringRef path)
- {
- CGContextRef myOutContext = NULL;
- CFURLRef url;
- url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, false);
-
- if (url != NULL) {
- myOutContext = CGPDFContextCreateWithURL (url, inMediaBox, NULL);
- CFRelease(url);
- }
- return myOutContext;
- }
|
- CGPDFContextCreate:當需要將pdf輸出發送給資料使用者時使用該方法。代碼清單2-3顯示了該函數的使用方法:
複製代碼
- Listing 2-3 Calling CGPDFContextCreate to create a PDF graphics context
- CGContextRef MyPDFContextCreate (const CGRect *inMediaBox, CFStringRef path)
- {
- CGContextRef myOutContext = NULL;
- CFURLRef url;
- CGDataConsumerRef dataConsumer;
-
- url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, false);
-
- if (url != NULL)
- {
- dataConsumer = CGDataConsumerCreateWithURL (url);
- if (dataConsumer != NULL)
- {
- myOutContext = CGPDFContextCreate (dataConsumer, inMediaBox, NULL);
- CGDataConsumerRelease (dataConsumer);
- }
-
- CFRelease(url);
- }
-
- return myOutContext;
- }
|
代碼清單2-4顯示是如何調用MyPDFContextCreate程式及繪製操作。
複製代碼
- Listing 2-4 Drawing to a PDF graphics context
- CGRect mediaBox;
-
- mediaBox = CGRectMake (0, 0, myPageWidth, myPageHeight);
- myPDFContext = MyPDFContextCreate (&mediaBox, CFSTR("test.pdf"));
-
- CFStringRef myKeys[1];
- CFTypeRef myValues[1];
-
- myKeys[0] = kCGPDFContextMediaBox;
- myValues[0] = (CFTypeRef) CFDataCreate(NULL,(const UInt8 *)&mediaBox, sizeof (CGRect));
-
- CFDictionaryRef pageDictionary = CFDictionaryCreate(NULL, (const void **) myKeys,
- (const void **) myValues, 1,
- &kCFTypeDictionaryKeyCallBacks,
- & kCFTypeDictionaryValueCallBacks);
-
- CGPDFContextBeginPage(myPDFContext, &pageDictionary);
- // ********** Your drawing code here **********
- CGContextSetRGBFillColor (myPDFContext, 1, 0, 0, 1);
- CGContextFillRect (myPDFContext, CGRectMake (0, 0, 200, 100 ));
- CGContextSetRGBFillColor (myPDFContext, 0, 0, 1, .5);
- CGContextFillRect (myPDFContext, CGRectMake (0, 0, 100, 200 ));
- CGPDFContextEndPage(myPDFContext);
-
- CFRelease(pageDictionary);
- CFRelease(myValues[0]);
- CGContextRelease(myPDFContext);
|
我們可以將任何內容(圖片,文本,繪製路徑)繪製到pdf中,並能添加連結及加密。
建立位元影像Graphics Context
一個位元影像Graphics Context接受一個指向記憶體緩衝(包含位元影像儲存空間)的指標,當我們繪製一個位元影像Graphics Context時,該緩衝被更新。在釋放Graphics Context後,我們將得到一個我們指定像素格式的全新的位元影像。
引用註:位元影像Graphics Context有時用於後台繪製。CGLayer對象最佳化了後台繪製,因為Quartz在顯卡上緩衝了層。
引用iOS提示:iOS應用程式使用了UIGraphicsBeginImageContextWithOptions取代Quartz低層函數。如果使用Quartz建立一下後台bitmap,bitmap Graphics Context使用的座標系統是Quartz預設的座標系統。而使用UIGraphicsBeginImageContextWithOptions建立圖形上下文,UIKit將會對座標系統使用與UIView對象的圖形上下文一樣的轉換。這允許應用程式使用相同的繪製代碼而不需要擔心座標系統問題。雖然我們的應用程式可以手動調整CTM達到相同的效果,但這種做沒有任何好處。
我們使用CGBitmapContextCreate來建立位元影像Graphics Context,該函數有如下參數:
- data:一個指向記憶體目標的指標,該記憶體用於儲存需要渲染的圖形資料。記憶體塊的大小至少需要(bytePerRow * height)位元組。
- width:指定位元影像的寬度,單位是像素(pixel)。
- height:指定位元影像的高度, 單位是像素(pixel)。
- bitsPerComponent:指定記憶體中一個像素的每個組件使用的位元。例如,一個32位的像素格式和一個rgb色彩空間,我們可以指定每個組件為8位。
- bytesPerRow:指定位元影像每行的位元組數。
- colorspace:色彩空間用於位元影像上下文。在建立位元影像Graphics Context時,我們可以使用灰階(gray), RGB, CMYK, NULL色彩空間。
- bitmapInfo:位元影像的資訊,這些資訊用於指定位元影像是否需要包含alpha組件,像素中alpha組件的相對位置(如果有的話),alpha組件是否是預乘的,及顏色組件是整型值還是浮點值。
代碼清單2-5顯示了如何建立位元影像Graphics Context。當向位元影像Graphics Context繪圖時,Quartz將繪圖記錄到記憶體中指定的塊中。
複製代碼
- Listing 2-5 Creating a bitmap graphics context
- CGContextRef MyCreateBitmapContext (int pixelsWide, int pixelsHigh)
- {
- CGContextRef context = NULL;
- CGColorSpaceRef colorSpace;
- void * bitmapData;
- int bitmapByteCount;
- int bitmapBytesPerRow;
-
- bitmapBytesPerRow = (pixelsWide * 4);
- bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
- colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
- bitmapData = calloc( bitmapByteCount );
- if (bitmapData == NULL)
- {
- fprintf (stderr, "Memory not allocated!");
- return NULL;
- }
- context = CGBitmapContextCreate (bitmapData, pixelsWide, pixelsHigh, 8, bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
-
- if (context== NULL)
- {
- free (bitmapData);
- fprintf (stderr, "Context not created!");
- return NULL;
- }
- CGColorSpaceRelease( colorSpace );
- return context;
- }
|
代碼清單2-6顯示了調用MyCreateBitmapContext 建立一個位元影像Graphics Context,使用位元影像Graphics Context來建立CGImage對象,然後將圖片繪製到視窗Graphics Context中。繪製結果2-3所示:
複製代碼
- Listing 2-6 Drawing to a bitmap graphics context
- CGRect myBoundingBox;
- myBoundingBox = CGRectMake (0, 0, myWidth, myHeight);
- myBitmapContext = MyCreateBitmapContext (400, 300);
-
- // ********** Your drawing code here **********
- CGContextSetRGBFillColor (myBitmapContext, 1, 0, 0, 1);
- CGContextFillRect (myBitmapContext, CGRectMake (0, 0, 200, 100 ));
- CGContextSetRGBFillColor (myBitmapContext, 0, 0, 1, .5);
- CGContextFillRect (myBitmapContext, CGRectMake (0, 0, 100, 200 ));
- myImage = CGBitmapContextCreateImage (myBitmapContext);
- CGContextDrawImage(myContext, myBoundingBox, myImage);
- char *bitmapData = CGBitmapContextGetData(myBitmapContext);
- CGContextRelease (myBitmapContext);
- if (bitmapData) free(bitmapData);
- CGImageRelease(myImage);
|
支援的像素格式
表2-1總結了位元影像Graphics Context支援的像素格式,相關的色彩空間及像素格式支援的Mac OS X最早版本。像素格式用bpp(每像素的位元)和bpc(每個組件的位元)來表示。表格同時也包含與像素格式相關的位元影像資訊常量。
表2-1:位元影像Graphics Context支援的像素格式
| Null |
8 bpp, 8 bpc, kCGImageAlphaOnly |
Mac OS X, iOS |
| Gray |
8 bpp, 8 bpc,kCGImageAlphaNone |
Mac OS X, iOS |
| Gray |
8 bpp, 8 bpc,kCGImageAlphaOnly |
Mac OS X, iOS |
| Gray |
16 bpp, 16 bpc, kCGImageAlphaNone |
Mac OS X |
| Gray |
32 bpp, 32 bpc, kCGImageAlphaNone|kCGBitmapFloatComponents |
Mac OS X |
| RGB |
16 bpp, 5 bpc, kCGImageAlphaNoneSkipFirst |
Mac OS X, iOS |
| RGB |
32 bpp, 8 bpc, kCGImageAlphaNoneSkipFirst |
Mac OS X, iOS |
| RGB |
32 bpp, 8 bpc, kCGImageAlphaNoneSkipLast |
Mac OS X, iOS |
| RGB |
32 bpp, 8 bpc, kCGImageAlphaPremultipliedFirst |
Mac OS X, iOS |
| RGB |
32 bpp, 8 bpc, kCGImageAlphaPremultipliedLast |
Mac OS X, iOS |
| RGB |
64 bpp, 16 bpc, kCGImageAlphaPremultipliedLast |
Mac OS X |
| RGB |
64 bpp, 16 bpc, kCGImageAlphaNoneSkipLast |
Mac OS X |
| RGB |
128 bpp, 32 bpc, kCGImageAlphaNoneSkipLast |kCGBitmapFloatComponents |
Mac OS X |
| RGB |
128 bpp, 32 bpc, kCGImageAlphaPremultipliedLast |kCGBitmapFloatComponents |
Mac OS X |
| CMYK |
32 bpp, 8 bpc, kCGImageAlphaNone |
Mac OS X |
| CMYK |
64 bpp, 16 bpc, kCGImageAlphaNone |
Mac OS X |
| CMYK |
128 bpp, 32 bpc, kCGImageAlphaNone |kCGBitmapFloatComponents |
Mac OS X |
反鋸齒
位元影像Graphics Context支援反鋸齒,這一操作是人為的較正在位元影像中繪製文本或形狀時產生的鋸齒邊緣。當位元影像的分辯率明顯低於人眼的分辯率時就會產生鋸齒。為了使位元影像中的對象顯得平滑,Quartz使用不同的顏色來填充形狀周邊的像素。通過這種方式來混合顏色,使形狀看起來更平滑。2-4顯示的效果。我們可以通過調用CGContextSetShouldAntialias來關閉位元影像Graphics Context的反鋸齒效果。反鋸齒設定是圖形狀態的一部分。
可以調用函數CGContextSetAllowsAntialiasing來控制一個特定Graphics Context是否支援反鋸齒;false表示不支援。該設定不是圖形狀態的一部分。當上下文及圖形狀態設定為true時,Quartz執行反鋸齒。
擷取列印的Graphics Context
Mac OS X中的Cocoa應用程式通過自訂的NSView子類來實現列印。一個視圖通過調用print:方法來進行列印。然後視圖以印表機為目標建立一個Graphics Context,並調用drawRect:方法。應用程式使用與在螢幕進行繪製相同的繪製代碼。我們同樣可以自訂drawRect: 方法將圖形繪製到印表機。
原帖地址:http://www.cocoachina.com/bbs/read.php?tid=78029
Quartz 2D編程指南(2) - 圖形上下文