Quartz 2D 编程指南二:图形上下文

2017-05-29  本文已影响195人  bobociel
logo.PNG

Graphics Contexts

A graphics context represents a drawing destination. It contains drawing parameters and all device-specific information that the drawing system needs to perform any subsequent drawing commands. A graphics context defines basic drawing attributes such as the colors to use when drawing, the clipping area, line width and style information, font information, compositing options, and several others.

一个Graphics Context表示一个绘制目标。它包含绘制系统用于完成绘制指令的绘制参数和设备相关信息。Graphics Context定义了基本的绘制属性,如颜色、裁减区域、线条宽度和样式信息、字体信息、混合模式等

You can obtain a graphics context by using Quartz context creation functions or by using higher-level functions provided by one of the Mac OS X frameworks or the UIKit framework in iOS. Quartz provides functions for various flavors of Quartz graphics contexts including bitmap and PDF, which you can use to create custom content.

我们可以通过几种方式来获取Graphics Context:Quartz提供的创建函数、Mac OS X框架或IOS的UIKit框架提供的函数。Quartz提供了多种Graphics Context的创建函数,包括bitmap和PDF,我们可以使用这些Graphics Context创建自定义的内容。

This chapter shows you how to create a graphics context for a variety of drawing destinations. A graphics context is represented in your code by the data type CGContextRef, which is an opaque data type. After you obtain a graphics context, you can use Quartz 2D functions to draw to the context, perform operations (such as translations) on the context, and change graphics state parameters, such as line width and fill color.

本章介绍了如何为不同的绘制目标创建Graphics Context。在代码中,我们用CGContextRef来表示一个Graphics Context。当获得一个Graphics Context后,可以使用Quartz 2D函数在上下文(context)中进行绘制、完成操作(如平移)、修改图形状态参数(如线宽和填充颜色)等

Drawing to a View Graphics Context in iOS

To draw to the screen in an iOS application, you set up a UIView object and implement its drawRect: method to perform drawing. The view’s drawRect: method is called when the view is visible onscreen and its contents need updating. Before calling your custom drawRect: method, the view object automatically configures its drawing environment so that your code can start drawing immediately. As part of this configuration, the UIView object creates a graphics context (a CGContextRef opaque type) for the current drawing environment. You obtain this graphics context in your drawRect: method by calling the UIKit function UIGraphicsGetCurrentContext.

在iOS应用程序中,如果要在屏幕上进行绘制,需要创建一个UIView对象,并实现它的drawRect:方法。视图的drawRect:方法在视图显示在屏幕上及它的内容需要更新时被调用。在调用自定义的drawRect:后,视图对象自动配置绘图环境以便代码能立即执行绘图操作。作为配置的一部分,视图对象将为当前的绘图环境创建一个Graphics Context。我们可以通过调用UIGraphicsGetCurrentContext函数来获取这个Graphics Context。

The default coordinate system used throughout UIKit is different from the coordinate system used by Quartz. In UIKit, the origin is in the upper-left corner, with the positive-y value pointing downward. The UIView object modifies the CTM of the Quartz graphics context to match the UIKit conventions by translating the origin to the upper left corner of the view and inverting the y-axis by multiplying it by -1. For more information on modified-coordinate systems and the implications in your own drawing code, see Quartz 2D Coordinate Systems.
UIView objects are described in detail in View Programming Guide for iOS.

UIKit默认的坐标系统与Quartz不同。在UIKit中,原点位于左上角,y轴正方向为向下。UIView通过将修改Quartz的Graphics Context的CTM[原点平移到左下角,同时将y轴反转(y值乘以-1)]以使其与UIView匹配。

Creating a Window Graphics Context in Mac OS X

When drawing in Mac OS X, you need to create a window graphics context that’s appropriate for the framework you are using. The Quartz 2D API itself provides no functions to obtain a windows graphics context. Instead, you use the Cocoa framework to obtain a context for a window created in Cocoa.

在Mac OS X中绘制时,我们需要创建一个窗口Graphics Context。Quartz 2D API 没有提供函数来获取窗口Graphics Context。取而代之的是用Cocoa框架来获取一个窗口上下文。

