圖形上下文(Graphics Context)—— Quartz 2D編程指導(dǎo)翻譯 第3篇

本文翻譯自蘋果官方文檔:原文地址

圖形上下文(Graphics Context)

圖形上下文指的是繪圖的地點(diǎn)阳柔,它包含了繪圖系統(tǒng)需要實(shí)現(xiàn)后續(xù)繪圖操作需要的參數(shù)和指定設(shè)備的所有信息。圖形上下文定義了基本的繪圖特性磷雇,如:顏色种远、裁剪區(qū)域盆耽、線的寬度和樣式轰绵、字體信息莹桅、復(fù)合選項(xiàng)等等昌执。

你能夠使用Quartz提供的上下文創(chuàng)建函數(shù)或者由 OS X 以及 iOS 提供的更高級(jí)的函數(shù)來(lái)得到一個(gè)圖形上下文。Quartz為很多不同種類的圖形上下文(如诈泼,bitmap懂拾、PDF)提供了很多函數(shù);你可以用這些來(lái)創(chuàng)建自定義的內(nèi)容铐达。

本章中岖赋,我們將教會(huì)你如何創(chuàng)建各式各樣的圖形上下文(針對(duì)不同的繪圖地點(diǎn))。在代碼中圖形上下文用一個(gè)類型為CGContextRef的數(shù)據(jù)代替瓮孙,這個(gè)數(shù)據(jù)是閉源的唐断。在你獲取到圖形上下文之后选脊,你可以使用Quartz提供的函數(shù)來(lái)進(jìn)行繪制、變換等操作脸甘。

iOS中繪制到頁(yè)面的圖形上下文(Drawing to a View Graphics Context in iOS)

在iOS的一個(gè)APP中,如果你想將內(nèi)容繪制到屏幕恳啥,你需要?jiǎng)?chuàng)建一個(gè)UIView對(duì)象并實(shí)現(xiàn)它的drawRect:方法。當(dāng)View可見并且內(nèi)容需要更新時(shí)丹诀,View的drawRect:將會(huì)被調(diào)用角寸。在調(diào)用drawRect:方法之前,這View對(duì)象自動(dòng)注冊(cè)了它的繪圖環(huán)境忿墅,以方便你能夠快速的繪制扁藕。這個(gè)UIView在注冊(cè)的過(guò)程中,創(chuàng)建了一個(gè)針對(duì)當(dāng)前繪圖環(huán)境的圖形上下文(CGContextRef類型)疚脐。你能夠在drawRect:方法中用使用UIGraphicsGetCurrentContext來(lái)獲取這個(gè)圖形上下文亿柑。

UIKit與Quartz使用著不同的坐標(biāo)系;在UIKit中棍弄,坐標(biāo)系的原點(diǎn)在左上角望薄,y軸正半軸向下延伸;而在Quartz中原點(diǎn)在左下角呼畸,y軸正半軸向上延伸痕支。UIView對(duì)象修改了當(dāng)前圖形上下文的CTM,使得坐標(biāo)系能夠與UIKit匹配蛮原。

UIView詳細(xì)的描述在View Programming Guide for iOS卧须。

在 Mac OS X 中創(chuàng)建一個(gè)窗口圖形上下文(Window Graphics Context)

當(dāng)你在 Mac OS X 中繪制時(shí),你需要?jiǎng)?chuàng)建一個(gè)適合你正在使用框架的圖形上下文儒陨。Quartz 2D 本身沒(méi)有提供函數(shù)來(lái)獲取一個(gè)窗口圖形上下文花嘶。但是,你可以使用Cocoa 框架來(lái)獲取一個(gè)在Cocoa中創(chuàng)建的窗口上下文蹦漠。

你在drawRect:中使用如下代碼來(lái)獲取上下文:

CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];

