【译】Creating a Bitmap Graphics Context

位图图形上下文接受指向包含位图存储空间的内存缓冲区的指针。当您绘制位图图形上下文时,缓冲区会更新。在您释放图形上下文之后,您可以使用指定的像素格式更新位图。

注:位图图形上下文有时用于离屏渲染。如因离屏渲染而使用位图图形上下文,请参阅 Core Graphics Layer Drawing。CGLayer对象(CGLayerRef)针对离屏渲染进行了优化,因为只要可能,Quartz会在视频帧上缓存图层。

iOS注意:iOS应用程序应该使用函数UIGraphicsBeginImageContextWithOptions,而不是使用这里描述的低级Quartz函数。如果应用程序使用Quartz创建离屏位图,则位图图形上下文使用的坐标系是默认的Quartz坐标系。相比之下,如果您的应用程序通过调用函数UIGraphicsBeginImageContextWithOptions来创建图像上下文,则UIKit将相应的转换应用于上下文的坐标系统,就像它对UIView对象的图形上下文所做的那样。这使您的应用程序可以使用相同的绘图代码,而无需担心不同的坐标系。虽然您的应用程序可以手动调整坐标转换矩阵以获得正确的结果,但在实践中,这样做没有性能优势。

您可以使用函数CGBitmapContextCreate创建位图图形上下文。该功能采用以下参数:

  • 数据。提供一个指向内存中您希望绘制渲染的目的地的指针。此内存块的大小应至少为(bytesPerRow * height)个字节。
  • 宽度。指定位图的宽度(以像素为单位)。
  • 高度。指定位图的高度(以像素为单位)。
  • bitsPerComponent。指定内存中每个像素组件使用的位数。例如,对于32位像素格式和RGB颜色空间,您可以指定每个组件8位的值。请参阅支持的像素格式。
  • bytesPerRow。指定每行位图使用的内存字节数。

提示:创建位图图形上下文时,如果确保数据和bytesPerRow是16字节对齐的,则会获得最佳性能。

  • 色彩空间。用于位图上下文的颜色空间。创建位图图形上下文时,可以提供灰色,RGB,CMYK或NULL色彩空间。有关色彩空间和色彩管理原理的详细信息,请参阅色彩管理概述。有关在Quartz中创建和使用颜色空间的信息,请参阅颜色和颜色空间。有关支持的颜色空间的信息,请参阅位图图像和图像蒙版章节中的颜色空间和位图布局。
  • 位图布局信息。 以CGBitmapInfo常量表示,该信息指定位图是否应包含alpha分量,像素中alpha分量的相对位置(如果存在),alpha分量是否为预乘,以及颜色分量是整数或浮点值。有关这些常量是什么的详细信息,以及Quartz支持的用于位图图形上下文和图像的像素格式,请参阅位图图像和图像蒙版章节中的颜色空间和位图布局。

清单2-5显示了如何创建一个位图图形上下文。当您绘制所得到的位图图形上下文时,Quartz会将您的图形作为位图数据记录在指定的内存块中。列表中的每一行代码都有详细的解释。

清单2-5创建一个位图图形上下文

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.声明一个变量来表示每行的字节数。本例中位图中的每个像素由4个字节表示;红色,绿色,蓝色和alpha各8位(字节)。

2.创建一个通用的RGB颜色空间。您也可以创建一个CMYK颜色空间。请参阅颜色和颜色空间以获取更多信息,以及讨论通用色彩空间与依赖设备的色彩空间。

3.调用calloc函数以创建并清除存储位图数据的内存块。本示例创建一个32位RGBA位图(即,每像素32位的数组,每个像素包含8位红色,绿色,蓝色和alpha信息)。位图中的每个像素占用4个字节的内存。在Mac OS X 10.6和iOS 4中,这一步可以省略 - 如果您将NULL作为位图数据传递,则Quartz自动为位图分配空间。