You obtain a Quartz graphics context from within the drawRect: routine of a Cocoa application using the following line of code:** CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];**

我们可以在Cocoa应用程序的drawRect:中获取一个Quartz Graphics Context,如下代码所示:

CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];

The method currentContext returns the NSGraphicsContext instance of the current thread. The method graphicsPort returns the low-level, platform-specific graphics context represented by the receiver, which is a Quartz graphics context. (Don’t get confused by the method names; they are historical.) For more information see NSGraphicsContext Class Reference.

currentContext方法在当前线程中返回NSGraphicsContext实例。graphicsPort方法返回一个低级别、平台相关的Graphics Context(Quartz Graphics Context)。

After you obtain the graphics context, you can call any of the Quartz 2D drawing functions in your Cocoa application. You can also mix Quartz 2D calls with Cocoa drawing calls. You can see an example of Quartz 2D drawing to a Cocoa view by looking atFigure 2-1. The drawing consists of two overlapping rectangles, an opaque red one and a partially transparent blue one. You’ll learn more about transparency in Color and Color Spaces. The ability to control how much you can “see through” colors is one of the hallmark features of Quartz 2D.

在获取到Graphics Context后,我们可以在Cocoa应用程序中调用任何Quartz 2D的绘制函数。我们同样可以将Quartz 2D与Cocoa绘制操作混合使用。如图2-1是一个在Cocoa视图中用Quartz 2D绘制的实例。绘图由两个长方形组成(一个不透明的红色长方形和半透明的蓝色长方形)。

[图片上传失败...(image-688a62-1534605915675)]

To create the drawing in Figure 2-1, you first create a Cocoa application Xcode project. In Interface Builder, drag a Custom View to the window and subclass it. Then write an implementation for the subclassed view, similar to what Listing 2-1 shows. For this example, the subclassed view is named MyQuartzView. The drawRect: method for the view contains all the Quartz drawing code. A detailed explanation for each numbered line of code appears following the listing.

为了实现图2-1实例,需要先创建一个Cocoa应用程序。在Interface Builder中,拖动一个Custom View到窗口中,并子类化。然后实现子类视图的,如代码清单2-1所示。视图的drawRect:包含了所有的Quartz绘制代码。

Note: The drawRect: method of the NSView class is invoked automatically each time the view needs to be drawn. To find out more about overriding the drawRect: method, see NSView Class Reference.

注: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)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

Here’s what the code does:

代码说明:
1.为视图获取一个Graphics Context
2.插入绘图代码的地方。以下四行是使用Quartz 2D函数的例子
3.设置完全不透明的红色填充色。
4.填充一个长方形,其原点为(0, 0), 大小为(200, 100)
5.设置半透明的蓝色填充色。
6.填充一个长方形,其原点为(0, 0), 大小为(100, 200)

Creating a PDF Graphics Context

When you create a PDF graphics context and draw to that context, Quartz records your drawing as a series of PDF drawing commands written to a file. You supply a location for the PDF output and a default media box—a rectangle that specifies bounds of the page. Figure 2-2 shows the result of drawing to a PDF graphics context and then opening the resulting PDF in Preview.

当创建一个PDF Graphics Context并绘制时,Quartz将绘制操作记录为一系列的PDF绘制命令并写入文件中。我们需要提供一个PDF输出的位置及一个默认的media box(用于指定页面边界的长方形)。图2-2显示了在PDF Graphics Context中绘制及在preview打开PDF的结果。

[图片上传失败...(image-ab7093-1534605915675)]

The Quartz 2D API provides two functions that create a PDF graphics context:

A detailed explanation for each numbered line of code follows each listing.

Quartz 2D API提供了两个函数来创建PDF Graphics Context:

iOS Note: A PDF graphics context in iOS uses the default coordinate system provided by Quartz, without applying a transform to match the UIKit coordinate system. If your application plans on sharing drawing code between your PDF graphics context and the graphics context provided by UIView object, your application should modify the CTM of the PDF graphics context to modify the coordinate system. See Quartz 2D Coordinate Systems.