currentContext方法返回了一個(gè)屬于當(dāng)前線程的NSGraphicsContext實(shí)例椭员。graphicsPort 方法返回一個(gè)低級(jí)、指定平臺(tái)的圖形上下文笛园,它是一個(gè)Quartz圖形上下文(CGContextRef)隘击,不要被這個(gè)方法的名字弄混淆了,它是有歷史原因的研铆。想要了解更多可以看:NSGraphicsContext Class Reference埋同。

在你獲取到這個(gè)圖形上下文之后,你可以調(diào)用任何Quartz提供的繪圖方法蚜印。你還可以混合使用Quartz 2D 和 Cocoa 繪圖方法莺禁。圖 2-1 展示了一個(gè)在Cocoa View 上的繪制,它是由兩個(gè)部分重疊的矩形構(gòu)成的窄赋,一個(gè)完全不透明的紅色矩形和一個(gè)半透明的藍(lán)色矩形哟冬。你可以在顏色和色域中了解更多楼熄。你能透過(guò)顏色看到多少內(nèi)容是 Quartz 2D 的一個(gè)特征。

圖 2-1 Cocoa框架中一個(gè)包含Quartz繪圖的View

想要完成 圖 2-1 繪制的浩峡,首先在Xcode中創(chuàng)建一個(gè)Cocoa應(yīng)用程序工程可岂;然后在Interface Builder中拖拽一個(gè)自定義的View到window并子類化它;接著翰灾,在相關(guān)的子類實(shí)現(xiàn)中寫下如 列表 2-1 中的代碼缕粹。在這個(gè)例子中,這個(gè)view的類叫做MyQuartzView纸淮。該view的drawRect:方法包含了所有的Quartz繪圖代碼平斩。在列表下面有詳細(xì)的解釋。

注意:NSView的drawRect:方法在每次需要被繪制的時(shí)候都會(huì)自動(dòng)調(diào)用咽块。想了解更多關(guān)于重寫drawRect:方法的信息绘面,請(qǐng)見:NSView Class Reference

列表 2-1 在窗口圖形上下文繪制

@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

下面解釋這些代碼做了什么:

  1. 獲取view的圖形上下文侈沪。
  2. 你需要把繪圖的代碼寫到這個(gè)地方揭璃。接下來(lái)的4行使用了 Quartz 2D 的函數(shù)。
  3. 將填充色設(shè)置為一個(gè)完全不透明的紅色亭罪。關(guān)于顏色和alpha(設(shè)置透明度)瘦馍,詳見:顏色和色域
  4. 填充了一個(gè)矩形应役,這個(gè)矩形原點(diǎn)在(0,0)情组,寬度為200,高度為100扛吞。關(guān)于繪制矩形的更多內(nèi)容見:路徑(Paths)呻惕。
  5. 設(shè)置一個(gè)半透明的藍(lán)色為填充色荆责。
  6. 填充了一個(gè)原點(diǎn)在(0滥比,0),寬度為100做院,高度為200的矩形盲泛。

創(chuàng)建一個(gè)PDF圖形上下文(PDF Graphics Context)

當(dāng)你創(chuàng)建一個(gè)PDF圖形上下文并繪制時(shí),Quartz將你的繪制記錄成一系列的繪圖指令键耕,并將其寫入到一個(gè)文件寺滚。你需要為這個(gè)PDF文件指定一個(gè)輸出位置和默認(rèn)的媒體盒(定義這個(gè)頁(yè)(Page)邊界的矩形)。圖 2-2 展示了用PDF預(yù)覽將使用 PDF Graphics Context 繪制的結(jié)果打開的情形屈雄。

圖 2-2 用 CGPDFContextCreateWithURL 創(chuàng)建的PDF文件

