Vektorová grafika v C # .NET WPF - Úvod
V dnešnej lekcii si popíšeme čo je to vektorová grafika a ako sa líši oproti grafike rastrové. Ďalej si ukážeme, ako sa k tejto problematike stavia .NET framework a WPF. Potom si skúsime cez XAML nakresliť pár jednoduchých objektov.
Vektorová vs. rastrová grafika
Veľmi laicky môžeme povedať, že vektorový obrázok si môžeme zväčšiť ako chceme a nikdy sa nám nerozmaže alebo nerozpixeluje. To je veľmi lákavé, pretože takýto obrázok je plne responzívne a stále 100% ostrý, navyše zaberá veľmi málo pamäte a naše aplikácie potom vyzerá na všetkých zariadeniach rovnako pekne. Niet divu, že napr. SVG ikony sú dnes na webe veľmi populárne. A aj my budeme vektorové ikony vo svojich WPF aplikáciách preferovať.
Vektorový obrázok
Obrázok v sebe obsahuje matematický zápis súradníc bodov (vrcholov) a ich spojníc (hrán), ktorý vytvára požadovaný obrazec (napr. Trojuholník, kruh, štvorec ...). Kombinovaním a prelínaním týchto obrazcov sa potom vytvárajú obrazce zložitejšie. Ďalej sa vo vektorových obrázkoch špecifikujú informácie ako hrúbka čiary, farba výplne atď. Z toho vyplýva, že s akýmkoľvek zväčšením či zmenšením obrazce sa mení len pomer vzdialeností medzi vrcholmi.
Rasterizácia
A ako sa krivky vykreslí? To, čo potom vidíme na obrazovke, sa musí samozrejme znova "rasterizovat", čiže vykresliť na 2D ploche nášho monitora:

Ako sami vidíte, vykreslenie vektorového obrázku na obrazovku vytvára pri malom počte pixelov "schody" čiže aliasing. WPF za nás však uplatňuje pokročilejšie algoritmy, tzv. Anti-aliasing, aby boli jednotlivé krivky obrázka vyhladené.
Rastrový obrázok
Naopak bitová mapa, napr vo formáte JPEG (keď ho zjednodušíme a opomenieme stratový algoritmus kompresie), sa skladá iba z pixelov a ich farby. Ak takýto obrázok zväčšíme, základný algoritmus zdvojí počet pixelov, ale tie vychádzajú iba z pôvodnej informácie, a teda bude obraz škaredo rozkostičkovaný a v lepšom prípade rozmazaný. O pretože sa hustota pixelov obrazoviek stále zvyšuje, môžeme si byť istí, že používatelia naši aplikáciu zväčšovať budú.
Ukážme si, ako to vyzerá, keď sa zväčší rastrový obrázok:

A tu príklad zväčšenie vektorového obrázku:

Kedy použiť vektorovú a kedy rastrovú grafiku?
Takže teraz máme predstavu, aký je rozdiel medzi vektorovou a rastrovou grafikou. Nemôžeme povedať, že jedna je lepšia ako druhá. Zjednodušene môžeme povedať, že na ikony by sme mali používať vektorové obrázky a na fotografie dostatočne kvalitné obrázky rastrové. Zhrňme si teraz do pár bodov základné rozdiely:
Vektorová grafika
- Jednoduchšie grafika ako ikony
- Akýkoľvek grafický prvok, ktorý sa bude dynamicky zmenšovať či zväčšovať
- Možnosť aj prípadné animácie
- Možno aj dynamicky meniť farbu jednotlivých prvkov v obrazci
- Menšia veľkosť súboru s obrázkom
- Náročnejší na výpočtový výkon
Rastrový obrázok
- Tam, kde sa jedná o reálnu fotografiu, či zložité obrazce
- Tam, kde bude obraz vždy v natívnom rozlíšení, a nebude sa s ním zoomovať
- Kde je potrebné detailného, fotorealistického obrázku sa tiene a nasvietením, ale nie je výhodné zaťažovať GPU / CPU veľmi zložitú scénou
- Vyššie nároky na veľkosť súboru
- Výpočtová nenáročnosť
Ako vo WPF pracovať s vektorovou grafikou
Ako možno už tušíte, štandardne bez ďalších rozširujúcich balíčkov WPF vo Visual Studiu nepodporuje externé súbory vektorovej grafiky. To sú napr .:
.svg- Scalable Vector Graphics.eps, .ps - PostScript.ai- Adobe Illustrator Artwork.cdr- Corel Draw.pdf- Portable Document Format
Najmä SVG súbor je v dnešnej dobe etalón, ktorý sa uchytil vo webovej
grafike, a vie okrem iného aj animácie. Bohužiaľ je podporovaný až v
novšej verzii Creator 's Update (teda verzie OS Windows 10 1709 z konca roka
2017) pod UWP (Universal Windows Platform), kde pre neho vznikla nová trieda
SvgImageSource.
Ako teda na vektorovú grafiku vo WPF?
XAML
Riešením je XAML, ktorý v základe využíva nástroje na
kreslenie ako <Rectangle>, <Line>,
<Ellipse> a ďalšie, ktoré sa vykresľujú ako vektorové
objekty. S kreslením tvarov sme sa v našom kurze už stretli. Teraz si
ukážeme aj ďalšie tvary a ako do XAML skonvertovať SVG
súbory.
Vytvorenie aplikácie
Začneme pracovať na aplikáciu, ktorá bude vo výsledku vyzerať takto:

Vytvorte si nový projekt a prepnite sa do XAML časti:

Tu si vytvoríme <Grid>, a ten rozdelíme na 9
rovnomerných "chlívečků" s týmito parametrami:
<Grid.ColumnDefinitions> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="1*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> </Grid.RowDefinitions>
To nám rozdelí pracovnú plochu na 3 * 3 chlívečky, ktoré si budú
vďaka parametra * udržiavať pomer s veľkosťou okna. Okno by
malo vyzerať v návrhári takto (objekty pridáme samozrejme neskôr):

Vloženie jednotlivých prvkov
Teraz si ukážme, ako vykreslíme základné tvary.
Rectangle
Ako prvý vložíme obdĺžnik <Rectangle>, vyplnený
zelenou farbou a so žltým okrajom:
<Rectangle Stroke="Bisque" StrokeThickness= "5" Fill="Aquamarine" Margin="10" Grid.Row="0" Grid.Column="0" />
výsledok:

Stroke je farba okraja, StrokeThickness je sila
čiary okraja v pixeloch. Fill je farba výplne,
Margin je odskok od okrajov, Grid.Row a
Grid.Column určuje, v ktorom z našich "chlívečků" bude obrazec
umiestnený.
Rectangle - Štvorec
Druhý obdĺžnik je špeciálny v tom, že je to vlastne štvorec. Stráži
si tu svoju aktuálnu šírku, a tú nastavuje aj pre výšku. To dosiahneme
priradením Binding:
<Rectangle StrokeThickness= "5" Margin="10" Grid.Row="1" Grid.Column="0" Width="{Binding ActualHeight, Mode=OneWay, RelativeSource={RelativeSource Mode=Self}}" Stroke="Black">
výsledok:

Binding môže nahrádzať konštantnú hodnotu v ktoromkoľvek parametra
premennú alebo referencií na inú premenou, v našom prípade na aktuálnu
výšku obdĺžnika:
Width="{Binding ActualHeight, Mode=OneWay, RelativeSource={RelativeSource Mode=Self}}"
Ellipse
Potom tu máme <Ellipse>, kde je nastavenie rovnaké ako v
prípade štvorca, ale okorenil som to efekty prechodov, ako pre výplň
Fill, tak pre okraje Stroke:
<Ellipse StrokeThickness= "5" Margin="10" Grid.Row="0" Grid.Column="1"> <Ellipse.Stroke> <LinearGradientBrush> <GradientStop Color="#FFFFFF03" Offset="0"/> <GradientStop Color="#FF000CFF" Offset="1"/> </LinearGradientBrush> </Ellipse.Stroke> <Ellipse.Fill> <RadialGradientBrush> <GradientStop Color="#FF0633FF" Offset="0"/> <GradientStop Color="Red" Offset="1"/> <GradientStop Color="#FFFFF500" Offset="0.7"/> <GradientStop Color="#FF3AFF00" Offset="0.403"/> <GradientStop Color="#FFFF16B5" Offset="0.837"/> </RadialGradientBrush> </Ellipse.Fill> </Ellipse>
výsledok:

Pre čiaru Stroke využívame lineárny prechod, teda postupný
prechod, v tomto prípade medzi dvoma farbami, od spodnej modrej, po hornú
žltú. Color nastavuje logicky farbu, a Offset
východiskovú pozíciu na farebnej škále - čiže aké miesto bude pre danú
farbu vyhradené. Postupuje sa po 0.1 krokoch alebo jemnejších,
maximálna hodnota 1. Výplň Fill sme pre zmenu
nastavili na prechod niekoľkých farieb, tentokrát na kruhový prechod.
Ellipse - Kruh
Teraz opäť pomocou Bindingu nakreslíme miesto elipsy kruh.
Postup je totožný ako u nášho štvorca:
<Ellipse x:Name="ellipse" Stroke="Black" Fill="AliceBlue" Margin="10" Grid.Row="1" Grid.Column="1" Width="{Binding ActualHeight, Mode=OneWay, RelativeSource={RelativeSource Mode=Self}}"/>
Pokračovať budeme nabudúce.