iOS中的PDF图形上下文使用Quartz提供的默认坐标系,而不应用变换来匹配UIKit坐标系。 如果您的应用程序计划在PDF图形上下文和UIView对象提供的图形上下文之间共享绘图代码,则应用程序应修改PDF图形上下文的CTM以修改坐标系。 参见Quartz 2D坐标系。

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, // 1
                                path,
                                kCFURLPOSIXPathStyle,
                                false);
    if (url != NULL) {
        myOutContext = CGPDFContextCreateWithURL (url,// 2
                                        inMediaBox,
                                        NULL);
        CFRelease(url);// 3
    }
    return myOutContext;// 4
}

Here’s what the code does:

代码说明:

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, // 1
                                        path,
                                        kCFURLPOSIXPathStyle,
                                        false);
 
    if (url != NULL)
    {
        dataConsumer = CGDataConsumerCreateWithURL (url);// 2
        if (dataConsumer != NULL)
        {
            myOutContext = CGPDFContextCreate (dataConsumer, // 3
                                        inMediaBox,
                                        NULL);
            CGDataConsumerRelease (dataConsumer);// 4
        }
        CFRelease(url);// 5
    }
    return myOutContext;// 6
}

Here’s what the code does:

代码说明:

Listing 2-4 shows how to call the MyPDFContextCreate
routine and draw to it. A detailed explanation for each numbered line of code appears following the listing.

Listing 2-4 Drawing to a PDF graphics context

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);

Here’s what the code does:

You can write any content to a PDF that’s appropriate for your application—images, text, path drawing—and you can add links and encryption. For more information see PDF Document Creation, Viewing, and Transforming.

代码说明:

Creating a Bitmap Graphics Context

A bitmap graphics context accepts a pointer to a memory buffer that contains storage space for the bitmap. When you paint into the bitmap graphics context, the buffer is updated. After you release the graphics context, you have a fully updated bitmap in the pixel format you specify.

位图图形上下文接受指向包含位图存储空间的内存缓冲区的指针。 当您绘制到位图图形上下文中时,缓冲区将被更新。 释放图形上下文后,您将以指定的像素格式完全更新位图。

Note: Bitmap graphics contexts are sometimes used for drawing offscreen. Before you decide to use a bitmap graphics context for this purpose, see Core Graphics Layer Drawing. CGLayer objects (CGLayerRef) are optimized for offscreen drawing because, whenever possible, Quartz caches layers on the video card.

注意:位图图形上下文有时用于离屏渲染。 在决定为此目的使用位图图形上下文之前,请参阅Core Graphics Layer Drawing。 CGLayer对象(CGLayerRef)针对屏幕外绘图进行了优化,因为,Quartz会尽可能地将layers缓存到显卡上。

iOS Note: iOS applications should use the function UIGraphicsBeginImageContextWithOptions instead of using the low-level Quartz functions described here. If your application creates an offscreen bitmap using Quartz, the coordinate system used by bitmap graphics context is the default Quartz coordinate system. In contrast, if your application creates an image context by calling the function UIGraphicsBeginImageContextWithOptions, UIKit applies the same transformation to the context’s coordinate system as it does to a UIView object’s graphics context. This allows your application to use the same drawing code for either without having to worry about different coordinate systems. Although your application can manually adjust the coordinate transformation matrix to achieve the correct results, in practice, there is no performance benefit to doing so.

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

You use the function CGBitmapContextCreate to create a bitmap graphics context. This function takes the following parameters:

Tip: When you create a bitmap graphics context, you’ll get the best performance if you make sure the data and bytesPerRow are 16-byte aligned.

您可以使用函数CGBitmapContextCreate来创建位图图形上下文。 此功能需要以下参数:

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

Listing 2-5 shows how to create a bitmap graphics context. When you draw into the resulting bitmap graphics context, Quartz records your drawing as bitmap data in the specified block of memory. A detailed explanation for each numbered line of code follows the listing

清单2-5显示了如何创建位图图形上下文。 当您绘制到生成的位图图形上下文时,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);// 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
}

Here’s what the code does:

代码说明:

Listing 2-6 shows code that calls MyCreateBitmapContext
to create a bitmap graphics context, uses the bitmap graphics context to create a CGImage
object, then draws the resulting image to a window graphics context. Figure 2-3 shows the image drawn to the window. A detailed explanation for each numbered line of code follows the listing.

