UIBezierPath描边1px线并填充1px宽度矩形 - 不同的结果。

时间:2012-06-24 10:05:45

标签: ios drawing uibezierpath

这是一张简单的图纸

    

- (void)drawRect:(CGRect)rect
{
    //vertical line with 1 px stroking
    UIBezierPath *vertLine = [[UIBezierPath alloc] init];
    [vertLine moveToPoint:CGPointMake(20.0, 10.0)];
    [vertLine addLineToPoint:CGPointMake(20.0, 400.0)];
    vertLine.lineWidth = 1.0;
    [[UIColor blackColor] setStroke];
    [vertLine stroke];

    //vertical rectangle 1px width 
    UIBezierPath *vertRect= [UIBezierPath bezierPathWithRect:CGRectMake(40.0, 10.0, 1.0, 390.0)];
    [[UIColor blackColor] setFill];
    [vertRect fill];

}

在非视网膜3GS和模拟器上,第一行模糊,看起来比1 px宽,但第二行很清晰。

不幸的是我没有测试iPhone4和新iPad,但在视网膜模拟器上两条线看起来都一样。

问题:矩形而非中风是获得非视网膜和视网膜设备相同结果的唯一方法吗?

2 个答案:

答案 0 :(得分:53)

您正在填充矩形的内部,但是您正在从中心划线。由于两种情况下的坐标(矩形的角和线中的起点和终点坐标)都被定义为整数值(无分数),因此坐标位于精确的点边界上。

在谈论线的点时,我说上面的“坐标”,不要将它们与屏幕上的点混淆。出于同样的原因,我也说“点边界”而不是“像素边界”。 iOS定义了它的坐标和所谓的“点”而不是像素的所有点。点是独立于分辨率的测量。视网膜和非视网膜设备在屏幕上具有相同数量的点,只是它们对应于不同数量的实际像素。

让我们看一下在点边界上划线(比如在你的问题中)与填充角点位于点边界的矩形相比:

在下面的插图中,我正在用黑色抚摸一条线,并在非视网膜屏幕和视网膜屏幕上填充橙色矩形。我还用蓝色勾勒出线条和矩形。在这两种情况下,您都可以看到该分辨率的点大小,并将其与实际像素网格进行比较。

在非视网膜情况下,您可以看到尝试从中心用1点线描边线(在这种情况下对应于1像素线宽)将填充顶部的一半像素和一半在下面的像素上。由于像素仅填充了一半,因此这些像素的不透明度为50%。这导致较浅的颜色(在白色背景上)。由于顶部和底部的像素都是派对填充的,因此在顶部和底部都可以触摸填充像素。这使得线条看起来好像是2像素宽而不是1像素。

您可以快速将其与内部填充的矩形进行比较。

non retina

视网膜屏幕上的相同情况看起来不同。在这种情况下,点的大小是相同的,但它由4个像素而不是1组成。这次,当抚摸线时,线上半个点和线下半个点将完全填充像素行由于分辨率较高的屏幕,因此在上方和下方。这意味着该线看起来好像是1点宽,并且颜色看起来完全不透明。

我们还可以看到填充的矩形看起来一样。

retina


要解决此问题,您可以将线条的点数设置为半像素。在低分辨率设备上从中心划线,意味着线向上延伸半个点,向下延伸半个点。由于线的中心现在位于点的中心,这意味着描边线完全位于像素内并且线看起来很清晰。这样做对视网膜线没有任何影响,因为向下(或向上)移动半个点,仍然意味着你完全填满了上下像素。

在下图中(对于视网膜)我已经显示了点网格和像素网格。

half pixel non-retina half pixel retina

答案 1 :(得分:2)

你在笔画和填充中获得不同结果的原因是他们对参数的解释是不同的。

笔划在坐标的每一边添加线宽的一半。所以,你的观点是20.0,线宽是1px。结果将是理论上(19.5-20.5)之间的1像素黑线。由于设备屏幕上没有任何非整数像素,因此它将在(19-21)之间转换为2像素灰度/模糊线。为了避免这种情况,你需要将每个坐标与0.5相加(如CGPointMake(20.5,10.5)),这样就不会再在像素之间划分宽度了。

但是,填充中的参数用于设置要填充的区域的边框,CGRectMake(40.0,10.0,1.0,390.0)表示介于(40 - 41)之间的区域。因此,没有像素部分落在像素上看起来模糊。