ios UIBezierPath 描边 1px 线并填充 1px 宽度矩形 - 不同的结果。
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11176560/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIBezierPath stroke 1px line and fill 1px width rectangle - different results.
提问by Michael
Here is a simple drawing
这是一张简单的图
- (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];
}
On non retina 3GS and simulator the first line is blurry and looks wider than 1 px, but the second line is crisp.
在非视网膜 3GS 和模拟器上,第一行是模糊的,看起来比 1 像素宽,但第二行是清晰的。
Unfortunately I have neither iPhone4 nor the new iPad to test, but on retina simulator both lines look the same.
不幸的是,我既没有 iPhone4 也没有新 iPad 来测试,但在视网膜模拟器上,两条线看起来都一样。
Question: Is rectangle instead of stroke the only way to obtain the same result for non retina and retina devices?
问题:对于非视网膜和视网膜设备,矩形而不是笔划是获得相同结果的唯一方法吗?
回答by David R?nnqvist
You are filling the inside of the rectangle but you are stroking the line from the center. Since the coordinates in both cases (the corners of the rectangle and the start and end coordinates in the line) are defined as whole number values (no fractions), the coordinates lie on exact point boundaries.
您正在填充矩形的内部,但您正在从中心抚摸这条线。由于两种情况下的坐标(矩形的角和直线中的起点和终点坐标)都定义为整数值(无分数),因此坐标位于精确的点边界上。
I said "coordinates" above when talking about the points of the line, to not confuse them with the points on the screen. I also said "point boundaries" instead of "pixel boundaries" for the same reason. iOS defines its coordinates and all the points in what is called "points" instead of pixels. A point is a resolution independent measurement. Both the retina and non-retina devices have the same number of points on the screen, it's just that they correspond to a different number of actual pixels.
在谈论线的点时,我在上面说了“坐标”,以免将它们与屏幕上的点混淆。出于同样的原因,我也说“点边界”而不是“像素边界”。iOS 在所谓的“点”中定义了它的坐标和所有点,而不是像素。点是与分辨率无关的测量。视网膜和非视网膜设备在屏幕上具有相同数量的点,只是它们对应于不同数量的实际像素。
Let's look at stroking a line that lie on the point boundaries (like in your question) compared to filling a rectangle where the corners lie on the the point boundaries:
让我们看看与填充角位于点边界上的矩形相比,抚摸位于点边界上的线(如您的问题中):
In the below illustrations I am stroking a line with black and filling a rectangle with orange on both a non-retina screen and a retina screen. I've also outlines the line and the rectangle with blue. In both cases you can see the size of a point for that resolution and compare it to the actual pixel grid.
在下面的插图中,我在非视网膜屏幕和视网膜屏幕上用黑色抚摸一条线并用橙色填充矩形。我还用蓝色勾勒出线条和矩形。在这两种情况下,您都可以看到该分辨率下点的大小,并将其与实际像素网格进行比较。
In the non-retina case, you can see that trying to stroke the line from the center with a 1 point line with (in this case corresponding to a 1 pixel line width) would fill half of the pixels on top and half on the pixels below. Since the pixels are only half filled, the opacity for those pixels are 50%. This results in the lighter color (on a white background). Since both the pixels on top and below are party filled, stroking the fills both the pixels on top and below. This makes the line look as if it's 2 pixels wide instead of one.
在非视网膜的情况下,您可以看到尝试从中心用 1 点线(在这种情况下对应于 1 像素线宽)将填充顶部的一半像素和像素的一半以下。由于像素仅填充了一半,因此这些像素的不透明度为 50%。这导致颜色较浅(在白色背景上)。由于顶部和下方的像素都是派对填充的,因此抚摸它会填充顶部和下方的像素。这使得线条看起来好像是 2 像素宽而不是 1 像素宽。
You can quickly compare that to the rectangle which is filled on the inside.
您可以快速将其与内部填充的矩形进行比较。
The same case on a retina screen looks different. In this case, the size of a point is the same but it consists of 4 pixels instead of 1. This time, when stroking the line, half a point above the line and half a point below the line will fully fill the row of pixels above and below because of the higher resolution screen. This means that the line looks as if it's 1 point wide and that the color looks fully opaque.
同样的情况在视网膜屏幕上看起来不同。在这种情况下,一个点的大小是相同的,但它由 4 个像素而不是 1 个像素组成。 这次,在划线时,线上方半点和线下方半点将完全填充该行像素上面和下面因为更高分辨率的屏幕。这意味着线条看起来好像是 1 磅宽,并且颜色看起来完全不透明。
We can also see that the filled rectangle looks the same.
我们还可以看到填充的矩形看起来是一样的。
To fix this, you would put the points for your line on half pixels. Stroking the line from the center on a low resolution device means that the line extends half a point upwards and half a point downwards. Since the center of the line now lies in the center of the point, this means that the stroked line fully lies within the pixels and the line looks sharp. Doing this won't have any effect on the retina line since moving down (or up) half a point, still means that you fully fill the pixels above and below.
要解决此问题,您可以将线条的点放在半像素上。在低分辨率设备上从中心抚摸线条意味着线条向上延伸半点,向下延伸半点。由于线的中心现在位于点的中心,这意味着描边线完全位于像素内并且线看起来很清晰。这样做不会对视网膜线产生任何影响,因为向下(或向上)移动半个点,仍然意味着您完全填充了上方和下方的像素。
In the illustration below (for retina) I have shown both the point grid and the pixel grid.
在下图中(对于视网膜),我同时显示了点网格和像素网格。
回答by ?zgür
The reason you get different results with stroke and fill is that their interpretations of arguments is different.
使用 stroke 和 fill 得到不同结果的原因是它们对参数的解释不同。
Stroke adds half the width of the line at each side of the coordinate. So, your point is 20.0 and width of line is 1px. The result will be a 1 pixel black line between (19.5-20.5), theorically. Since there isn't any nonintegral pixel on the device screen, it will be converted 2 pixels gray/blurry line between (19-21). to circumvent this, you need to sum each of your coordinates with 0.5 (as in CGPointMake(20.5, 10.5) ) so that width won't be divided between pixels any longer.
描边在坐标的每一侧添加线的宽度的一半。所以,你的点是 20.0,线宽是 1px。理论上,结果将是 (19.5-20.5) 之间的 1 像素黑线。由于设备屏幕上没有任何非整数像素,它将在 (19-21) 之间转换为 2 个像素的灰色/模糊线。为了避免这种情况,您需要将每个坐标与 0.5 相加(如 CGPointMake(20.5, 10.5) ),这样宽度就不会再在像素之间划分了。
However, the arguments in the fill are used to set the borders of the region to fill, CGRectMake(40.0, 10.0, 1.0, 390.0) implies a region between (40 - 41). As a result there is no fractional part falling on the pixels to look blurry.
但是,fill 中的参数用于设置要填充的区域的边界,CGRectMake(40.0, 10.0, 1.0, 390.0) 表示 (40 - 41) 之间的区域。结果是没有落在像素上的小数部分看起来模糊。