Quartz 2D 的API 提供了兩種函數(shù)來(lái)創(chuàng)建一個(gè)PDF圖形上下文:

  • CGPDFContextCreateWithURL,當(dāng)你想為輸出的PDF文件指定一個(gè)路徑時(shí)(CoreFoundation URL)。列表 2-2 展示了如何用這個(gè)函數(shù)創(chuàng)建PDF圖形上下文雀扶。
  • CGPDFContextCreate,當(dāng)你想把PDF輸出送到一個(gè)消費(fèi)者(Consumer)處理的時(shí)候(可以在Quartz 2D的數(shù)據(jù)管理中查看更多)奶赔。列表 2-3 展示了如何用這個(gè)函數(shù)創(chuàng)建PDF圖形上下文。

對(duì)于每個(gè)標(biāo)注了數(shù)字的代碼行杠氢,都會(huì)有詳細(xì)的解釋站刑。

iOS 注意:在iOS中的PDF圖形上下文使用了Quartz提供的默認(rèn)坐標(biāo),并沒(méi)有應(yīng)用一個(gè)變換去適配UIKit的坐標(biāo)鼻百。如果你的應(yīng)用程序計(jì)劃在PDF圖形上下文和UIView提供的圖形上下文之間共享繪制代碼绞旅,你的應(yīng)用應(yīng)當(dāng)修改PDF圖形上下文的CTM從而修改坐標(biāo)系。詳見:Quartz 2D Coordinate Systems温艇。

列表 2-2 調(diào)用CGPDFContextCreateWithURL來(lái)創(chuàng)建PDF圖形上下文

CGContextRef MyPDFContextCreate (const CGRect *inMediaBox,
                                    CFStringRef path)
{
    CGContextRef myOutContext = NULL;
    CFURLRef url;
 
    url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, false); // 1
    if (url != NULL) {
        myOutContext = CGPDFContextCreateWithURL (url,
                                        inMediaBox,
                                        NULL); // 2
        CFRelease(url);// 3
    }
    return myOutContext;// 4
}

代碼解釋:

  1. 調(diào)用了 Core Foundation 的函數(shù)來(lái)用CFString創(chuàng)建一個(gè)CFURL對(duì)象因悲,這個(gè)對(duì)象稍后會(huì)被用于MyPDFContextCreate函數(shù)。對(duì)于CFURLCreateWithFileSystemPath勺爱,你傳入第一個(gè)參數(shù)為NULL時(shí)使用默認(rèn)的分配器(allocator)囤捻;同時(shí)你需要指定路徑的樣式,在這個(gè)例子中是一個(gè)POSIX-style的路徑名邻寿。
  2. 調(diào)用Quartz 2D 的函數(shù)來(lái)創(chuàng)建PDF圖形上下文蝎土,會(huì)使用到剛剛創(chuàng)建的路徑和一個(gè)指示PDF頁(yè)(Page)大小的矩形,這個(gè)矩形在調(diào)用MyPDFContextCreate時(shí)由外部傳入绣否,他表示了默認(rèn)的PDF邊界大小誊涯。
  3. 釋放CFURL對(duì)象。
  4. 返回創(chuàng)建的PDF圖形上下文對(duì)象蒜撮。調(diào)用者在不使用的時(shí)候必須釋放這個(gè)圖形上下文暴构。

列表 2-3 調(diào)用CGPDFContextCreate來(lái)創(chuàng)建PDF圖形上下文

CGContextRef MyPDFContextCreate (const CGRect *inMediaBox,
                                    CFStringRef path)
{
    CGContextRef        myOutContext = NULL;
    CFURLRef            url;
    CGDataConsumerRef   dataConsumer;
 
    url = CFURLCreateWithFileSystemPath (NULL, 
                                        path,
                                        kCFURLPOSIXPathStyle,
                                        false); // 1
 
    if (url != NULL)
    {
        dataConsumer = CGDataConsumerCreateWithURL (url);// 2
        if (dataConsumer != NULL)
        {
            myOutContext = CGPDFContextCreate (dataConsumer,
                                        inMediaBox,
                                        NULL);  // 3
            CGDataConsumerRelease (dataConsumer);// 4
        }
        CFRelease(url);// 5
    }
    return myOutContext;// 6
}

