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.