4.创建位图图形上下文,提供位图数据,位图的宽度和高度,每个组件的位数,每行的字节数,颜色空间以及指定位图是否应包含Alpha通道及其像素中的相对位置。常数kCGImageAlphaPremultipliedLast指示alpha分量存储在每个像素的最后一个字节中,并且颜色分量已经乘以该alpha值。有关预乘alpha的更多信息,请参阅Alpha值。

5.如果由于某种原因未创建上下文,则释放为位图数据分配的内存。

6.释放颜色空间。

7.返回位图图形上下文。调用者必须在不再需要时释放图形上下文。

清单2-6显示了调用MyCreateBitmapContext来创建位图图形上下文,使用位图图形上下文创建CGImage对象,然后将结果图像绘制到窗口图形上下文的代码。图2-3显示了绘制到窗口的图像。列表中的每一行代码都有详细的解释。

清单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);
}

以下是代码步骤解读:

1.声明一个变量来存储边界框的原点和尺寸,Quartz将绘制从位图图形上下文创建的图像。

2.将边界框的原点设置为(0,0),并将宽度和高度设置为先前声明的变量,但其声明未在此代码中显示。

3.调用应用程序提供的函数MyCreateBitmapContext(参见清单2-5)创建一个400像素宽,300像素高的位图上下文。您可以使用适合您应用程序的任何尺寸创建位图图形上下文。

4.调用Quartz 2D函数以绘制位图图形上下文。您可以用适合您应用程序的绘图代码替换此代码和接下来的四行代码。

5.从位图图形上下文创建一个Quartz 2D图像(CGImageRef)。

6.将图像绘制到由边界框指定的窗口图形上下文中的位置。边界框指定绘制图像的用户空间中的位置和尺寸。

此示例不显示创建窗口图形上下文。有关如何创建窗口图形上下文的信息,请参阅在Mac OS X中创建窗口图形上下文。

7.获取与位图图形上下文关联的位图数据。

8.不再需要时释放位图图形上下文。

9.如果存在,则释放位图数据。

10.不再需要时释放图像。

图2-3从位图图形上下文创建并绘制到窗口图形上下文的图像


cocoa_draw.gif

支持的像素格式

表2-1总结了位图图形上下文支持的像素格式,关联的颜色空间(cs)以及格式第一次可用的Mac OS X版本。 像素格式被指定为每像素位数(bpp)和每个分量位数(bpc)。 该表还包括与该像素格式相关的位图信息常量。 有关每个位图信息格式常量代表的详细信息,请参阅CGImage Reference。

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

CS Pixel format and bitmap information constant Availability
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, kCGImageAlphaNonekCGBitmapFloatComponents 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, kCGImageAlphaNoneSkipLastkCGBitmapFloatComponents Mac OS X
RGB 128 bpp, 32 bpc, kCGImageAlphaPremultipliedLastkCGBitmapFloatComponents 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

抗锯齿

位图图形上下文支持消除锯齿,这是人为地纠正绘制文本或形状时有时在位图图像中看到的锯齿状(或锯齿形)边缘的过程。当位图的分辨率明显低于眼睛的分辨率时,会出现这些锯齿状边缘。为了使对象在位图中看起来平滑,Quartz对形状轮廓周围的像素使用不同的颜色。通过以这种方式混合颜色,形状显得平滑。您可以在图2-4中看到使用抗锯齿的效果。您可以通过调用函数CGContextSetShouldAntialias来关闭特定位图图形上下文的消除锯齿。抗锯齿设置是图形状态的一部分。

您可以通过使用函数CGContextSetAllowsAntialiasing来控制是否允许对特定图形上下文进行消除锯齿。通过这个函数来实现抗锯齿;假不允许它。此设置不是图形状态的一部分。当上下文和图形状态设置设置为true时,Quartz执行消除锯齿。

图2-4混叠和抗锯齿绘图的比较


antialias.jpg
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容