清单2-6显示了调用MyCreateBitmapContext创建位图图形上下文的代码,使用位图图形上下文来创建CGImage对象,然后将生成的图像绘制到窗口图形上下文。 图2-3显示了绘制到窗口的图像。 列出每个编号代码行的详细说明。

Listing 2-6 Drawing to a bitmap graphics context

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);

Here’s what the code does:

代码说明:

[图片上传失败...(image-137405-1534605915675)]

Supported Pixel Formats

Table 2-1 summarizes the pixel formats that are supported for bitmap graphics context, the associated color space (cs
), and the version of Mac OS X in which the format was first available. The pixel format is specified as bits per pixel (bpp) and bits per component (bpc). The table also includes the bitmap information constant associated with that pixel format. See CGImage Reference for details on what each of the bitmap information format constants represent.

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, kCGImageAlphaNone or 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, kCGImageAlphaNoneSkipLastor kCGBitmapFloatComponents Mac OS X
RGB 128 bpp, 32 bpc, kCGImageAlphaPremultipliedLast or 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, kCGImageAlphaNoneor kCGBitmapFloatComponents Mac OS X
Anti-Aliasing

Bitmap graphics contexts support anti-aliasing, which is the process of artificially correcting the jagged (or aliased) edges you sometimes see in bitmap images when text or shapes are drawn. These jagged edges occur when the resolution of the bitmap is significantly lower than the resolution of your eyes. To make objects appear smooth in the bitmap, Quartz uses different colors for the pixels that surround the outline of the shape. By blending the colors in this way, the shape appears smooth. You can see the effect of using anti-aliasing in Figure 2-4. You can turn anti-aliasing off for a particular bitmap graphics context by calling the function CGContextSetShouldAntialias. The anti-aliasing setting is part of the graphics state.

You can control whether to allow anti-aliasing for a particular graphics context by using the function CGContextSetAllowsAntialiasing. Pass true to this function to allow anti-aliasing; false not to allow it. This setting is not part of the graphics state. Quartz performs anti-aliasing when the context and the graphic state settings are set to true.

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

您可以通过使用函数CGContextSetAllowsAntialiasing来控制是否允许特定图形上下文的反锯齿。传递此功能以允许反锯齿;假不允许它。此设置不是图形状态的一部分。当上下文和图形状态设置设置为true时,Quartz会执行抗锯齿。

Figure 2-4 A comparison of aliased and anti-aliasing drawing

Obtaining a Graphics Context for Printing(打印图形上下文)

Cocoa applications in Mac OS X implement printing through custom NSView subclasses. A view is told to print by invoking its print: method. The view then creates a graphics context that targets a printer and calls its drawRect: method. Your application uses the same drawing code to draw to the printer that it uses to draw to the screen. It can also customize the drawRect: call to an image to the printer that is different from the one sent to the screen.

For a detailed discussion of printing in Cocoa, see Printing Programming Guide for Mac.

Mac OS X中的Cocoa应用程序通过NSView子类实现打印。 通过调用其print:方法,可以看到打印的视图。 然后该视图创建一个打印图形上下文,并调用其drawRect:方法。 您的应用程序可以使用相同的绘图代码绘制到用于绘制到屏幕的打印机。 它还可以自定义drawRect:将图片映射到不同的打印设备。

代码实例:

#import <UIKit/UIKit.h>

@interface CGView : UIView

@end

// 创建PDFContext
CGContextRef MyCrearePDFContent(const CGRect *inMediaBox, CFStringRef path){
    CGContextRef context = NULL;
    CFURLRef url;
    CGDataConsumerRef dataConsumer;

    url = CFURLCreateWithFileSystemPath(NULL, path, kCFURLPOSIXPathStyle, false);
    if(url != NULL){
        dataConsumer = CGDataConsumerCreateWithURL(url);
        if(dataConsumer != NULL){
            context = CGPDFContextCreate(dataConsumer, inMediaBox, NULL);
        }
        CGDataConsumerRelease(dataConsumer);
    }
    CFRelease(url);
    return context;
}

