Programowanie
w środowiskach graficznych
Wykład 6 GDI+
• Kolekcje generyczne w C#:
◦ lista, gdzie każdy element ma swój indeks (może być traktowana jako dynamiczna tablica):
▪ List<Element>
◦ słownik – pewnej wartości klucza przyporządkowują pewną wartość (mogą być traktowane jako uogólnienie tablic):
▪ Dictionary<Klucz, Wartość>
• Tworząc kolekcję określamy rodzaj przechowywanego elementu (może to być typ obiektowy lub prosty).
List<Figura> figury = new List<Figura>();
Dictionary<string, Figura> słownik =
new Dictionary<string, Figura>();
36/43
• Najważniejsze metody klasy List<>:
◦ Add(Element o) i Insert(int indeks, Element o) – wstawianie elementu do listy na koniec lub pod żądanym indeksem
◦ bool Contains(Element o) i int IndexOf(Element o) – przeszukiwanie listy
◦ void Clear(), void RemoveAt(int index), bool Remove(Element o) – usuwające elementy z listy
• Przeglądanie listy:
for(int i = 0; i < al.Count; ++i) { lista[i].metoda();
}
• lub:
foreach(Element e in lista) { e.metoda();
}
37/43 Dostęp do listy – jak do
zwykłej tablicy.
• Najważniejsze metody klasy Dictionary<>:
◦ Add(Klucz key, Element value) – umieszcza wartość pod danym kluczem
◦ Clear(), Remove(Klucz key) – usuwanie zawartości
◦ bool ContainsKey(Klucz key) – sprawdza, czy jest jakaś wartość pod danym kluczem (szybka metoda)
◦ bool ContainsValue(Element value) – sprawdza, czy w mapie jest dana wartość (wolna metoda)
Dictionary<string, string> słownik =
new Dictionary<string, string>();
słownik.Add("kot", "cat");
słownik.Add("dom", "house");
if(słownik.ContainsKey("dom"))
Console.WriteLine(słownik["dom"]);
38/43 Dostęp do słownika – jak do
zwykłej tablicy.
GDI
Służy do reprezentacji obiektów graficznych i
transmitowania ich do urządzeń zewnętrznych jak np. monitory i drukarki
Rysowanie linii i krzywych, renderowanie fontów, zarządzanie paletami kolorów, itp.
Rysowanie okien, pasków menu, pasków narzędzi itp. jest realizowane przez nadbudowaną na GDI bibliotekę user32.dll
Może być używane do prostych gier, ale
współcześnie używa się jako bazy DirectX lub
OpenGL
• Rozszerzenie GDI o dodatkowe możliwości
• Bazuje na C++
• Wprowadzone w Windows XP, możliwe do zainstalowania na 98, Me, NT 4.0 SP6, 2000
• w .NET zawarte w przestrzeni nazw
System.Drawing , a fizycznie w Gdiplus.dll
GDI+
Nowe cechy GDI+
Anty-aliasing 2D
Koordynaty w liczbach float (dotychczas wyłącznie int )
Gradientowe pędzle (liniowe i zadawane ścieżkami)
Krzywe typu Cardinal (cardinal splines)
Niezależne obiekty ścieżek (GraphicsPath)
Przekształcenia kolorów: obiekty Matrix
Przekształcenia regionów
Przezroczystość (alpha blending) - ARGB
Wbudowane formaty plików graficznych:
BMP, GIF, JPEG, Exif, PNG, TIFF, ICON, WMF, EMF
Obiekt klasy Graphics
Podstawowa, najważniejsza klasa GDI+
Zwykle związany z oknem
Zawiera metody do rysowania
Udoskonalenia w stosunku do GDI:
pióra, pędzle, ścieżki, obrazki i fonty jako parametry metod
brak „aktualnej pozycji" wykorzystywanej do rysowania linii
oddzielne metody do rysowania konturu i wypełnionej figury PaintEventArgs e) e.Graphics.FillRectangle(Brushes.White, Pen mP = new Pen(Color.Red, 3);
}
private void AboutForm_Paint(object sender, {
0, 0, 200, 100);
e.Graphics.DrawLine(mP, 20, 10, 90, 90);
Użycie obiektu klasy Graphics
Pobieranie Graphics:
obsługa zdarzenia Paint: PaintEventArgs.Graphics
Control.CreateGraphics()
Graphics: FromHdc(), FromHwnd(), FromImage()
Wymuszanie odświeżenia:
Form.Invalidate()
Form.Update(), Form.Refresh()
Zapobieganie mruganiu:
DoubleBuffered = true;
// zwykle w konstruktorze lub OnLoad
Proste figury
Metody klasy Graphics :
proste figury:
DrawLine(), DrawArc(),
DrawRectangle(), DrawEllipse(), DrawPolygon()
FillEllipse(), FillRectangle()
krzywe typu Cardinal:
FillPie(), FillPolygon(),
DrawCurve(), DrawClosedCurve()
FillClosedCurve()
krzywe Beziera:
DrawBezier(), DrawBeziers()
Ścieżki
Tworzone z linii, figur i krzywych
Klasa GraphicsPath
dodawanie elementów do ścieżki:
AddLine(), AddArc(),
AddRectangle(), AddEllipse(),
AddPie(), AddBezier(), AddCurve(), AddClosedCurve(), AddPolygon(),
łączenie dwóch ścieżek: AddPath()
Graphics.DrawPath()
Graphics.FillPath()
AddString()
Przykład ścieżki
public void DrawPathEllipse(PaintEventArgs e) {
// Create graphics path object and add ellipse.
GraphicsPath graphPath = new GraphicsPath();
graphPath.AddEllipse(0, 0, 200, 100);
// Create pen.
Pen blackPen = new Pen(Color.Black, 3);
// Draw graphics path to screen.
e.Graphics.DrawPath(blackPen, graphPath);
}
Pióra
Klasa Pen
Właściwości:
szerokość – SetWidth()
wyrównanie
końce linii – LineCap
łączenie linii
– SetAlignment(), wyliczenie PenAlignment SetStartCap(), SetEndCap(), wyliczenie
– SetLineJoin(), wyliczenie LineJoin
kreskowanie linii – SetDashPattern()
tekstura
TextureBrush tBrush = new TextureBrush(image);
e.Graphics.DrawLine(texturedPen, 0, 0, 50, 50);
Image image = new Bitmap("texture.jpg");
Pen texturedPen = new Pen(tBrush, 30);
Pędzle
Abstrakcyjna klasa Brush i dziedziczące z niej:
SolidBrush, HatchBrush, TextureBrush, LinearGradientBrush, PathGradientBrush
Color.FromArgb(255, 255, 0, 0));
HatchStyle.Horizontal,
e.Graphics.FillEllipse(hBrush,100,0,100,60);
TextureBrush tBrush = new TextureBrush(image);
0.0f, 0.0f, 75.0f/480.0f, 0.0f, 0.0f);
SolidBrush solidBrush = new SolidBrush(
e.Graphics.FillEllipse(solidBrush,0,0,100,60);
HatchBrush hBrush = new HatchBrush(
Color.Green, Color.Blue);
Image image = new Bitmap("texture.jpg");
tBrush.Transform = new Matrix(75.0f/640.0f, e.Graphics.FillEllipse(tBrush,200,0,100,60);
Obrazy
Klasa Image - abstrakcyjna
Klasa Bitmap dziedzicząca z Image
wyspecjalizowane metody do odczytu, wyświetlania modyfikacji obrazków rastrowych
PixelFormat.Format32bppPArgb
i
(klasa CachedBitmap w wersji niezarządzanej)
format zgodny z aktualnymi ustawieniami ekranu
trzymanie obrazków w tym formacie może znacznie przyspieszyć ich rysowanie
Graphics.DrawImage()
Obcinanie
Skalowanie, wyliczenie InterpolationMode
Obracanie, odwracanie, przekrzywianie
Automatyczne skalowanie, gdy nie został podany rozmiar
GDI+ skaluje obrazki w taki sposób, by ich fizyczny rozmiar na urządzeniu używanym do rysowania był jak najbliższy
fizycznemu rozmiarowi na urządzeniu, na którym zostały stworzone
Formaty grafiki: Image Encoders i Decoders :
Wyliczenie zainstalowanych encoders i decoders :
ImageCodecInfo: GetImageEncoders(), GetImageDecoders()
Konwersja obrazków z JPG do PNG
try }
{
MessageBox.Show("conversion failed: exc=" + }
Image image = new Bitmap("bird.jpg");
image.Save("bird.png", ImageFormat.Png);
catch (Exception ex) { ex.ToString());
Przezroczystość – kanał alfa
displayColor = sourceColor * alpha / 255 + backgroundColor * (255 – alpha) / 255
Color ARGB – 4 wartości: (alpha, red, green, blue)
SolidBrush semi(Color.FromArgb(128,0,0,255));
Tryby składania (Compositing modes)
SolidBrush opaque(Color.FromArgb(255,0,0,255));
CompositingMode.SourceCopy CompositingMode.SourceOver
Przezroczystość w obrazach
Bez przezroczystości Z pewną przezroczystością
Z przezroczystością definiowaną
wypełnieniem gradientowym
Teksty
Graphics.DrawString()
w określonym
w określonym
Formatowanie
wyrównanie –
miejscu
prostokącie
StringFormat.SetAlignment(), StringFormat.SetLineAlignment()
tabulatory – StringFormat.SetTabStops()
pionowy tekst – StringFormat.SetFormatFlags()
Antyaliasing
Graphics.SetTextRenderingHint()
Fonty
Tworzenie
FontStyle.Regular);
Wielkości
Font.GetSize()
FontFamily.GetEmHeight()
FontFamily.GetCellAscent()
FontFamily.GetCellDescent()
FontFamily.GetLineSpacing()
Font font = new Font("Arial", 16,
Kontenery graficzne
Stan obiektów klasy Graphics
powiązanie z kontekstem urządzenia
ustawienia dot. jakości
przekształcenia
region obcinania
Użycie kontenerów graficznych
GraphicsContainer graphicsContainer;
gr.RotateTransform(30.0f);
gr.EndContainer(graphicsContainer);
Pen pen = new Pen(Color.Red);
gr.TranslateTransform(100.0f, 80.0f);
graphicsContainer = gr.BeginContainer();
gr.DrawRectangle(pen,-60,-30,120,60);
gr.DrawRectangle(pen,-60,-30,120,60);
Przekształcenia
Klasa Matrix
Proste metody klasy Graphics:
ScaleTransform()
RotateTransform()
TranslateTransform()
Kolejność przekształceń jest znacząca
Matrix m=new Matrix();
//move the origin to 200,200 m.Translate(200,200);
//rotate 90 deg clockwise
m.Rotate(90,MatrixOrder.Prepend);
Przekształcenia
Klasa Matrix
L1-L4 – przekształcenia linearne D1, D2 – translacja
Klasy które można modyfikować za pomocą ich własności Transform z użyciem Matrix:
• Graphics
• Pen
• GraphicsPath
Np.:
Graphics g = e.Graphics;
g.Transform(mm1);
Użycie Matrix do tranformacji
Regiony
Klasa Region
Elementy:
linie
wielokąty
krzywe
Sprawdzenie zawierania punktu
Region.IsVisible(point,
Obcinanie
Graphics.SetClip(region)
graphics)
Zmiana kolorów za pomocą ColorMatrix
Struktura ColorMatrix
Klasa ImageAttributes
ImageAttributes imageAttributes = new float[][] colorMatrixElements = {
0.0f, 1.0f, new
new
float[]
float[]
{0.0f, {0.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f}, 0.0f}, ColorMatrix colorMatrix = new
imageAttributes.SetColorMatrix(colorMatrix, ColorAdjustType.Bitmap);
new Rectangle(15, 10, im.Width, im.Height), Image im = new Bitmap(@"d:\img.jpg");
ImageAttributes();
new float[] {1.0f, 0.0f, 0.0f, 0.0f, 0.0f}, new float[] {0.5f, 0.0f, 1.0f, 0.0f, 0.0f}, new float[] {0.0f, 0.0f, 0.0f, 0.0f, 1.0f}};
ColorMatrix(colorMatrixElements);
ColorMatrixFlag.Default, e.Graphics.DrawImage(im,
0, 0, im.Width, im.Height,
Przykładowe transformacje
Użycie GDI+ z kodu niezarządzanego (poza VS)
Dołączyć nagłówek gdiplus.h
//#define
#include
WIN32_LEAN_AND_MEAN
<gdiplus.h>
Dołączyć przestrzeń nazw Gdiplus
Dołączyć do projektu bibliotekę gdiplus.lib
w ustawieniach projektu albo użyć dyrektywy #pragma
#pragma comment(lib, "gdiplus.lib")
// albo dodac w ustawieniach projektu using namespace Gdiplus;
// !!! NIE DEFINIOWAC WIN32_LEAN_AND_MEAN
#include <windows.h>
Użycie GDI+ z kodu niezarządzanego
Zainicjować GDI+
c.d.
ULONG_PTR gdiplusToken;
gdiplusStartupInput,
Używać obiektów i metod GDI+
HDC hdc = BeginPaint(hWnd, &ps);
// ...
Zwolnić zasoby używane przez GDI+
GdiplusShutdown(gdiplusToken);
PAINTSTRUCT ps;
Graphics myGraphics(hdc);
EndPaint(hWnd, &ps);
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, NULL);