代碼解釋:

  1. 調(diào)用了 Core Foundation 的函數(shù)來(lái)用CFString創(chuàng)建一個(gè)CFURL對(duì)象,這個(gè)對(duì)象稍后會(huì)被用于MyPDFContextCreate函數(shù)段磨。對(duì)于CFURLCreateWithFileSystemPath取逾,你傳入第一個(gè)參數(shù)為NULL時(shí)使用默認(rèn)的分配器(allocator);同時(shí)你需要指定路徑的樣式苹支,在這個(gè)例子中是一個(gè)POSIX-style的路徑名砾隅。
  2. 使用CFURL對(duì)象,創(chuàng)建了一個(gè)Quartz data consumer 對(duì)象债蜜。如果你不想使用CFURL對(duì)象(例如你想要放置的輸出數(shù)據(jù)不能指定CFURL對(duì)象時(shí))晴埂,你可以利用一系列的回掉函數(shù)(callback functions)創(chuàng)建一個(gè)data consumer來(lái)代替CFURL。詳見: Quart 2D 中的數(shù)據(jù)管理寻定。
  3. 調(diào)用Quartz 2D的函數(shù)來(lái)創(chuàng)建PDF圖形上下文儒洛。
  4. 釋放data cunsumer。
  5. 釋放CFURL對(duì)象狼速。
  6. 返回創(chuàng)建的PDF圖形上下文對(duì)象琅锻。調(diào)用者在不使用的時(shí)候必須釋放這個(gè)圖形上下文。

列表 2-4 展示了MyPDFContextCreate 的使用和繪制。

列表 2-4 在PDF圖形上下文中繪制

    CGRect mediaBox;// 1
 
    mediaBox = CGRectMake (0, 0, myPageWidth, myPageHeight);// 2
    myPDFContext = MyPDFContextCreate (&mediaBox, CFSTR("test.pdf"));// 3
 
    CFStringRef myKeys[1];// 4
    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);// 5
        // ********** Your drawing code here **********// 6
        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);// 7
    CFRelease(pageDictionary);// 8
    CFRelease(myValues[0]);
    CGContextRelease(myPDFContext);

代碼解釋:

  1. 聲明用來(lái)定義PDF的media box 的矩形恼蓬。
  2. 設(shè)置矩形的原點(diǎn)沫浆、寬度和高度。
  3. 調(diào)用函數(shù)MyPDFContextCreate(列表 2-3)獲取一個(gè)PDF圖形上下文滚秩,并傳入正確的 media box 和路徑专执。CFSTR可以將一個(gè)字符串轉(zhuǎn)換成CFStringRef類型。
  4. 設(shè)置page的選項(xiàng)郁油。在這個(gè)例子中本股,只有media box 是指定了值的。你不需要傳入相同的矩形來(lái)設(shè)置PDF圖形上下文桐腌。因?yàn)閙edia box 取代了你傳入設(shè)置PDF圖形上下文的矩形拄显。
  5. 開始一個(gè)page的信號(hào)。這個(gè)方法用于面向頁(yè)面的繪圖案站,即PDF繪圖躬审。
  6. 調(diào)用Quartz 2D的繪圖函數(shù)。你可以替換接下來(lái)的這四行蟆盐,來(lái)畫你想畫的東西承边。
  7. PDF page結(jié)束的信號(hào)。
  8. 在選項(xiàng)字典和PDF圖形上下文不使用時(shí)釋放它們石挂。

你能夠在PDF中寫下任意的內(nèi)容(對(duì)于你的應(yīng)用來(lái)說(shuō)合適的內(nèi)容)博助。如:圖片、文字痹愚、基于路徑的繪圖富岳、鏈接、編碼等等拯腮。更多信息請(qǐng)見:PDF文檔的創(chuàng)建窖式、預(yù)覽和轉(zhuǎn)換

創(chuàng)建一個(gè)位圖圖形上下文(Bitmap Graphics Context)

