FillRectangle 和 DrawRectangle 的像素行为
几乎每次我使用 Graphics.DrawRectangle
或 Graphics.FillRectangle
(int
版本)时,我似乎都会错过右侧和底部边框上的像素我想要绘制的矩形。
哪些像素的确切定义是什么
Graphics.FillRectangle(brush,x,y,width,height)
填充
Graphics.DrawRectangle(pen,x,y,width,height) // pen is one pixel width, i.e. width=0f
?是否有合理的解释? (这样我终于可以记住这种行为了:) ...)
编辑:
使用奥列格·朱克的奇妙尝试GDI+ 应用程序中,我发现了 FillRectangle
和 DrawRectangle
之间的一个奇怪的区别:
FillRectangle(brush,0,0,1,1)< /code> 在 (0,0) 处绘制一个点,这在某种程度上是可以理解的(毕竟它是一个宽度和高度均为一的矩形)。
另一方面,DrawRectangle(pen,0,0,1,1)
绘制一个 2 x 2 像素的小矩形。
其他宽度/高度组合也会显示相同的行为,DrawRectangle
总是向左侧和底部多延伸一个像素(这有点烦人,例如在使用 ClientRectangle
属性时)在控件周围画一个框架)
我的第一个问题解决了(如何它们的行为...)仍然存在第二个问题:为什么它们这样做?
nearly every time I use Graphics.DrawRectangle
or Graphics.FillRectangle
(the int
versions) I seem to miss the pixels on the right and bottom border of the rectangle I want to draw.
What is the exact definition of which pixels get filled by
Graphics.FillRectangle(brush,x,y,width,height)
and
Graphics.DrawRectangle(pen,x,y,width,height) // pen is one pixel width, i.e. width=0f
and is there a logical explanation for it? (so I can finally remember the behaviour :) ...)
EDIT:
Using Oleg Zhuk's marvelous Try GDI+ application, I was able to find a curious difference between FillRectangle
and DrawRectangle
:
FillRectangle(brush,0,0,1,1)
draws a single dot at (0,0) which is somehow understandable (it's a rectangle with width and height one after all).
DrawRectangle(pen,0,0,1,1)
on the other hand draws a small 2 by 2 pixel rectangle.
The same behaviour is shown for other width/height combinations, DrawRectangle
always extends one pixel more to the left and the bottom (which is a little annoying e.g. when using the ClientRectangle
property to draw a frame around a control)
My first question solved (how to they behave...) there still remains the second one: Why do they behave this way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这些方法可以正常工作,您只需考虑抗锯齿和舍入的效果即可。
首先,打开抗锯齿功能以查看所有内容(不仅仅是舍入结果):
现在 FillRectangle(10,10,10,10) 将产生模糊结果,而 DrawRectangle(10,10,10,10) 将产生清晰结果。
模糊的结果意味着您有像素坐标离网。如果需要调用:
将矩形的左上角对齐在网格上。
DrawRectangle 很尖锐,因为它使用宽度为 1.0 的 Pen。因此,该线从像素中心开始,向两个方向延伸 0.5 个像素,从而恰好填充 1 个像素。
请注意,宽度和高度是这样计算的:
请注意,19.5 是也在网格上对齐的矩形的右/下坐标,结果是一个整数。
您可以使用不同的公式:
但这仅适用于舍入坐标,因为最小单位是 1 像素。使用抗锯齿的 GDI+ 时,请注意该点的大小为零并且位于像素中心(它不是整个像素)。
These methods work correctly, you just have to take into account effects of anti-aliasing and rounding.
First, turn on anti-aliasing to see everything (not only rounded result):
Now FillRectangle(10,10,10,10) will produce blurry result and DrawRectangle(10,10,10,10) will be sharp.
The blurry result means that you have pixel coordinates off-grid. If you need to call:
to align top-left corner of the rectangle on grid.
The DrawRectangle is sharp because it uses Pen of width 1.0. So the line starts on the pixel center and goes 0.5 pixels in both directions, thus filling exactly 1 pixel.
Note that width and height are computed this way:
Notice that 19.5 is a right/bottom coordinate of the rectangle also aligned on the grid and the result is a whole number.
You can use different formula:
But this applies on rounded coordinates only, since the smallest unit is 1 pixel. When working with GDI+ that uses anti-aliasing, be aware of the fact that the point has zero size and lies in the center of pixel (it is not the whole pixel).
您问题中的两个 Graphics 方法中的矩形均以左上角的
(x, y)
和 (x + width - 1, y + height - 1) 为边界> 在右下角。这是指定宽度和高度而不是右下点的结果。当您从两点计算宽度和高度时,请记住通过将差值加 1 来包含原始像素。
例如,假设您想要从点 (5, 5) 到点 (10, 20) 填充一个矩形。矩形的宽度是 6,而不是 5。矩形的高度是 16,而不是 15。
The rectangle in both of the Graphics methods in your question is bounded by
(x, y)
in the upper left and(x + width - 1, y + height - 1)
in the lower right. This is a consequence of specifying width and height, rather than the lower right point.When you're calculating the width and height from two points, you have remember to include the origin pixel by adding 1 to the difference.
For example, say you want to fill a Rectangle from point (5, 5) to point (10, 20). The width of the rectangle is 6, not 5. The height of the rectangle is 16, not 15.
行为上的差异是由于有些违反直觉的事实,即这两种算法做了完全不同的事情。
DrawRectangle 在盒子形状中绘制四条线。 FillRectangle 生成一个 W*H 的填充像素块。由此很容易看出行为差异的原因。即相似性假设的错误。绘制四条线与生成盒状像素簇有很大不同。
The difference in behavior is due to the somewhat counter intuitive fact that these two algorithms do completely different things.
DrawRectangle draws four lines in the shape of a box. FillRectangle produces a W*H clump of filled in pixels. From this it's easy to see the reason for the difference in behavior. Namely the wrongness of the assumption of similarity. Drawing four lines is quite different than producing a boxlike clump of pixels.