Пиксельное поведение FillRectangle и DrawRectangle - PullRequest
12 голосов
/ 30 июня 2010

почти каждый раз, когда я использую 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 для рисования рамки вокруг элемента управления)

Мой первый вопрос решен ( как ведет себя ...) до сих пор остается второй: Почему они так себя ведут?

Ответы [ 3 ]

7 голосов
/ 12 февраля 2011

Эти методы работают правильно, вы просто должны учитывать эффекты сглаживания и округления .

Сначала включите сглаживание, чтобы увидеть все (не только округленный результат):

graphics.SmoothingMode = SmoothingMode.AntiAlias;

Теперь FillRectangle (10,10,10,10) даст размытый результат, а DrawRectangle (10,10,10,10) будет резким.

Результат размытия означает, что у вас есть координаты пикселей вне сетки . Если вам нужно позвонить:

graphics.FillRectangle(9.5f, 9.5f, 10, 10);

для выравнивания верхнего левого угла прямоугольника на сетке.

DrawRectangle острый, потому что он использует перо шириной 1,0. Таким образом, линия начинается в центре пикселя и идет на 0,5 пикселя в обоих направлениях, заполняя ровно 1 пиксель.

Обратите внимание, что ширина и высота вычисляются следующим образом:

width = (right - left) = 19.5 - 9.5 = 10
height = (bottom - top) = ...

Обратите внимание, что 19.5 - это правильная / нижняя координата прямоугольника, также выровненного по сетке, и результатом является целое число.

Вы можете использовать другую формулу:

width2 = (right - left + 1)

Но это относится только к округленным координатам , так как наименьшая единица равна 1 пикселю. При работе с GDI +, использующим сглаживание, следует учитывать тот факт, что точка имеет нулевой размер и находится в центре пикселя (это не весь пиксель).

1 голос
/ 30 июня 2010

Прямоугольник в обоих методах Graphics в вашем вопросе ограничен (x, y) в верхнем левом углу и (x + width - 1, y + height - 1) в нижнем правом. Это является следствием указания ширины и высоты, а не нижней правой точки.

Когда вы рассчитываете ширину и высоту из двух точек, не забудьте включить исходный пиксель, добавив к разнице 1.

Например, скажем, вы хотите заполнить прямоугольник из точки (5, 5) в точку (10, 20). Ширина прямоугольника 6, а не 5. Высота прямоугольника 16, а не 15.

0 голосов
/ 07 февраля 2012

Различие в поведении связано с несколько противоречивым интуитивным фактом, что эти два алгоритма делают совершенно разные вещи.

DrawRectangle рисует четыре линии в форме блокаFillRectangle создает W * H скопление залитых пикселей.Отсюда легко понять причину различий в поведении.А именно ошибочность предположения о сходстве.Рисование четырех линий совершенно отличается от создания коробчатого скопления пикселей.

...