位圖圖形上下文接收一個(gè)指向內(nèi)存的指針动壤,這片指向的區(qū)域中包含了位圖(bitmap)萝喘。當(dāng)你在位圖圖形上下文中繪制時(shí),這些字節(jié)流會(huì)得到更新狼电,當(dāng)你釋放這個(gè)圖形上下文時(shí)蜒灰,你就在你指定的像素格式下完全更新了這個(gè)bitmap。

注意:位圖圖形上下文有時(shí)候也被用來(lái)做離屏繪制肩碟。在你決定這么做之前,看看:核心圖形圖層繪畫(Core Graphics Layer Drawing)凸椿。CGLayer 對(duì)象(CCGLayerRef)針對(duì)離屏繪制有特定的優(yōu)化削祈,因?yàn)樵诳赡艿臅r(shí)候它將緩存 video card 上的涂層。

iOS 注意:iOS中的應(yīng)用程序應(yīng)當(dāng)使用UIGraphicsBeginImageContextWithOptions方法而不是這里描述的Quartz低級(jí)方法來(lái)獲取圖形上下文。如果你的應(yīng)用程序使用Quartz提供的API創(chuàng)建了一個(gè)離屏的bitmap髓抑,那么這么位圖圖形上下文會(huì)使用Quartz默認(rèn)的坐標(biāo)系咙崎。作為對(duì)比,如果你使用 UIGraphicsBeginImageContextWithOptions 來(lái)創(chuàng)建圖形上下文吨拍,那么UIKit會(huì)對(duì)其(位圖圖形上下文)使用與從UIView獲取圖形上下文相同的變換褪猛。這就允許你使用相同的坐標(biāo)系來(lái)繪制。雖然你的應(yīng)用程序能夠人為地來(lái)完成這些補(bǔ)償羹饰,但是在實(shí)際中伊滋,這樣做沒(méi)有任何好處。

你可以使用CGBitmapContextCreate函數(shù)來(lái)創(chuàng)建一個(gè)位圖圖形上下文队秩,這個(gè)函數(shù)接收下列的參數(shù):

  • 數(shù)據(jù)(data)笑旺。提供一個(gè)指向內(nèi)存的指針,指向的這個(gè)地方是你想要存放繪圖渲染的地方馍资;這塊內(nèi)存的大小至少要有(bytesPerRow*height)字節(jié)筒主。
  • 寬度(width)。指定位圖的像素寬度(單位是像素)鸟蟹。
  • 高度(height)乌妙。指定位圖圖像的高度(單位是像素)。
  • 組成部分的位數(shù)(bitsPerComponent)建钥。指定每一個(gè)像素中組件的位數(shù)(bits冠胯,二進(jìn)制位)。例如:對(duì)于32位格式的RGB色域锦针,你需要為每一個(gè)部分指定8位荠察。見:本章中的表“支持的像素格式”。
  • 每行的字節(jié)數(shù)(bytesPerRow)奈搜。指定內(nèi)存中位圖每一行的字節(jié)數(shù)悉盆。

注意:當(dāng)你創(chuàng)建一個(gè)位圖圖形上下文后,如果你確保數(shù)據(jù)(data)和每行的字節(jié)數(shù)(bitsPerCompoent)是16為對(duì)齊的馋吗,那么你將獲得最佳的性能焕盟。

  • 色域(colorspace)。位圖圖形上下文所使用的色域宏粤,你可以提供灰階(Gray)脚翘、RGB、CMYK或者NULL這些色域值給位圖圖形上下文绍哎。更多關(guān)于色域和顏色管理的細(xì)節(jié)来农,見:Color Management Overview。更多關(guān)于顏色創(chuàng)建的信息見:顏色和色域崇堰。更多支持的色域見:位圖圖像和圖像遮罩沃于。
  • 位圖信息(bitmapInfo)涩咖。位圖的布局信息,通常用一個(gè)CGBitmapInfo的常量來(lái)表示繁莹。這個(gè)信息指明了位圖是否包含alpha檩互、alpha值在一個(gè)像素中的位置、alpha值是否是預(yù)相乘的(premultiplied)以及顏色的組成到底是浮點(diǎn)還是整數(shù)值等等咨演。想要知道這些常量是什么闸昨、什么時(shí)候使用、Quartz支持的位圖圖形上下文和圖片的像素格式等信息薄风,查看:位圖圖像和圖像遮罩章節(jié)的色域和位圖布局饵较。

