坐标、点和像素之间的微妙转换也可能降低绘制性能,导致线条和文字模糊。观察以下代码:
CGContextSetLineWidth(context, 3.); // 绘制从坐标{10, 100}到{200, 100}的3像素宽水平线条
CGContextMoveToPoint(context, 10., 100.);
GContextAddLineToPoint(context, 200., 100.);
CGContextStrokePath(context); // 绘制从坐标{10, 105.5} 到 {200, 105.5}的3像素宽水平线条
CGContextMoveToPoint(context, 10., 105.5);
CGContextAddLineToPoint(context, 200., 105.5); GContextStrokePath(context);
CGContextSetLineWidth(context, 3.); // 绘制从坐标{10, 100}到{200, 100}的3像素宽水平线条
CGContextMoveToPoint(context, 10., 100.);
GContextAddLineToPoint(context, 200., 100.);
CGContextStrokePath(context); // 绘制从坐标{10, 105.5} 到 {200, 105.5}的3像素宽水平线条
CGContextMoveToPoint(context, 10., 105.5);
CGContextAddLineToPoint(context, 200., 105.5); GContextStrokePath(context);
图8-3展示了这个程序在非Retina屏幕上的输出结果,这里放大了图片,可以更清晰地看出区别。
图8-3 比较分别从{10, 100}和{10, 105.5}出发的两条线
从{10, 100}到{200, 100}的线条要比从{10, 105.5}到{200, 105.5}的线条模糊很多,原因就在于iOS对坐标系的解读方式。
构造一个CGPath时,便是使用了所谓的**几何坐标系**。这与数学中使用的坐标系是一样的,以两条网格线的交点来表示零坐标点。你无法绘制出真正的几何点或几何线条,因为它们都是无限小和无限细的。iOS绘制中必须将这些几何对象转换成**像素坐标**。这是一个可以指定颜色的2D网格。像素是设备能控制的最小显示区域单位。来看图8-4。
图8-4 展示从{10, 100}到{200, 100}的几何线条
当调用了CGContextStrokePath,iOS会让线条沿路径居中。理想情况下,线条有3像素宽,从y = 98.5到y = 101.5,如图8-5所示。
图8-5 理想的3像素宽线条
但是,这个线条仍不能绘制。每个像素必须有唯一的颜色,线条顶部和底部的像素有两种颜色。一半是画笔颜色,一半是背景颜色。iOS通过取两个颜色的平均值解决了这个问题。同样的技术也用在了反锯齿上,如图8-6所示。
图8-6 反锯齿的3像素宽线条
在屏幕上,线条看起来会有些模糊。解决这个问题的方法就是将水平或垂直的线条移动到半个点的位置,这样当iOS将线条居中时,边缘刚好就是像素的边界。或者可以让线条更粗一些。
使用非整型宽度的线条,或者坐标系不是整型和半整型时,也可能遇到这个问题。让iOS绘制小数像素时都有可能导致模糊。
画笔的线条是中心对齐路径的,而填充颜色是基于路径的。如果填充从{10, 100}到{200, 103}的矩形,每个像素都会被正确填充,如图8-7所示。
图8-7 填充从{10, 100}到{200, 103}的矩形
Core
在Retina屏幕上并不需要位移半个点的位置,不过这不会有影响。若是要支持iPhone 3GS或iPad2,便需要对水平或垂直线条使用半个点的位移。
只能对水平或垂直线条使用这些方法。斜线与曲线应该进行反锯齿处理以便不会出现缺口,没有必要为它们进行偏移操作。