Пиксельное поведение 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)
рисует одну точку в (0,0), которая как-то понятна (это прямоугольник с шириной и высотой в конце концов).
DrawRectangle(pen,0,0,1,1)
, с другой стороны, рисует маленький прямоугольник размером 2 на 2 пикселя.
То же поведение показано для других комбинаций ширины и высоты, DrawRectangle
всегда расширяет один пиксель больше влево и снизу (что немного раздражает, например, при использовании свойства ClientRectangle
для рисования кадра вокруг элемента управления )
Мой первый вопрос, решенный (как они ведут себя...), все еще остается вторым: почему они ведут себя таким образом?
Ответы
Ответ 1
Эти методы работают правильно, вам просто нужно учитывать эффекты сглаживания и округления.
Сначала включите сглаживание, чтобы увидеть все (не только округленный результат):
graphics.SmoothingMode = SmoothingMode.AntiAlias;
Теперь FillRectangle (10,10,10,10) произведет размытый результат, а DrawRectangle (10,10,10,10) будет резким.
Размытый результат означает, что у вас пиксельные координаты вне сетки. Если вам нужно позвонить:
graphics.FillRectangle(9.5f, 9.5f, 10, 10);
чтобы выровнять верхний левый угол прямоугольника на сетке.
DrawRectangle острый, потому что он использует Pen шириной 1.0. Таким образом, линия начинается с центра пикселя и проходит 0,5 пиксела в обоих направлениях, таким образом, заполняя ровно 1 пиксель.
Обратите внимание, что ширина и высота вычисляются следующим образом:
width = (right - left) = 19.5 - 9.5 = 10
height = (bottom - top) = ...
Обратите внимание, что 19.5 - это правая/нижняя координата прямоугольника, также выровненного по сетке, и результат - целое число.
Вы можете использовать другую формулу:
width2 = (right - left + 1)
Но это применимо только к округленным координатам, так как наименьшая единица - 1 пиксель. При работе с GDI +, использующим сглаживание, имейте в виду, что точка имеет нулевой размер и лежит в центре пикселя (это не весь пиксель).
Ответ 2
Прямоугольник в обоих методах Graphics в вашем вопросе ограничен (x, y)
в верхнем левом углу и (x + width - 1, y + height - 1)
в правом нижнем углу. Это следствие указания ширины и высоты, а не нижней правой точки.
Когда вы вычисляете ширину и высоту из двух точек, вы не забудьте включить пиксель начала, добавив 1 к разнице.
Например, скажем, вы хотите заполнить прямоугольник от точки (5, 5) до точки (10, 20). Ширина прямоугольника равна 6, а не 5. Высота прямоугольника равна 16, а не 15.
Ответ 3
Различие в поведении связано с несколько противоположным интуитивным фактом, что эти два алгоритма делают совершенно разные вещи.
DrawRectangle рисует четыре строки в форме прямоугольника. FillRectangle создает скопление W * H заполненных пикселей. Из этого легко увидеть причину разницы в поведении. А именно, неправильность предположения о подобии. Рисование четырех строк сильно отличается от создания прямоугольного скопления пикселей.