列表 2-5 展示了如何創(chuàng)建一個(gè)位圖圖形上下文。當(dāng)你在位圖圖形上下文中繪制時(shí)村刨,Quartz記錄你的繪圖操作告抄,并將其轉(zhuǎn)換數(shù)據(jù)存放到指定的內(nèi)存區(qū)域中。

列表 2-5 創(chuàng)建一個(gè)位圖圖形上下文

CGContextRef MyCreateBitmapContext (int pixelsWide,
                            int pixelsHigh)
{
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;
 
    bitmapBytesPerRow   = (pixelsWide * 4);// 1
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);
 
    colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);// 2
    bitmapData = calloc( bitmapByteCount, sizeof(uint8_t) );// 3
    if (bitmapData == NULL)
    {
        fprintf (stderr, "Memory not allocated!");
        return NULL;
    }
    context = CGBitmapContextCreate (bitmapData,// 4
                                    pixelsWide,
                                    pixelsHigh,
                                    8,      // bits per component
                                    bitmapBytesPerRow,
                                    colorSpace,
                                    kCGImageAlphaPremultipliedLast);
    if (context== NULL)
    {
        free (bitmapData);// 5
        fprintf (stderr, "Context not created!");
        return NULL;
    }
    CGColorSpaceRelease( colorSpace );// 6
 
    return context;// 7
}

代碼解釋:

  1. 聲明代表每行有多少字節(jié)的變量嵌牺。在這個(gè)例子中bitmap中的一個(gè)像素由4個(gè)字節(jié)表示打洼,8位的紅、綠逆粹、藍(lán)和alpha募疮。
  2. 創(chuàng)建了一個(gè)普通的RGB色域,當(dāng)然你也可以創(chuàng)建其他的色域如CMYK僻弹。在顏色和色域中你能了解到普通的(generic)色域是依賴于設(shè)備的阿浓。
  3. 調(diào)用calloc函數(shù)來(lái)創(chuàng)建一個(gè)用于存儲(chǔ)bitmap數(shù)據(jù)的內(nèi)存塊。在這個(gè)例子中創(chuàng)建了一個(gè)32位的bitmap(32位表示一個(gè)像素蹋绽,每個(gè)像素都包含8位的紅芭毙、綠、藍(lán)和aplha值)卸耘。不難看出每一個(gè)像素占用了4個(gè)字節(jié)(1個(gè)字節(jié)8位)退敦。在 Mac OS 10.6 和 iOS 4 以及之后的版本中,你可以將bitmap data 傳為NULL蚣抗,此時(shí)Quartz將自動(dòng)為你分配bitmap的存儲(chǔ)空間侈百。
  4. 調(diào)用方法創(chuàng)建一個(gè)位圖圖形上下文,傳入相應(yīng)的參數(shù)翰铡。常量kCGImageAlphaPremultipliedLast指明了alpha值被存儲(chǔ)在每個(gè)像素的最后一個(gè)字節(jié)钝域,同時(shí)它也指明了其中的顏色早已經(jīng)與alpha值相乘過(guò)了。關(guān)于alpha值的預(yù)乘(premultiplied alpha)見:The Alpha Value锭魔。
  5. 如果上下文沒(méi)有創(chuàng)建成功例证,釋放申請(qǐng)的用來(lái)存放 bitmap data 數(shù)據(jù)的內(nèi)存。
  6. 釋放色域赂毯。
  7. 返回創(chuàng)建好的位圖圖形上下文战虏。使用者需要釋放這個(gè)圖形上下文拣宰。

