CGContextDrawImage使用和分析

首先看看网上关于Quartz 2D的一段话:

Quartz 2D 绘制模型定义了两种独立的坐标空间:用户空间(用于表现文档页)和设备空间(用于表现设备的本地分辨率)。用户坐标空间用浮点数表示坐标,与设备空间的像素分辨率没有关系。当我们需要一个点或者显示文档时, Quartz会将用户空间坐标系统映射到设备空间坐标系统。


下面说下自己的个人见解和分析:

由于坐标空间分为用户空间和设备空间两种,所以坐标系也分为两种。一种是CGContext绘图时的坐标系,以左下角为原点,y正轴向上,x正轴向右。另一种是设备空间的坐标系,以左上角为原点,y正轴向下,x正轴向右。

其中用户空间有一个绘图上下文,可以将其想象成一张画布。如果要在当前上下文中画图片,就要使用CGContextDrawImage方法,先看看直接使用该方法的情况:

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    UIImage *image = [UIImage imageNamed:@"addText.png"];
    CGRect rect1 = CGRectMake(100.0, 100.0, 100.0, 100.0);
    CGContextDrawImage(context, rect1, [image CGImage]);
//    drawImage(context, [image CGImage], rect1);
}


原来的图片为:

CGContextDrawImage使用和分析

运行结果如下:

CGContextDrawImage使用和分析

每个方格为100 * 100的规格。也就是image的位置是(100, 100, 100, 100),但是图片反过来了。如何在上下文中绘图,才能正确地映射到设备空间中?需要先做一些变换:

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    UIImage *image = [UIImage imageNamed:@"addText.png"];
    CGRect rect1 = CGRectMake(100.0, 100.0, 100.0, 100.0);
//    CGContextDrawImage(context, rect1, [image CGImage]);
    drawImage(context, [image CGImage], rect1);
}

void drawImage(CGContextRef context, CGImageRef image , CGRect rect){
    CGContextSaveGState(context);
    
    CGContextTranslateCTM(context, rect.origin.x, rect.origin.y);
    CGContextTranslateCTM(context, 0, rect.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextTranslateCTM(context, -rect.origin.x, -rect.origin.y);
    CGContextDrawImage(context, rect, image);
    
    CGContextRestoreGState(context);
}

运行结果为:

CGContextDrawImage使用和分析


之后来分析一下变化过程,先看看用户空间到设备空间的变换:

CGContextDrawImage使用和分析


再来看看以上代码变换的详细过程,假设要在设备空间的(a, b, c, d)位置画一个矩形。

1.原来的画布

CGContextDrawImage使用和分析

2.平移画布:CGContextTranslateCTM(context, rect.origin.x, rect.origin.y)

CGContextDrawImage使用和分析

3.平移画布:CGContextTranslateCTM(context,0, rect.size.height);

CGContextDrawImage使用和分析

4.翻转画布:CGContextScaleCTM(context,1.0, -1.0);

CGContextDrawImage使用和分析

5.平移画布:CGContextTranslateCTM(context, -rect.origin.x, -rect.origin.y);

在画布上参照画布的坐标系(蓝色的坐标系)的(a, b, c, d)位置绘图:CGContextDrawImage(context, rect, image);

CGContextDrawImage使用和分析

6.将用户空间中的图像映射到设备空间中

CGContextDrawImage使用和分析



其中画布就是一个绘图上下文,绘图操作的结果在这里展现。用户空间有一个属于自己的坐标系,画布有一个独立于用户空间的坐标系,设备空间也有自己的坐标系,其中画布的坐标系是可变的,例如平移,翻转等,另外两个是固定的。

在进行上下文变换时,画布的位置是变化的,注意画布的坐标系翻转后,往(-c, -d)方向作平移,是相对自己的坐标系做平移的(即蓝色的坐标系),而不是原来黑色标识的用户空间坐标系。

同样地,在画布上画图时就是根据画布自己的坐标系在上面画图。

在画布上画好图后,将图像从用户空间映射到设备空间时,参照的坐标系是用户空间坐标系和设备空间坐标系。


在创建PDF文档时,PDF上下文和输出的PDF文档的坐标系是一致的。


以上部分参考了:Quartz 2D编程指南(5) - 变换

代码参考了:讨论CGContextDrawImage


以上经过Demo的测试和分析,分析过程的图是自己做的,纯属个人的一些见解。



CGContextDrawImage使用和分析

上一篇:UVALive - 4851 Restaurant


下一篇:hdu 1024 Max Sum Plus Plus (求一个序列中选出的m个不相交子段和的最大值)