// 创建BitmapContext
CGContextRef MyCreateBitmapContent(int pixelsWide, int pixelsHigh){
    CGContextRef content = NULL;
    CGColorSpaceRef colorSpace;
    void  *bitmapData;
    NSUInteger bitmapBytesCount;
    NSUInteger bitmapBytesPerRow;

    bitmapBytesPerRow = pixelsWide * 4;
    bitmapBytesCount = bitmapBytesPerRow * pixelsHigh;

    colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
    bitmapData = calloc(bitmapBytesCount, sizeof(uint8_t));
    if(bitmapData == NULL){
        fprintf(stderr, "Memory not allocated");
        return NULL;
    }
    content = CGBitmapContextCreate(bitmapData,
                                    pixelsWide,
                                    pixelsHigh,
                                    8,
                                    bitmapBytesPerRow,
                                    colorSpace,
                                    kCGImageAlphaPremultipliedLast);
    if(content == NULL){
        free(bitmapData);
        fprintf(stderr, "Context not created");
        return NULL;
    }
    CGColorSpaceRelease(colorSpace);

    return content;
}

@implementation CGView

- (instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if(self){

    }
    return self;
}

- (void)drawRect:(CGRect)rect{
    CGContextRef content = UIGraphicsGetCurrentContext();
    CGContextRef myPDFContext;
    CGContextRef myBitmapContext;
    CGRect mediaBox = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);

    /*
    //1, View上下文绘制
    CGContextSetRGBFillColor(content, 1, 0, 0, 1);
    CGContextFillRect(content, CGRectMake(100, 0, 100, 100));
    CGContextSetRGBFillColor(content, 1, 1, 0, 1);
    CGContextFillRect(content, CGRectMake(0, 100, 100, 100));
     */

    //2, PDF上下文绘制
    /*
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *path = [paths[0] stringByAppendingString:@"/test.pdf"];
    myPDFContext = MyCrearePDFContent(&mediaBox, (__bridge CFStringRef)(path));

    CFStringRef myKeys[1];
    CFTypeRef myValues[1];
    myKeys[0] = kCGPDFContextMediaBox;
    myValues[0] = CFDataCreate(NULL,(const UInt8 *)&mediaBox, sizeof(CGRect));

    // 设置pdf page参数
    CFDictionaryRef pageDictionary = CFDictionaryCreate(NULL,
                                                        (const void **)myKeys,
                                                        (const void **)myValues, 1,
                                                        &kCFTypeDictionaryKeyCallBacks,
                                                        &kCFTypeDictionaryValueCallBacks);
    // PDF开始绘制
    CGPDFContextBeginPage(myPDFContext, pageDictionary);

    // PDF绘制
    CGContextSetRGBFillColor(myPDFContext, 1, 0, 0, 1);
    CGContextFillRect(myPDFContext, CGRectMake(100, 0, 100, 100));
    CGContextSetRGBFillColor(myPDFContext, 1, 1, 0, 1);
    CGContextFillRect(myPDFContext, CGRectMake(0, 100, 100, 100));

    // PDF结束绘制
    CGPDFContextEndPage(myPDFContext);
    // PDF释放
    CFRelease(pageDictionary);
    CFRelease(myValues[0]);
    CGContextRelease(myPDFContext);
     */


    // 3, Bitmap上下文绘制
    myBitmapContext = MyCreateBitmapContent(mediaBox.size.width, mediaBox.size.height);

    // bitmap绘制
    CGContextSetRGBFillColor(myBitmapContext, 1, 0, 0, 1);
    CGContextFillRect(myBitmapContext, CGRectMake(100, 0, 100, 100));
    CGContextSetRGBFillColor(myBitmapContext, 1, 1, 0, 1);
    CGContextFillRect(myBitmapContext, CGRectMake(0, 100, 100, 100));

    //bitmap渲染
    CGImageRef myImage = CGBitmapContextCreateImage(myBitmapContext);
    CGContextDrawImage(content, rect, myImage);

    //bitmap释放
    char *bitmapData = CGBitmapContextGetData(myBitmapContext);
    CGContextRelease(myBitmapContext);
    if(bitmapData){ free(bitmapData); }
    CGImageRelease(myImage);
}

@end

上一篇 下一篇

猜你喜欢

热点阅读