列表 2-6 使用先前創(chuàng)建的MyCreateBitmapContext函數(shù)來(lái)創(chuàng)建一個(gè)位圖圖形上下文党涕,然后使用這個(gè)圖形上下文創(chuàng)建了一個(gè)CGImage對(duì)象烦感,接著將這個(gè)圖片繪制到了一個(gè)窗口圖形上下文上。
圖 2-3 展示了繪制到窗口上的這個(gè)圖片膛堤。

列表 2-6 在位圖圖形上下文上繪制

    CGRect myBoundingBox;// 1
 
    myBoundingBox = CGRectMake (0, 0, myWidth, myHeight);// 2
    myBitmapContext = MyCreateBitmapContext (400, 300);// 3
    // ********** Your drawing code here ********** // 4
    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);// 5
    CGContextDrawImage(myContext, myBoundingBox, myImage);// 6
    char *bitmapData = CGBitmapContextGetData(myBitmapContext); // 7
    CGContextRelease (myBitmapContext);// 8
    if (bitmapData) free(bitmapData); // 9
    CGImageRelease(myImage);//10

代碼解釋:

  1. 聲明了一個(gè)定義了原點(diǎn)和尺寸的變量box手趣,這個(gè)變量將被用于繪制由位圖圖形上下文產(chǎn)生的圖片。
  2. 設(shè)置這個(gè)box的原點(diǎn)和寬高肥荔。
  3. 調(diào)用自定義的函數(shù)MyCreateBitmapContext(列表 2-5)來(lái)創(chuàng)建了一個(gè)寬為400px高為300px的像素绿渣。你使用任意尺寸來(lái)創(chuàng)建位圖圖形上下文。
  4. 調(diào)用Quartz 2D的函數(shù)來(lái)在這個(gè)位圖圖形上下文中繪制燕耿。你能夠自由替換下面4行繪制代碼中符。
  5. 從位圖圖形上下文中創(chuàng)建了一個(gè)Quartz 2D 圖片(CGImageRef)。
  6. 將這個(gè)圖片繪制到box指定的窗口圖形上下文中誉帅,這個(gè)有邊界的box指示的坐標(biāo)和尺寸是在用戶空間下的(user space)淀散。例子中沒(méi)有展示如何創(chuàng)建窗口圖形上下文,可以看本章中的在 Mac OS X 中創(chuàng)建一個(gè)窗口圖形上下文蚜锨。
  7. 獲取和這個(gè)位圖圖形上下文關(guān)聯(lián)的 bitmap data 指針档插。
  8. 釋放位圖圖形上下文。
  9. 如果bitmap data 存在則釋放它亚再。
  10. 在不使用的時(shí)候釋放圖片郭膛。
圖 2-3 由位圖圖形上下文產(chǎn)生的圖片,并將該圖片繪制到窗口圖形上下文

支持的像素格式(Supported Pixel Formats)

表 2-1 概括了位圖圖形上下文支持的像素格式氛悬、相關(guān)的色域(color space)则剃、Mac OS X中的可用性。像素格式由每個(gè)像素的位數(shù)(bits per pixel -- bpp)和每個(gè)部分的位數(shù)(bits per component -- bpc)表示如捅。表中同樣包含了與像素格式關(guān)聯(lián)的位圖信息常量(bitmap information constant)棍现。想要了解每一個(gè)常量代表什么可以查看:CGImage Reference

表 2-1 位圖圖形上下文支持的像素格式

色域(Color Space) 像素格式和位圖信息常量(Pixel format and bitmap information constant) 可用性
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

抗鋸齒(Anti-Aliasing)

