Рисующее приложение в версии .NET, страница 16

Some overloads of the DrawImage method include a source-rectangle parameter as well as a destination-rectangle parameter. The source-rectangle parameter specifies the portion of the original image to draw. The destination rectangle parameter specifies the rectangle in which to draw that portion of the image. If the source rectangle specifies a region of the original image that is smaller than the original image, the image drawn in the destination rectangle will be a cropped version of the original image showing only that portion of the image specified by the source rectangle. If the size of the destination rectangle is different from the size of the source rectangle, the image is scaled to fit the destination rectangle.

You can rotate, skew, and reflect an image by specifying destination points for the upper-left, upper-right, and lower-left corners of the original image.

Работа с растровыми изображениями

¨  Создайте новый проект типа Windows Application с именем Image. В класс формы добавьте объявление:

private Image bitmap;  // Ссылка на объект класса Image. Он является родителем класса Bitmap

¨  Принесите в папку проекта какое-либо (не очень большое) растровое изображение, например, avisse.jpg.

¨  В конструктор формы вставьте код, который создает изображение, читая его из файла.

¨  Добавьте код, который заменяет цвет фона формы на белый, точнее на один из известных (системных) цветов.

public Form1()

{

InitializeComponent();

BackColor = Color.FromKnownColor (KnownColor.Window);

bitmap = new Bitmap ("../../avisse.jpg");

}

¨  Добавьте в класс переопределенную версию виртуального метода OnPaint, внутри которого выведем изображение в указанную позицию (25, 25).

protected override void OnPaint (PaintEventArgs e)

{

Graphics g = e.Graphics;

int dx = 25, dy = 25;

g.DrawImage (bitmap, dx, dy); // Draw the original image

}

Запустив приложение, вы увидите растровое изображение, в указанной позиции клиентской области окна. Любопытно, что размеры изображения, полученного таким (самым простым) способом не совпадают с теми, которые заявлены в свойствах объекта bitmap. Так, мой bitmap сообщает, что его размеры: 640 х 480. Но на форме он имеет размеры: 409 х 307. В чем же дело? Для исследования этой ситуации вставьте такой код.

int w = bitmap.Size.Width,    // Заявленный размер

h = bitmap.Size.Height;

float

fx = w * g.DpiX / bitmap.HorizontalResolution, // Вычисления, рожденные в муках творчества

fy = h * g.DpiY / bitmap.VerticalResolution;

int cx = (int)fx,    // Фактический размер

cy = (int)fy;

Text = "width = " + w.ToString() + ", height = " + h.ToString() +

";    cx = " + cx.ToString() +  ", cy = " + cy.ToString();

Теперь в заголовке окна мы увидим как заявленный, так и фактический размеры. Оказывается последний задан в дюймах! Интересно, когда же они от этого избавятся? В объекте класса Image есть свойство HorizontalResolution (сколько пиксел в дюйме), а в объекте класса Graphics — пара свойств: DpiX и DpiY (сколько неделимых атомов изображения в том же дюйме). Атомами я назвал dots (точки), потому что класс Graphics (и тип HDC) обслуживают поверхность как окна, так и листа бумаги в принтере. Здесь dots — обобщение понятий пикселы и dots принтера.

Фактические размеры изображения (те, что видим на экране) меньше заявленных. Коэффициенты сжатия (в моей системе) одинаковы и равны 0.64. Это число получается при делении 96 на 150. Действительно, в моей системе на один дюйм приходится 96 pixel (для Windows-окон это и есть атомы), а выбранное изображение говорит, что оно при воспроизведении хочет, чтобы в дюйме было 150 pixel. Заметьте, что при таком подходе, изображение при воспроизведении на любой поверхности сохраняет свой размер в дюймах. Это и есть его фактический размер. Замечу, что в каркасе MFC-приложений (он использует подсистему GDI) для сохранения размера надо прикладывать усилия.

Трансформация цвета