位圖圖形上下文支持抗鋸齒伪朽≈嵩郏抗鋸齒是對(duì)繪制文字或者圖形時(shí)邊緣出現(xiàn)鋸齒狀情況的糾正。當(dāng)位圖的分辨率大大低于人眼的分辨率時(shí)烈涮,就會(huì)出現(xiàn)鋸齒朴肺。為了使繪制的內(nèi)容變得光滑,Quartz對(duì)包裹在對(duì)應(yīng)圖形形狀外的像素使用了不同的顏色坚洽。通過(guò)這樣的混色方式戈稿,這些形狀看起來(lái)就光滑了一些。你能夠從 圖 2-4 中看出來(lái)抗鋸齒的效果讶舰。同樣鞍盗,你可以在繪制特殊的位圖圖形上下文時(shí)關(guān)閉抗鋸齒(通過(guò)CGContextSetShouldAntialias方法)需了。這個(gè)抗鋸齒設(shè)置是圖形狀態(tài)的(graphics state)一部分。

你同樣也能夠使用CGContextSetAllowsAntialiasing方法針對(duì)一個(gè)特殊的圖形上下文設(shè)置其是否抗鋸齒般甲。當(dāng)函數(shù)的參數(shù)傳入true時(shí)則允許抗鋸齒肋乍。這個(gè)設(shè)置不屬于圖形狀態(tài)(graphics state)。只有當(dāng)圖形狀態(tài)和當(dāng)前上下文中的抗鋸齒都設(shè)置為true時(shí)敷存,Quartz才會(huì)進(jìn)行抗鋸齒操作墓造。

圖 2-4 抗鋸齒的使用與否對(duì)比

獲取打印使用的圖形上下文

在 Mac OS X 中的Cocoa應(yīng)用程序通過(guò)自定義的NSView子類來(lái)實(shí)現(xiàn)打印。想要打印一個(gè)view锚烦,直接調(diào)用它的print:方法觅闽;隨后,這個(gè)view創(chuàng)建了一個(gè)針對(duì)打印的圖形上下文并調(diào)用它的drawRect:方法涮俄。對(duì)于繪制到屏幕和打印機(jī)蛉拙,你的程序使用了相同的繪圖代碼。同樣也可自定義drawRect:方法彻亲,圖片這樣對(duì)于打印機(jī)的調(diào)用是不同于屏幕的(原文:It can also customize the drawRect: call to an image to the printer that is different from the one sent to the screen.)孕锄。

對(duì)于更多在Cocoa中打印的資料,請(qǐng)查看:Printing Programming Guide for Mac睹栖。


上一章:Quartz 2D 概述
下一章:路徑(Paths)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末硫惕,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子野来,更是在濱河造成了極大的恐慌恼除,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件曼氛,死亡現(xiàn)場(chǎng)離奇詭異豁辉,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)舀患,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門徽级,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人聊浅,你說(shuō)我怎么就攤上這事餐抢。” “怎么了低匙?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵旷痕,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我顽冶,道長(zhǎng)欺抗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任强重,我火速辦了婚禮绞呈,結(jié)果婚禮上贸人,老公的妹妹穿的比我還像新娘。我一直安慰自己佃声,他們只是感情好艺智,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著秉溉,像睡著了一般力惯。 火紅的嫁衣襯著肌膚如雪碗誉。 梳的紋絲不亂的頭發(fā)上召嘶,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天,我揣著相機(jī)與錄音哮缺,去河邊找鬼弄跌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛尝苇,可吹牛的內(nèi)容都是我干的铛只。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼糠溜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼淳玩!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起非竿,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蜕着,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后红柱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體承匣,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年锤悄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了韧骗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡零聚,死狀恐怖袍暴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情隶症,我是刑警寧澤政模,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站沿腰,受9級(jí)特大地震影響览徒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜颂龙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一习蓬、第九天 我趴在偏房一處隱蔽的房頂上張望纽什。 院中可真熱鬧,春花似錦躲叼、人聲如沸芦缰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)让蕾。三九已至,卻和暖如春或听,著一層夾襖步出監(jiān)牢的瞬間探孝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工誉裆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留顿颅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓足丢,卻偏偏與公主長(zhǎng)得像粱腻,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子斩跌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容