Univerzita Karlova v Praze Matematicko-fyzikální fakulta
BAKALÁŘSKÁ PRÁCE
Jan Ambrož
Podpora formátu SVG pro .NET Framework Středisko informatické sítě a laboratoří Vedoucí bakalářské práce: RNDr. Vojtěch Jákl Studijní program: Informatika, Programování. 2007
Poděkování Zvláštní poděkování patří RNDr. Jiřímu Křesťanovi, CSc., řediteli firmy GD Software, za námět práce, za důvěru při konkrétní dospecifikaci zadání, za možnost poskytnout zdrojový kód implementace vývojářské komunitě a rovněž za poskytnutí vývojových prostředků k realizaci této práce. Dále bych rád poděkoval RNDr. Vojtěchu Jáklovi, vedoucímu práce, za trpělivost a odborné vedení této práce.
Prohlašuji, že jsem svou bakalářskou práci napsal samostatně a výhradně s použitím citovaných pramenů. Souhlasím se zapůjčováním práce.
V Praze dne
_____________________
2
Obsah Část I. ............................................................................................................................ 5 1.
Úvod ...................................................................................................................... 5
2.
Zadání a hlavní cíl práce ........................................................................................ 7
3.
Formáty podporující reprezentaci vektorových grafických dat ............................ 7
4.
Formát SVG ........................................................................................................... 9 4.1.
Základní informace o formátu SVG ............................................................... 9
4.2.
Implementace standardu SVG v rámci práce .............................................. 11
Část II. ......................................................................................................................... 15 1.
Základní popis řešení .......................................................................................... 15
2.
Projekt corelib ..................................................................................................... 16
3.
4.
5.
2.1.
Popis implementace knihovny .................................................................... 16
2.2.
Popis nejdůležitějších tříd ........................................................................... 20
2.3.
Příklady využití knihovny ............................................................................. 20
Projekt drawing................................................................................................... 23 3.1.
Popis implementace knihovny .................................................................... 23
3.2.
Popis nejdůležitějších tříd ........................................................................... 25
3.3.
Příklady využití knihovny ............................................................................. 25
Projekt drawingwpf ............................................................................................ 27 4.1.
Popis implementace knihovny .................................................................... 27
4.2.
Popis nejdůležitějších tříd ........................................................................... 28
4.3.
Příklady využití knihovny ............................................................................. 28
Ostatní součásti implementace .......................................................................... 30 5.1.
Stručný popis projektu testapp ................................................................... 30
5.2.
Stručný popis projektu wpfviewer .............................................................. 30
Část III. ........................................................................................................................ 31 1.
Zhodnocení naplnění zadání ............................................................................... 31
2.
Další cíle práce .................................................................................................... 31
3.
Závěr ................................................................................................................... 32
3
Název práce: Podpora formátu SVG pro .NET Framework Autor: Jan Ambrož Katedra (ústav): Středisko informatické sítě a laboratoří Vedoucí bakalářské práce: RNDr. Vojtěch Jákl e-mail vedoucího:
[email protected] Abstrakt: Obsahem této bakalářské práce je realizace knihovny tříd, využívající prostředků Microsoft .NET Framework, která umožňuje libovolné grafické aplikaci vytváření, zpracování, načítání a ukládání vektorových grafických dat ve formátu SVG, resp. podmnožiny formátu SVG pro statickou vektorovou grafiku. Dále je obsahem i realizace nadstavby na tuto knihovnu tříd, která, rovněž v podobě knihovny tříd, umožňuje vytvoření grafických aplikací pro prezentaci grafických dat ve formátu SVG s využitím prostředků rozhraní GDI+ a také prostředků formátu XAML. Je připravováno komerční využití prostředků vytvořených v rámci této práce. Klíčová slova: vektorová grafika, SVG, .NET Framework, WPF, C#
Title: SVG Support For .NET Framework Author: Jan Ambrož Department: Network and Labs Management Center Supervisor: RNDr. Vojtěch Jákl Supervisor’s e-mail address:
[email protected] Abstract: This thesis describes a Microsoft .NET class library which gives any graphics application the ability to create, process, load and save vector graphics data in the SVG format, specifically the subset of the SVG format for static vector graphics. Another part of this thesis describes an extension (also in the form of Microsoft .NET class library) which allows creation of graphics applications for presentation of graphics data represented in the SVG format using GDI+ and XAML. The commercial use of the resources developed is being prepared. Keywords: vector graphics, SVG, .NET Framework, WPF, C#
4
Část I. Úvod do problému
1. Úvod Prezentace
dynamicky
generovaných
vektorových
grafických
dat
v internetových prohlížečích na intranetu je poněkud přehlížené téma. Donedávna byla realizace tohoto úkolu velmi složitá a bez použití proprietárních komponent třetích stran téměř vyloučena. Dnes je již tento problém částečně vyřešen s příchodem platformy Microsoft .NET Framework verze 3.0 a možností použít tzv. XBAP (XAML Browser Application). Formát XAML dokáže, kromě popisu uživatelského rozhraní vlastní prezentační grafické aplikace, rovněž reprezentovat vektorová grafická data, a tak, společně s programovacím jazykem, jakým je např. C#, umožňuje nad platformou Microsoft .NET Framework verze 3.0 vytvořit grafické aplikace běžící v rámci webového prohlížeče, které umožní dynamicky generovaná vektorová grafická data interaktivně prezentovat. Bohužel však toto řešení není všeobecně akceptované, je omezené na platformu Microsoft Windows a ani na této platformě není stoprocentně podporováno všemi dostupnými webovými prohlížeči. A tak se nabízí otázka, zda nepojmout problém z poněkud jiného úhlu pohledu a spíše než na vlastní prezentaci vektorových grafických dat se raději nezaměřit na způsob, jak nejprve daná grafická data reprezentovat ve formátu, který je rozšířený, podporovaný a umožní tedy prezentaci takových dat i na platformách, které koncept XBAP nepodporují. Tento způsob řešení problému také značně rozšíří možnost využití oněch dynamicky generovaných vektorových grafických dat, neboť umožní jejich zpracování libovolnou grafickou aplikací, která daný formát umí zpracovat. Problémem prezentace a persistence dynamicky generovaných vektorových grafických dat a jeho možnými řešeními se již delší dobu zabývá firma GD Software. Aplikace, které tato firma vyvíjí, potřebují ukládat, zpracovávat a prezentovat statická grafická data převážně vektorové povahy, a to včetně aplikací běžících na intranetu, na které se firma v posledních několika letech začala výrazněji orientovat. 5
Dříve používané řešení, kterým byl vlastními prostředky vyvinutý proprietární binární formát, se ukázalo, právě s postupnou orientací na vývoj intranetových aplikací, jako velmi nevhodné. Proprietární binární formát není přenosný a prezentace grafických dat reprezentovaných takovým formátem tak znamenala nutnost vytváření vlastních konverzních a prezentačních aplikací, které dokázaly statická grafická data reprezentovaná tímto formátem převádět na rastrovou grafiku a následně je prezentovat uživateli. Vytváření podobných aplikací pro intranetové použití pak narazilo na velmi omezené možnosti realizace. Problém byl částečně vyřešen konverzí vektorových grafických dat na rastrová data již na straně serveru. Rastrová data (nejčastěji ve formátu GIF) pak byla prezentována ve webovém prohlížeči. Toto řešení je však velmi omezené a interaktivnost je vykoupena zvýšenou zátěží webového serveru a přenosové sítě. Téměř vyloučené je pak nasazení podobného řešení v rámci aplikace dostupné na Internetu. Potřeby firmy GD Software nakonec vedly k formulaci zadání (v dalším textu odkazováno jako původní zadání), které bylo následně na MFF upraveno a je předmětem této bakalářské práce. Zadání obsahovalo realizaci řešení problémů popsaných výše, konkrétně tedy implementaci prostředků k persistenci, zpracování a prezentaci statických vektorových grafických dat reprezentovaných formátem, který nebyl zadavatelem přesněji specifikován, který je otevřený, rozšířený, nezávislý na platformě a má perspektivu dalšího vývoje. Výsledná implementace musela umožňovat použití vytvořených prostředků v libovolné aplikaci, včetně aplikace běžící v rámci podnikového intranetu či na Internetu. Požadována byla rovněž realizace řešení s využitím prostředků platformy Microsoft .NET Framework verze 2.0. Z důvodů zpětné kompatibility a nutnosti generovat také výsledky ve formátu GIF bylo rovněž nutné jako jeden ze způsobů prezentace grafických dat požadovat realizaci vykreslování pomocí prostředků rozhraní GDI+. Na základě tohoto zadání pak vzniklo i zadání pro tuto práci, které je již konkrétní a volí jeden z dostupných formátů, který vyhovuje podmínkám původního zadání.
6
2. Zadání a hlavní cíl práce Zadání práce vzniklo na základě původního zadání firmy GD Software, popsaného v úvodu. Pro realizaci byl zvolen formát SVG, který vyhovuje podmínkám původního zadání. Předmětem zadání bylo vytvoření knihovny tříd, využívající prostředků Microsoft .NET Framework, která umožní libovolné grafické aplikaci vytváření, zpracování, načítání a ukládání vektorových grafických dat ve formátu SVG, resp. podmnožiny formátu SVG pro statickou vektorovou grafiku. Dalším cílem bylo vytvoření nadstavby na tuto knihovnu tříd, která, rovněž v podobě knihoven tříd, umožní tvorbu grafických aplikací pro prezentaci grafických dat ve formátu SVG s využitím prostředků rozhraní GDI+ (zpětná kompatibilita a možnost generování výstupů v podporovaných formátech rastrové grafiky) a také prostředků formátu XAML (možnost moderní a efektivní prezentace grafických dat v podporovaných webových prohlížečích na intranetu či Internetu). Součástí zadání je rovněž snaha o co největší míru respektování specifikace standardu formátu SVG (omezená na podporu persistence, zpracování a prezentace statických vektorových grafických dat) ve verzi 1.1. Hlavním cílům práce byla podřízena velikost implementované podmnožiny specifikace standardu formátu SVG.
3. Formáty podporující reprezentaci vektorových grafických dat Při přípravě finálního zadání práce bylo, mimo jiné, třeba rozhodnout, jaký formát pro uchovávání vektorových grafických dat použít. Ačkoli by se mohlo zdát, že je k dispozici více různých možností, opak byl pravdou. Přestože původní zadání nijak nediktovalo použití formátu SVG (a pro jeho naplnění je zvolený formát persistence vektorových grafických dat nepodstatný), podmínky, které byly na takový formát kladeny, splnil pouze formát SVG. Existuje více různých formátů, které vektorovou grafiku podporují, např. WMF (Windows Metafile), EMF (Enhanced Metafile), VML (Vector Markup Language) nebo nový XAML (Extensible Application Markup Language). První dva jmenované formáty jsou proprietární formáty firmy Microsoft, určené výhradně pro použití 7
s Windows GDI, bez otevřené specifikace a dnes již dále nevyvíjené. Formát VML pochází opět z dílny společnosti Microsoft (byl vyvinut společně s dalšími firmami, např. firmou Macromedia), tentokrát však již s otevřenou specifikací a návrhem na schválení jako standard W3C z roku 1998. Formát VML však jako standard W3C neprošel (kvůli odporu konkurenční skupiny, která prosazovala u W3C svůj vlastní formát, PGML). Nicméně VML i PGML (Precision Graphics Markup Language) jsou svou stavbou (oba založené na použití XML jako reprezentace dat) dost podobné a právě na jejich bázi (a spoluprácí všech zúčastněných stran) vznikl formát SVG. Poslední jmenovaný formát, XAML, byl vyvíjen firmou Microsoft v minulých letech a představen pak v loňském roce, kdy byla uvolněna finální verze Microsoft .NET Framework 3.0, jejíž je XAML součástí. Co se týče podmínek kladených na příslušný formát dle původního zadání, formáty WMF a EMF jsou doménou Microsoft Windows, jinde nejsou podporovány, nemají otevřenou specifikaci a nejsou již dlouhou dobu dále vyvíjeny. Proto nevyhovují původnímu zadání. Formát VML je rovněž doménou Microsoft Windows, otevřenou specifikaci sice má, je rovněž rozšířený (prakticky na každém počítači s Microsoft Windows lze tento formát zobrazit), avšak je podporován pouze produkty firmy Microsoft, jiné aplikace jej využívají velmi zřídka (formát VML je využíván např. firmou Google v produktu Google Maps pro zobrazení vektorové grafiky v prohlížeči Internet Explorer, který VML od verze 5.5 nativně podporuje). Z výše uvedených důvodů tedy formát VML rovněž podmínkám původního zadání nevyhovuje. Formát XAML je moderní formát s otevřenou specifikací, který bude s velkou pravděpodobností dále vyvíjen. Formát byl od počátku určen, mimo jiné, k záznamu vektorových grafických dat a grafiky obecně (XAML v praxi zaznamenává popis objektové struktury, je jím tudíž možné reprezentovat úplně cokoli, pro co existuje ve světě Microsoft .NET objektová reprezentace) a svou úlohu plní velmi dobře. Hlavním důvodem, proč formát XAML nebyl zvolen jako formát pro uchovávání vektorových grafických dat v rámci řešení práce, je jeho omezení na platformu Microsoft Windows. Jeho podpora na jiných rozšířených systémech (vyjma Apple Mac) je v nejbližší době téměř vyloučena (důvodem pro tento fakt je právě to, že XAML zaznamenává objektovou strukturu Microsoft .NET, nikoliv např. jen 8
vektorová grafická data; podpora tedy prakticky znamená nutnost podpory celé Microsoft .NET Framework 3.0). Dalším důvodem je také to, že v době finalizace zadání byl formát XAML stále pouze beta verzí. Přesto je třeba zmínit, že formát XAML (a zvláště pak renderovací moduly WPF (Windows Presentation Foundation), které slouží pro renderování grafiky v prostředí Microsoft .NET Framework 3.0) je z hlediska filozofie návrhu (nikoli syntaxe) velmi podobný SVG a v prostředí, kde je nová verze Microsoft .NET Framework 3.0 k dispozici, je rozhodně nejkvalitnější a nejefektivnější cestou k implementaci zobrazování vektorových grafických dat, ať už původně byla v jakémkoli formátu. Pro řešení práce byl, po zvážení vlastností všech výše uvedených formátů, zvolen formát SVG. Tento formát má otevřenou specifikaci, jeho vývoj pokračuje, je podporován mnoha společnostmi, je rozšířený a nezávislý na platformě. Nakonec je to také formát určený přesně k tomuto účelu, tedy záznamu vektorových grafických dat. Zvolená specifikace formátu SVG verze 1.1 je již delší dobu uznána jako standard W3C, tudíž je podporována na většině platforem, včetně mobilních zařízení.
4. Formát SVG 4.1.
Základní informace o formátu SVG
SVG je zkratkou pro Scalable Vector Graphics (lze přeložit např. jako škálovatelná
vektorová
grafika).
SVG
je
platformou
(formátem)
pro
dvojdimenzionální grafiku, se zaměřením na popis vektorové grafiky. Autorem formátu SVG je internetové sdružení W3C (World Wide Web Consortium). Verze 1.0 formátu SVG pochází již z roku 2001, verze 1.1, která byla přijata jako tzv. standard webu (Web standard – W3C Recommendation), byla dokončena v roce 2003 a v současné době probíhá další vývoj v rámci verze 1.2, která je zatím nedokončena (Working Draft; poslední z dubna roku 2005). Formát SVG je postaven na dvou základních pilířích. Jedním je skutečnost, že syntaxe SVG plně využívá textového XML (Extensible Markup Language; standard W3C) formátu, druhým je pak programátorské rozhraní pro grafické aplikace, které je rovněž součástí definice formátu SVG. Klíčovými prvky formátu SVG jsou 9
geometrické útvary, texty a vložená rastrová grafika, v neposlední řadě pak také mnoho různých způsobů, jak kreslit čáry a výplně. Formát SVG podporuje skriptování pomocí jazyka, jakým je např. ECMAScript, a také obsahuje širokou podporu pro animace. Formát SVG má své uplatnění v mnoha oblastech. Za zmínku stojí např. grafika na webu, popisy animací či uživatelských rozhraní aplikací. Formát SVG byl rovněž navržen tak, aby mohl být použit jako prostředek pro výměnu popisu grafických (hlavně vektorových) dat mezi aplikacemi různých výrobců, lze jej též dobře využít pro popis grafiky připravené k tisku a umožňuje také použití v mobilních aplikacích (omezené možnosti formátu podporované např. mobilními telefony apod.). Formát SVG je otevřený a nezávislý standard, za jehož použití v komerčních i nekomerčních aplikacích není třeba platit. Na vývoji formátu SVG se podílí mnoho různých firem, zejména společnosti Adobe, Agfa, Apple, Canon, Corel, Ericsson, HP, IBM, Kodak, Macromedia, Microsoft, Nokia, Sharp nebo Sun Microsystems a další. V dnešní době je již značně rozšířen a jeho podpora celosvětově roste. Formát SVG jako takový je založen na mnoha jiných úspěšných standardech. Využívá XML pro zápis dat (grafika je zapsána v textové podobě, a proto je velmi snadné ji vytvořit nebo modifikovat), JPEG (Joint Photographic Experts Group) a PNG (Portable Network Graphics; standard W3C) jako podporované formáty pro rastrovou grafiku, zahrnuje podporu DOM (Document Object Model; standard W3C) pro skriptování, SMIL (Synchronized Multimedia; standard W3C) pro popis animací a CSS (Cascading Style Sheets; standard W3C) pro definici a úpravu vzhledu. Formát SVG je velmi rozsáhlý a bohatý na funkce. Je nezávislý na platformě a nepředurčuje žádným způsobem podobu implementace (i když v některých případech je součástí definice i rada, jak příslušný problém implementovat nebo popis toho, jak se obvykle daná součást formátu implementuje). To bohužel v praxi znamená, že některé jeho součásti je velmi obtížné, někdy i úplně nemožné implementovat pomocí standardních metod pro vykreslování grafiky na té které platformě. Rovněž sám rozsah formátu odrazuje od jeho úplné implementace. Proto často dochází k implementaci jen omezeného množství funkcionality podle toho, kde a jak bude příslušná implementace využívána. Také implementace realizovaná v rámci této práce není úplná a vychází ze zadání a konkrétní potřeby využití v 10
grafických aplikacích zmíněných v úvodu. Popis implementace z hlediska podpory standardu SVG je obsahem následující kapitoly.
4.2.
Implementace standardu SVG v rámci práce
Implementace formátu SVG realizovaná v rámci této práce není kompletní. Formát SVG je, v souladu se zadáním, použit jako prostředek pro persistenci, zpracování a zobrazování základních vektorových a rastrových dat. Přesto však výsledné řešení umožňuje do budoucna podporu SVG standardu co nejvíce zdokonalit a rozšířit. Pokud není uvedeno jinak, je v dalším textu pod pojmem „specifikace SVG“ myšlena specifikace formátu SVG ve verzi 1.1 [1]. Důležitý je fakt, že je se specifikací SVG při implementaci důsledně počítáno. Výsledná knihovna tříd generuje validní SVG dokumenty (Conforming SVG StandAlone File dle SVG specifikace), což zahrnuje jednak validní textovou XML reprezentaci dat a následně také validní popis grafických dat ve formátu SVG. SVG elementy, které jsou implementací podporovány, umožňují použít pouze atributy, které jim implementovaná část SVG specifikace přisuzuje, potomky SVG elementů v XML stromu mohou být pouze SVG elementy, které implementovaná část SVG specifikace povoluje apod. Stejná omezení platí pro načítání a zpracování již existujících SVG dokumentů. Nelze tedy načíst či zpracovat dokument, který obsahuje nepodporované SVG elementy nebo nepodporované atributy na některém z SVG elementů. Implementace je však rozšiřitelná; vždy jde přidat podporu pro další SVG element dle specifikace a přesně nadefinovat požadavky na jeho chování. Knihovna tříd určená k vytváření, modifikací, načítání a ukládání SVG dokumentů podporuje podmnožinu specifikace SVG pro statickou vektorovou grafiku (feature string http://www.w3.org/TR/SVG11/feature#SVG-static) kromě modulu
pro
podporu
uživatelské
definice
fontů
(feature
string
http://www.w3.org/TR/SVG11/feature#Font). Pro každý datový typ, atribut, třídu atributů, element či třídu elementů jsou definovány třídy nebo struktury, které příslušný prvek specifikace SVG představují. Knihovny tříd určené k zobrazování obsahu SVG dokumentů jsou, co se týče podpory specifikace SVG, mnohem více omezené. Důraz byl kladen na přesnou implementaci souřadných systémů, jednotek a transformací souřadných systémů 11
dle specifikace SVG. Obě zobrazovací knihovny tedy správně a formálně přesně dle specifikace SVG implementují veškeré prvky specifikace SVG týkající se souřadných systémů. Dále jsou v obou knihovnách formálně přesně implementovány významy jednotlivých SVG elementů (a jejich atributů) definujících základní geometrické obrazce (rect, ellipse, circle, line, polyline a polygon). Poněkud omezena je podpora SVG elementu path (definice grafické cesty), ne však v případě WPF knihovny, kde XAML reprezentace podporuje vše potřebné pro plnou implementaci. Obě knihovny však prozatím nepodporují autorem předem vypočtenou a určenou délku grafické cesty (atribut pathLength). Implementace SVG elementu image je téměř úplná, s výjimkou podpory data: URI scheme (podpora inline vkládaní binárních rastrových dat). Podpora SVG elementu text je omezena na sadu základních zobrazovacích SVG elementů a atributů (Basic Text Module dle specifikace SVG), přičemž je možno polohu vlastního textu určit jen jedním párem souřadnic (ostatní páry jsou ignorovány) a chybí podpora atributu rotate (zbytečné, pokud není možné přesně určit pozici jednotlivých znaků v textu; rotace celého textu je možná pomocí atributu transform). Plná podpora vykreslování textů (další atributy a SVG elementy mimo Basic Text Module) překračuje zadání této práce. Implementace dále plně podporuje následující SVG elementy, které se přímo nevykreslují, ale slouží jako kontejnery pro ostatní (přípustné) SVG elementy, tj. svg, g a symbol. SVG element symbol je renderován jako g element s jistým následným zpracováním některých atributů přesně dle specifikace SVG. SVG element use byl rovněž implementován. Tento SVG element umožňuje vytvářet instance libovolného jiného SVG elementu (s jistými výjimkami dle specifikace SVG), a tak podporovat vícenásobné využití definovaných (mnohdy složitých) grafických útvarů. Implementace use elementu je plně slučitelná se specifikací SVG, s výjimkou odkazů na SVG elementy mimo aktuální SVG dokument. Implementace obou knihoven tříd podporují ořezávání grafického výstupu (clipping paths dle specifikace SVG) pomocí atributů overflow a clip, rovněž také definice složitějších útvarů určených pro ořezávání grafického výstupu pomocí SVG
12
elementu clipPath a reference těchto definic pomocí atributu clip-path. Implementace dále plně podporuje atribut clip-rule. Implementace knihovny tříd pro grafický výstup nad GDI+ plně podporuje použití masek průhlednosti (opacity/alpha masking dle specifikace SVG), jejich definice pomocí SVG elementu mask a reference těchto definic pomocí atributu mask. Implementace knihovny tříd pro grafický výstup pomocí WPF masky průhlednosti nepodporuje (nemožné implementovat pomocí managed prostředků). Obě knihovny tříd plně implementují atributy pro specifikace obrysů a výplní (color, fill-opacity, fill-rule, fill, stroke-opacity, stroke-width, stroke-linecap, stroke-linejoin, stroke-miterlimit, stroke-dasharray, stroke-dashoffset a stroke), atribut pro specifikaci průhlednosti celého grafického útvaru (opacity) a také atributy pro specifikaci viditelnosti grafického útvaru nebo skupiny grafických útvarů (display, visibility). Podpora paint serverů (paint servers dle specifikace SVG) byla omezena na podporu SVG elementu linearGradient u obou knihoven tříd. Knihovna tříd používající WPF rovněž podporuje SVG element radialGradient (pro funkce tohoto SVG elementu není v GDI+ přímo zabudována podpora). Oba SVG elementy, pokud jsou v dané knihovně tříd implementovány, jsou plně podporovány, s výjimkou dědění vlastností odkazem na jiný SVG element stejného typu. Podpora funkcí spojených s SVG elementem pattern nebyla (vzhledem k tomu, co vše specifikace SVG od implementace tohoto SVG elementu vyžaduje) dokončena. Následující SVG elementy nejsou knihovnami tříd pro zobrazování obsahu SVG dokumentů implementovány: switch, style, colorProfile a foreignObject. SVG element switch nebyl implementován, protože bylo rozhodnuto nepracovat v rámci práce s podmíněným zpracováním SVG elementů při renderingu (opět, do budoucna není problém implementaci o tuto funkci rozšířit). SVG element style nebyl implementován, protože funkce kaskádových stylů (CSS) nebyly do implementace zahrnuty (viz. dále). SVG element colorProfile nebyl implementován, protože to není specifikací SVG přímo vyžadováno a konečně SVG element foreignObject rovněž nebyl implementován, protože je určen k rozšiřování funkcí formátu SVG (sám o sobě žádnou funkci v rámci vykreslování nemá).
13
Funkce definované SVG elementem filter dle specifikace SVG nebyly implementovány. Podpora funkcí grafických filtrů překračuje zadání této práce a pod WPF je, stejně jako použití masek průhlednosti, neimplementovatelná pomocí managed prostředků. Rovněž nebyly implementovány funkce definované SVG elementem marker. Není implementována podpora pro funkce kaskádových stylů (CSS). Tato problematika je velmi rozsáhlá, nejsou pro ni k dispozici knihovny tříd pro Microsoft .NET Framework, a překračuje rámec zadání této práce. V praxi to znamená, že hodnoty prezentačních atributů lze zadávat pouze přímo jako XML atributy na SVG elementech (s čímž ale specifikace SVG počítá; pro vyhovující implementace není podpora CSS povinná). Není tedy brán zřetel na SVG element style, ani na atribut style, který je definován na většině elementů. Přesto však byl plně implementován princip dědění hodnot prezentačních atributů dle specifikace SVG. Prezentační atributy podporují CSS hodnotu inherit, která automaticky použije hodnotu atributu na předkovi, případně výchozí hodnotu prezentačního atributu danou specifikací SVG nebo CSS. Není implementován SVG DOM dle specifikace SVG. Tato funkčnost nebyla pro řešení práce zapotřebí, neboť je v rámci formátu SVG využívána výhradně pro podporu animací a dynamické prezentace obsahu, což není součástí zadání práce.
14
Část II. Popis řešení
1. Základní popis řešení V souladu se zadáním byla praktická část práce realizována nad Microsoft .NET Framework verze 2.0 (jisté části implementace využívají součástí Microsoft .NET Framework verze 3.0, jmenovitě Windows Presentation Foundation), jako programovací jazyk byl zvolen jazyk C#. Celá implementace byla dekomponována na tři knihovny tříd (reprezentované samostatnými projekty v prostředí Microsoft Visual Studio). Každá knihovna tříd se tedy kompiluje do vlastního DLL souboru (class-library assembly). Součástí implementace jsou rovněž dvě aplikace určené pro testování knihoven tříd pro generování grafického výstupu, jedna určená pro testování funkčnosti grafického výstupu nad GDI+, druhá, využívající platformy Microsoft .NET Framework verze 3.0, určená pro testování funkčnosti grafického výstupu pod WPF. Tyto aplikace však nejsou předmětem řešení (ani součástí zadání) této práce. Knihovna tříd GDSoftware.Svg.dll (projekt corelib) využívá pouze zdrojů platformy
Microsoft
.NET
Framework
verze
2.0.
Knihovna
tříd
GDSoftware.Drawing.dll (projekt drawing) rovněž využívá zdrojů platformy Microsoft .NET Framework verze 2.0, také ale přímo závisí na funkcích poskytovaných
předchozí
jmenovanou
knihovnou
tříd.
Knihovna
tříd
GDSoftware.Drawing.Wpf.dll (projekt drawingwpf) je závislá na přítomnosti platformy Microsoft .NET Framework verze 3.0 a rovněž závisí na funkcích poskytovaných oběma předchozími knihovnami tříd. První testovací aplikace (projekt testapp) testuje vlastnosti a funkce knihovny tříd GDSoftware.Drawing.dll a je tudíž závislá pouze na platformě Microsoft .NET Framework verze 2.0. Druhá testovací aplikace (projekt wpfviewer) testuje vlastnosti a funkce knihovny tříd GDSoftware.Drawing.Wpf.dll a je určena k běhu nad platformou Microsoft .NET Framework verze 3.0.
15
Všechny projekty byly vytvořeny ve vývojovém prostředí Microsoft Visual Studio 2005 a jsou určeny pro kompilaci a využití na platformě Microsoft Windows. Pro úspěšné přeložení projektů závislých na platformě Microsoft .NET Framework verze 2.0 není zapotřebí žádné rozšíření Microsoft Visual Studia. Pro úspěšné přeložení projektů závislých na platformě Microsoft .NET Framework verze 3.0 je nutné (kromě instalace runtime této verze platformy) doinstalovat produkt Visual Studio 2005 extensions for .NET Framework 3.0 (WCF & WPF), November 2006 CTP. Implementace nechává prostor pro budoucí funkční i výkonnostní optimalizace. Důraz na jistou optimalizaci výkonu byl kladen jen na určitých konkrétních místech, kde by méně optimální implementace neumožňovala kvalitně realizovat zadání práce. Součástí implementace je zdrojový kód všech projektů (viz. Dodatek A.) a kódová dokumentace knihoven tříd generovaná programem Sandcastle s využitím dokumentačních funkcí jazyka C# (viz. Dodatek B.). Kódová dokumentace je vytvořena v anglickém jazyce. Samotný zdrojový kód je opatřen průběžnými komentáři v českém jazyce. Implementace žádné části řešení práce není závislá na použití zdrojového kódu nebo knihovny tříd vytvořených nebo dodaných třetí stranou.
2. Projekt corelib 2.1.
Popis implementace knihovny
Tato knihovna tříd implementuje třídy, struktury a rozhraní určené k vytváření, zpracování, načítání a ukládání SVG dokumentů. Umožňuje tedy přístup k vektorovým grafickým datům přímo na úrovni formátu SVG a jeho stavebních prvků. Nezávislost knihovny tříd na čemkoli vyjma platformních knihoven umožňuje její využití v jakékoli grafické aplikaci, která potřebuje vytvářet nebo zpracovávat (nikoli však zobrazovat či prezentovat) grafická data ve formátu SVG, včetně např. využití v dávkových generátorech grafických dat běžících např. jako Windows Service nebo Web Service.
16
Základem implementace této knihovny tříd je využití již existujících tříd Microsoft .NET Framework určených pro manipulaci s formátem XML. Třídy reprezentující SVG dokument či libovolný SVG element jsou přímo či nepřímo odvozeny z odpovídajících tříd Microsoft .NET Framework. Toto řešení umožnilo zaměřit se na implementaci formátu SVG bez nutnosti implementovat podporu pro formát XML, který je základem formátu SVG. Při vytváření či úpravách SVG dokumentů tak může programátor využívající tuto knihovnu tříd použít známých postupů pro manipulaci s XML elementy či atributy, s tím rozdílem, že každý element formátu SVG je implementován svou vlastní třídou (tudíž je nutné vytvořit instanci této třídy a přidat ji do seznamu potomků jiného elementu). Tímto je zajištěna část kontroly správnosti dat SVG dokumentu dle specifikace SVG. Při načítání již existujícího dokumentu dochází k nahrazení automaticky vytvořených XML elementů (reprezentovaných třídou Microsoft .NET Framework XmlElement) příslušnými třídami objektové hierarchie formátu SVG (tam, kde je nahrazení žádoucí). Při ukládání dat SVG dokumentu pak stačí využít metod pro ukládání standardního XML dokumentu. Knihovna tříd dále implementuje rozšířenou kontrolu správnosti dat SVG dokumentu dle specifikace SVG. Základními prvky systému kontrol jsou následující 4 třídy:
SvgAttributeProvider,
SvgElementProvider,
SvgAttributeFactory
a
SvgElementFactory. První dvě jmenované třídy představují výchozí abstraktní třídy pro objektovou strukturu poskytovatelů atributů a elementů. Druhé dvě třídy pak tvoří rozhraní mezi jednotlivými SVG elementy (reprezentovanými výchozí abstraktní třídou SvgElement) a jejich atributy či potomky v XML stromu (tyto třídy představují správce poskytovatelů atributů a elementů pro příslušný SVG element). Přiblížení struktury XML dokumentu, kde každý element či atribut je stejně důležitý a má stejné vlastnosti jako jiný element či atribut, struktuře SVG dokumentu, kde se vztahy mezi elementy a atributy řídí specifikací SVG, bylo realizováno následujícím způsobem. V případě elementů došlo k již zmíněnému vytvoření zvláštní třídy pro každý jeden SVG element. V případě atributů nebylo zvoleno nahrazení objektu atributu ekvivalentní odvozenou třídou, nicméně k realizaci této objektové struktury došlo na úrovni poskytovatelů atributů.
17
Poskytovatel
elementů
existuje
jen
jeden,
je
reprezentován
třídou
DefaultElementProvider a je společný pro všechny elementy. O specifikaci odlišností v chování jednotlivých elementů ve struktuře se starají dva atributy (zde ve významu atributu platformy .NET), kterými jsou opatřeny odvozené třídy všech SVG elementů. Pomocí těchto atributů lze např. specifikovat, zda se daný SVG element může jako potomek jiného vyskytnout vícekrát apod. Pro každý atribut dle specifikace SVG byl naopak vytvořen speciální poskytovatel (výjimkou jsou některé atributy, které se opakují na více elementech; takové atributy pak v praxi reprezentuje stejná třída poskytovatele). Toto řešení umožnilo přidat do poskytovatelů vlastnosti a metody pro manipulaci s obsahem atributů. V původní XML struktuře je hodnota atributu reprezentována řetězcem. Použití poskytovatelů však umožnilo např. reprezentovat číselná data jako číslo apod. V praxi jsou mezi konkrétní poskytovatele a výchozí třídu zařazeny ještě třídy reprezentující určitý specifický datový typ dle specifikace SVG. To umožnilo několika poskytovatelům sdílet stejné funkce pro zpracování hodnot jejich atributů. Každá třída pro libovolný SVG element je odvozena ze třídy SvgElement. Tato třída v sobě obsahuje funkce sdílené všemi SVG elementy. Konkrétně, obsahuje instance tříd SvgAttributeFactory a SvgElementFactory a dále pak sadu metod využívajících funkce těchto dvou tříd k vynucení správnosti dat SVG dokumentu dle specifikace SVG. Každá odvozená třída pak v příslušných metodách informuje výchozí třídu o atributech a potomcích, které podporuje. Funkce ve výchozí třídě pak automaticky provádějí příslušné kontroly. Výchozí třída také implementuje další metody využívající služeb správců poskytovatelů atributů a elementů. Lze tak získat seznam všech potomků (SVG elementů), které příslušný SVG element právě obsahuje, dále tento seznam omezit jen na konkrétní třídu potomků, získat seznam všech poskytovatelů atributů, nebo jen těch, jejichž atributy SVG element právě obsahuje. Přímým využitím správce poskytovatelů elementů je pak i realizace již zmíněné transformace jednotlivých XML elementů na jejich SVG ekvivalenty při načítání SVG dokumentu. Podobným způsobem je rovněž realizován přístup k obsahu SVG elementu pomocí vlastností (zastřešení funkce popisných SVG elementů desc, title a metadata).
18
Aby bylo možné realizovat kontrolu správnosti dat SVG dokumentu dle specifikace SVG, ale i jiné funkce, bylo nutné vytvořit způsob, jak příslušné elementy informovat o tom, že dochází k nějaké změně ve struktuře dokumentu. To bylo realizováno pomocí třídy SvgDocument, která obsluhou příslušných událostí předka (třídy XmlDocument), jejich zpracováním a následným voláním příslušných metod na vlastních SVG elementech zajistí vše potřebné. Jednou z operací, kterou grafická aplikace využívající prostředků formátu SVG potřebuje provádět, je odkazování se na nějaký konkrétní SVG element, který je označen atributem id s příslušnou hodnotou (tuto operaci však také využívá i sama knihovna tříd pro realizaci podpory pro element shadow trees, viz. další odstavec). Třída SvgDocument, zastřešující celý SVG dokument, obsahuje funkce pro realizaci této operace a ostatních souvisejících operací. Třída spravuje interní mapování hodnot id atributů elementů na příslušné instance těchto elementů. Aktualizace (včetně přidávání a rušení) referencí jsou zajištěny automaticky pomocí stejné techniky jako v případě kontroly správnosti dat. Dotaz na existenci mapování lze pak realizovat voláním příslušné veřejné metody třídy. Důležitou vlastností formátu SVG je podpora tzv. element shadow trees (lze přeložit např. jako virtuální stromy elementů). Tato podpora je nutná pro správné fungování use elementu. Tento SVG element umožňuje odkázat se na téměř libovolný (dané specifikací SVG) element v rámci aktuálního dokumentu (omezeno implementací), vytvořit virtuální strom SVG elementů, který bude obsahovat odkazovaný element a dále všechny jeho potomky (včetně jejich potomků atd.). Nedochází však ke kopírování vlastních SVG elementů. Virtuální strom je realizován pomocí třídy SvgDocumentFragment, která zajistí jeho mapování na příslušný use element, který daný strom založil (toto je nutné zejména proto, aby bylo vždy možné zjistit aktuálního předka v tzv. rendering tree, tedy ve stromu, podle kterého probíhá výsledné vykreslení či jiné zpracování SVG dokumentu). Tato třída pak jako potomky obsahuje instance třídy SvgElementInstance, které reprezentují instance jednotlivých SVG elementů objevujících se ve virtuálním stromu. S tímto řešením úzce souvisí rozhraní ISvgRenderingData, které implementují jak třídy reprezentující vlastní SVG elementy, tak i třída SvgElementInstance. Využitím tohoto rozhraní lze
19
naprogramovat metody, které umožní zpracovat příslušný SVG element bez ohledu na to, zda je prvkem reálného či virtuálního stromu.
2.2.
Popis nejdůležitějších tříd
Popis tříd je předmětem kódové dokumentace, viz. Dodatek B.
2.3.
Příklady využití knihovny
První příklad ukazuje způsob, jak vytvořit novou instanci třídy SvgDocument, načíst existující SVG dokument a uložit jej znovu do jiného souboru. Tento příklad ukazuje
v praxi
podobnost
třídy
SvgDocument
obecně
využívané
třídě
XmlDocument pro práci s XML dokumenty, která je součástí Microsoft .NET Framework.
// zalození instance tridy SvgDocument doc = new SvgDocument(); // nacteni jiz existujiciho SVG dokumentu doc.Load(@"C:\test_load.svg"); // ulozeni SVG dokumentu do souboru doc.Save(@"C:\test_save.svg");
Druhý příklad ukazuje, jak v aktuálním dokumentu vytvořit SVG elementy desc a title sloužící k popisu obsahu dokumentu. U těchto elementů není nutné pracovat přímo s třídami reprezentujícími tyto elementy, ale lze využít přístupu k jejich obsahu přes vlastnosti třídy SvgDocument. Vlastnosti Title, Description a Metadata jsou rovněž k dispozici přes rozhraní ISvgDescription. Toto rozhraní implementuje mnoho dalších SVG elementů, které podporují vysvětlující komentáře ke svému obsahu pomocí výše uvedených elementů.
// nastaveni nazvu dokumentu doc.Title = "Nejaky nazev" // nastaveni vysvetlujiciho komentare k dokumentu doc.Description = "Nejaky popis dokumentu"; // nastaveni nazvu dokumentu pres rozhrani ISvgDescription ISvgDescription desc = doc as ISvgDescription;
20
desc.Title = "Nazev zapsany pres rozhrani".
Odkaz na kořenový svg element lze získat pomocí vlastnosti RootElement třídy SvgDocument. Tím je získán odkaz na instanci třídy SvgSvgElement. Tato třída je potomkem třídy SvgElement a umožňuje tedy použití všech funkcí definovaných na SVG elementech. Následující příklad ukazuje vytvoření g elementu a následně dvou rect elementů. První rect element používá ke specifikaci svých atributů způsob obvyklý při vytváření XML dokumentů prostředky Microsoft .NET Framework. Druhý rect element ukazuje použití vlastností rect elementu ke specifikování základních atributů a následně rovněž použití metody GetPresentationAttribute rozhraní ISvgStylable, která vrací rozhraní ICssValue určené pro přímý (a vždy aktuální) přístup k hodnotám prezentačních atributů, a nakonec také použití metody GetPresentationAttributeProvider
třídy
SvgElement,
která
vrací
rozhraní
ISvgPresentationAttributeProvider určené pro přímý přístup k poskytovatelům prezentačních atributů.
// zalozeni g elementu SvgGElement g = doc.RootElement.CreateSvgElement<SvgGElement>(); // zalozeni prvniho rect elementu SvgRectElement rect = g.CreateSvgElement<SvgRectElement>(); // specifikace atributu rect.SetAttribute("x", "10px"); rect.SetAttribute("y", "10px"); rect.SetAttribute("width", "100px"); rect.SetAttribute("height", "100px"); rect.SetAttribute("fill", "rgb(40%, 80%, 20%)"); rect.SetAttribute("stroke", "black"); rect.SetAttribute("stroke-width", "2em"); // pridani elementu jako potomka g elementu g.AppendChild(rect); // zalozeni druheho rect elementu 21
rect = g.CreateSvgElement<SvgRectElement>(); // specifikace atributu rect.X = new SvgLength(10, SvgLengthUnitType.Pixel); rect.Y = new SvgLength(10, SvgLengthUnitType.Pixel); rect.Width = new SvgLength(100, SvgLengthUnitType.Pixel); rect.Height = new SvgLength(100, SvgLengthUnitType.Pixel); ICssValue value = rect.GetPresentationAttribute("fill"); value.Text = "rgb(40%, 80%, 20%)"; value = rect.GetPresentationAttribute("stroke"); value.Text = "black"; ISvgPresentationAttributeProvider pAP = rect.GetPresentationAttributeProvider("stroke-width"); pAP.Value = "2em"; // pridani elementu jako potomka g elementu g.AppendChild(rect); // pridani g elementu jako potomka korenoveho elementu doc.RootElement.AppendChild(g);
Následující příklad ukazuje, jak provést nějakou operaci na všech potomcích nějakého SVG elementu. První část příkladu předvádí g element, jehož potomky mohou být různé typy SVG elementů. Druhá část příkladu předvádí linearGradient element,
u
kterého
je
získán
seznam
všech
bodů
změny
gradientu,
reprezentovaných stop elementem.
// cyklus pres vsechny elementy foreach (SvgElement element in g.GetSvgElements()) { // provest nejakou operaci na vsech elementech } // cyklus pres stop elementy foreach (SvgStopElement stop in linearGradient.GetSvgElements<SvgStopElement>()) { // provest nejakou operaci na vsech stop elementech }
22
Nejkomplexnějším příkladem toho, co vše tato knihovna tříd umožňuje, je však zdrojový kód následujících dvou projektů.
3. Projekt drawing 3.1.
Popis implementace knihovny
Tato knihovna tříd definuje a implementuje výchozí třídy pro prezentaci a zobrazování grafických dat ve formátu SVG, konkrétní třídy implementující prezentaci a zobrazování grafických dat ve formátu SVG nad GDI+, rovněž pak obsahuje výchozí třídu, která umožňuje kreslení (u některých formátů lépe vytváření grafických dat) nezávisle na výstupním formátu pomocí syntaxe obvyklé při využití třídy Graphics, která je v Microsoft .NET Framework verze 2.0 určena ke kreslení do GDI+. Současná implementace umožňuje, pomocí dvou konkrétních tříd, které tyto funkce implementují, omezeně kreslit do GDI+ a do SVG (resp. dynamicky vytvářet grafická dat ve formátu SVG). Výchozí třídy pro prezentaci a zobrazování grafických dat ve formátu SVG implementují vlastnosti a metody, které jsou společné pro všechny třídy implementující zobrazování s užitím konkrétních prostředků nějakého rozhraní či platformy. Třída SvgViewer obsahuje vlastnosti určené k nastavení velikosti počátečního viewportu (velikostí omezené plátno s možností ořezávání obsahu) a také řadu chráněných metod určených pro zpracování CSS hodnot atributů během renderingu. Třída SvgRenderingContext implementuje metody pro převádění jednotek, podporu kontextové informace o velikosti fontu (tato informace pak slouží k výpočtu reálné velikosti jednotek em a ex), podporu pro zjišťování konkrétní hodnoty prezentačních atributů (podpora dědičnosti a výchozích hodnot), podporu pro zásobník obsahující informace o viewboxech (uživatelský souřadný systém definovaný v rámci nějakého viewportu) a také podporu pro uchovávání informací o nekritických chybách. Konkrétní implementace prezentace a zobrazování grafických dat ve formátu SVG nad GDI+ je realizována třídami SvgGdiViewer a SvgGdiRenderingContext. Pro interakci s grafickou aplikací, která třídy využívá, je určena metoda PaintDocument, která po založení kontextu pro rendering zahájí samotné vykreslování. Jako rozhraní 23
pro výsledná grafická data byla zvolena třída Microsoft .NET Framework Image; jedná se o výchozí třídu GDI+ reprezentující na formátu nezávislá grafická data. Transformace souřadného systému jsou implementovány pomocí zásobníku obsahujícího třídy reprezentující matice transformace. Každá další transformace či skupina transformací je vyjádřena pomocí matice transformace, zleva vynásobena aktuální maticí transformace a uložena na zásobník. Stejným způsobem je realizováno založení nového viewportu či viewboxu. Jakékoli vykreslování grafických dat pak probíhá s použitím nové aktuální matice transformace. Na konci platnosti aktuální transformace souřadného systému je matice reprezentující tuto transformaci ze zásobníku odebrána. Tím je zajištěn návrat k původnímu souřadnému systému (včetně jeho transformací) před aplikováním dané transformace. Implementace používá koncept vrstev. V rámci kontextu je uchováván odkaz na cílovou vrstvu (reprezentovanou instancí třídy Image, která je vstupem metody PaintDocument), dále pak odkazy na vrstvy sloužící pro ořezávání a alphamaskování obsahu a také odkaz na temporální vrstvu určenou pro některé speciální operace (použití průhledných obrysů či výplní apod.). Kontext rovněž obsahuje zásobník pro další kreslící vrstvy. Na začátku renderingu je obsahem zásobníku jen cílová vrstva a rendering tedy probíhá právě na cílovou vrstvu. Pokud je při renderingu nalezen SVG element, který vyžaduje použití ořezávání, alpha-masky či definuje hodnotu průhlednosti, je pro rendering tohoto elementu (a jeho potomků) založena nová vrstva a uložena na zásobník. Po zpracování SVG elementu dochází k odstranění aktuální vrstvy ze zásobníku a jejímu tzv. merge s předchozí vrstvou. V rámci tohoto procesu je případně provedeno ořezání, alpha-maskování a aplikace průhlednosti. Ke zpracování speciálního ořezávání (definovaného elementem clipPath) a alpha-maskování (definovaného elementem mask) jsou použity upravené verze kreslících metod a výsledek renderingu je pak uložen na speciální vrstvy určené k těmto účelům (viz. předchozí odstavec). V merge fázi pak dochází ke zpracování grafických dat z těchto vrstev (pokud to daný SVG element vyžaduje). Toto zpracování je implementováno přímým přístupem ke grafickým datům jednotlivých pixelů s využitím aritmetiky ukazatelů. Tato nestandardní implementace byla 24
zvolena z výkonnostních důvodů, kdy by použití čistě managed řešení značně zvýšilo nároky na procesor nebo paměť RAM. Pro úplnost následuje stručný popis implementace na výstupním formátu nezávislého kreslení. Výchozí třída, nazvaná GraphicsBase, definuje metody určené pro kreslení základních grafických prvků. Grafická aplikace tak použije ve svých kreslících rutinách právě instanci třídy GraphicsBase. Odvozené třídy, GdiGraphics a SvgGraphics, představují konkrétní implementaci kreslení pro příslušný výstupní formát. Třída GdiGraphics pro kreslení interně využívá instanci třídy Graphics určenou pro kreslení do GDI+, třída SvgGraphics pak generuje objektovou strukturu formátu SVG a výsledky ukládá do instance třídy SvgDocument. V kódu využívajícím funkcí těchto tříd pak lze kdykoli pomocí operátoru is jazyka C# zjistit, do jakého výstupního formátu kreslení právě probíhá, a optimalizovat tak svou činnost.
3.2.
Popis nejdůležitějších tříd
Popis tříd je předmětem kódové dokumentace, viz. Dodatek B.
3.3.
Příklady využití knihovny
První příklad ukazuje způsob, jak zjistit reálnou velikost výchozího viewportu v pixelech, vytvořit bitovou mapu v paměti, rozhodnout, zda povolit zoomování a vykreslit obsah nějakého SVG dokumentu pomocí nové instance prohlížecí třídy. Proměnné containerSize, dpi, font a zoomRatio představují po řadě velikost kontejneru pro nějaký ovládací prvek, který bude zobrazovat výsledný obrázek (nutné pro interpretaci hodnot zadaných v procentech), rozlišení obrázku v dotsper-inch (nutné pro přepočet pixelů na pointy, inche apod.), referenční font (nutné pro interpretaci hodnot zadaných v jednotkách em nebo ex) a hodnotu aktuálního zoomu (uváděno jako násobek původní velikosti).
// nastavit vychozi parametry prohlizeci tridy SvgViewerDefaults defaults = new SvgViewerDefaults(Color.Black, font.SizeInPoints); // zalození instance prohlizeci tridy SvgGdiViewer viewer = new SvgGdiViewer(doc, defaults);
25
// zjistit doporucenou realnou velikost v pixelech SizeF size = viewer.GetRealSize(containerSize, dpi, font); SizeF zoomedSize = size; // zjistit, zda je podporovano zoomovani if (viewer.ZoomAndPan) { // upravit realnou velikost zoomedSize.Width *= zoomRatio; zoomedSize.Height *= zoomRatio; } // zaokrouhlit velikost na cela cisla Size intSize = new Size((int)Math.Round(zoomedSize.Width), (int)Math.Round(zoomedSize.Height)); // zalozit bitovou mapu Bitmap bitmap = new Bitmap(intSize.Width, intSize.Height); // vykreslit obsah SVG dokumentu viewer.PaintDocument(bitmap, size, zoomRatio, true);
Druhý příklad ukazuje, jak použít třídy pro kreslení nezávisle na výstupním formátu. Příklad obsahuje 3 metody. První metoda zakládá instanci třídy GdiGraphics s použitím nějaké instance třídy Image. Druhá metoda pak zakládá instanci třídy SvgGraphics s použitím nějaké instance třídy SvgDocument. Obě metody pak volají třetí metodu, která, nezávisle na výstupním formátu, nakreslí a vyplní obdélník. V první metodě je rovněž naznačeno, jak nastavit speciální vlastnosti vztahující se k vykreslení prostřednictvím GDI+.
public void PaintOnImage(Image image) { // zalozit instanci tridy GdiGraphics using (GdiGraphics g = GdiGraphics.FromImage(image)) { // nastavit specialni vlastnosti GDI+ g.GdiSurface.SmoothingMode = SmoothingMode.HighQuality; g.GdiSurface.PixelOffsetMode = PixelOffsetMode.HighQuality;
26
// nakreslit obdelnik this.PaintRectangle(g); } } public void PaintToSvg(SvgDocument doc, float dpi) { // zalozit instanci tridy SvgGraphics using (SvgGraphics g = SvgGraphics.FromDocument(doc, dpi)) { // nakreslit obdelnik this.PaintRectangle(g); } } private void PaintRectangle(GraphicsBase g) { // nadefinovat obdelnik Rectangle rect = new Rectangle(10, 10, 100, 100); // nakreslit obrys obdelniku cervene g.DrawRectangle(Pens.Red, rect); // vyplnit obdelnik modre g.FillRectangle(Brushes.Blue, rect); }
4. Projekt drawingwpf 4.1.
Popis implementace knihovny
Tato knihovna tříd definuje a implementuje třídy pro prezentaci a zobrazování grafických dat ve formátu SVG pod WPF. Konkrétní implementace je realizována třídami SvgWpfViewer a SvgWpfRenderingContext. Pro interakci s grafickou aplikací, která třídy využívá, je určena metoda PaintDocument, která po založení kontextu pro rendering zahájí samotné vykreslování. Jako rozhraní pro výsledná grafická data byla zvolena třída WPF Canvas; jedná se o kontejner WPF elementů, kde lze u každého elementu stanovit jeho přesnou pozici v aktuálních jednotkách v rámci plátna.
27
Implementace využívá koncept vrstev. Každá vrstva je vyjádřena novou instancí třídy Canvas. Aktuální kreslící vrstva je vždy na vrcholu zásobníku vrstev. Na začátku renderingu je obsahem zásobníku jen cílové plátno a rendering tedy probíhá právě na cílové plátno. Pokud je při renderingu nalezen SVG element, který vyžaduje použití ořezávání či definuje nějaké transformace souřadného systému, je pro rendering tohoto elementu (a jeho potomků) založena nová vrstva a uložena na zásobník. Po zpracování SVG elementu dochází k odstranění aktuální vrstvy ze zásobníku a nastavení příslušných vlastností vrstvy. Transformace souřadného systému jsou pro jednoduchost implementovány pomocí použití vlastnosti RenderTransform nově vytvořené vrstvy reprezentované instancí třídy Canvas. Ke zpracování speciálního ořezávání (definovaného elementem clipPath) jsou použity upravené verze kreslících metod a výsledek renderingu je pak přiřazen vlastnosti Clip nově vytvořené vrstvy reprezentované instancí třídy Canvas. Alphamaskování není v této knihovně tříd implementováno, neboť tuto funkci nelze implementovat managed způsobem. Každý SVG element, který má být vykreslen, je převeden na svou optimální reprezentaci ve WPF struktuře a přiřazen jako potomek aktuální vrstvě. Vlastnosti SVG elementu, jako je např. průhlednost, jsou implementovány pomocí odpovídajících vlastností WPF objektové reprezentace SVG elementu.
4.2.
Popis nejdůležitějších tříd
Popis tříd je předmětem kódové dokumentace, viz. Dodatek B.
4.3.
Příklady využití knihovny
První příklad ukazuje způsob, jak zjistit reálnou velikost výchozího viewportu v pixelech, vytvořit nove plátno, rozhodnout, zda povolit zoomování a vykreslit obsah nějakého SVG dokumentu pomocí nové instance prohlížecí třídy. Proměnné containerSize, dpi, fontSize a zoomRatio představují po řadě velikost kontejneru pro nějaký ovládací prvek, který bude zobrazovat výsledný obrázek (nutné pro interpretaci hodnot zadaných v procentech), rozlišení obrázku v dots-per-inch (nutné pro přepočet pixelů na pointy, inche apod.), velikost referenčního fontu
28
v aktuálních jednotkách (nutné pro interpretaci hodnot zadaných v jednotkách em nebo ex) a hodnotu aktuálního zoomu (uváděno jako násobek původní velikosti).
// nastavit vychozi parametry prohlizeci tridy SvgViewerDefaults defaults = new SvgViewerDefaults(Color.Black, fontSize); // zalození instance prohlizeci tridy SvgWpfViewer viewer = new SvgWpfViewer(doc, defaults); // zjistit realnou velikost v aktualnich jednotkach Size size = viewer.GetRealSize(containerSize, dpi, fontSize); // zalozit platno a nastavit jeho velikost Canvas canvas = new Canvas(); canvas.Width = size.Width; canvas.Height = size.Height; // zjistit, zda je podporovano zoomovani if (viewer.ZoomAndPan) { // definovat zmenu meritka ScaleTransform st = new ScaleTransform(zoomRatio, zoomRatio); // aplikovat zmenu meritka canvas.LayoutTransform = st; } // vykreslit obsah SVG dokumentu viewer.PaintDocument(canvas, size, dpi);
Druhý příklad ukazuje způsob, jak uložit vygenerovanou WPF strukturu na disk a získat tak transformaci formátu SVG do formátu XAML. Příklad předpokládá, definici a použití proměnné canvas z předchozího příkladu.
XmlWriter xw = new XmlTextWriter("data.xaml", Encoding.UTF8); try { XamlWriter.Save(canvas, xw); xw.Flush(); 29
} finally { xw.Close(); }
5. Ostatní součásti implementace 5.1.
Stručný popis projektu testapp
Výstupem projektu je Windows Forms aplikace určená k testování funkcí knihovny tříd pro prezentaci a zobrazování grafických dat ve formátu SVG nad GDI+. Aplikace umožňuje načtení SVG dokumentu a jeho zobrazení prostředky GDI+, včetně podpory zoomování. Aplikace dále obsahuje několik dalších testovacích funkcí.
5.2.
Stručný popis projektu wpfviewer
Výstupem projektu je aplikace využívající prostředků Windows Presentation Foundation určená k testování funkcí knihovny tříd pro prezentaci a zobrazování grafických dat ve formátu SVG pod WPF. Aplikace umožňuje načtení SVG dokumentu a jeho zobrazení prostředky WPF, včetně podpory zoomování, umožňuje také otevření více SVG dokumentů současně a přepínání mezi nimi.
30
Část III. Zhodnocení a závěr
1. Zhodnocení naplnění zadání Zadání bakalářské práce bylo splněno. Výsledné knihovny tříd umožňují tvorbu grafických aplikací určených k vytváření, zpracování, načítání a ukládání statických vektorových grafických dat ve formátu SVG, dále rovněž grafických aplikací určených k prezentaci těchto dat s využitím prostředků rozhraní GDI+ a také prostředků formátu XAML. Při implementaci realizované podmnožiny formátu SVG bylo důsledně dbáno na specifikaci standardu formátu SVG ve verzi 1.1. Původní komerční zadání firmy GD Software bylo rovněž splněno. Řešení bylo firmou akceptováno a nyní bude začleňováno do příslušných aplikací. Forma realizace plně vyhovuje a umožní v budoucnu zcela opustit dříve používaný proprietární binární formát. Řešení umožňuje využití v jakékoli formě aplikace, vyvíjené na platformě Microsoft .NET Framework verze 2.0, tak, jak bylo původním zadáním požadováno. Rovněž byla splněna nutnost implementace výstupů do rastrového formátu GIF. Rozšíření původního zadání o podporu části Microsoft .NET Framework verze 3.0, hlavně pak o možnost budování grafických XBAP aplikací dostupných v rámci podnikového intranetu, bylo firmou GD Software velmi kladně přijato a značně rozšířilo potenciál vývoje intranetových a internetových aplikací této firmy.
2. Další cíle práce Cílem práce je nabídnout současnou podobu implementace včetně zdrojového kódu široké veřejnosti. Pro projekt budou vytvořeny samostatné webové stránky, na které bude umístěn popis a záměr projektu, popis současného stavu implementace, zdrojový kód implementace a rovněž také výzva všem, kteří by se chtěli podílet na vývoji projektu tak, aby podporoval co nejvíce ze standardu formátu SVG a případně do budoucna i novou verzi tohoto formátu. Plná podpora standardu formátu SVG
31
není realizovatelná (v rozumném časovém období) jednotlivcem a zde by tedy podpora vývojářské komunity výrazně pomohla.
3. Závěr V rámci této bakalářské práce byly navrženy, implementovány a ověřeny knihovny tříd, využívající prostředků Microsoft .NET Framework, které umožňují libovolné grafické aplikaci vytváření, zpracování, načítání a ukládání vektorových grafických dat ve formátu SVG dle standardu formátu SVG verze 1.1. Implementace vycházela z konkrétních potřeb definovaných zadáním a není tedy úplná. Způsob realizace a zpřístupnění zdrojových kódů umožňují další doplnění dosud neimplementovaných částí standardu.
32
Dodatek A. Zdrojový kód Zdrojový kód implementace je k dispozici na přiloženém CD v adresáři /source. Návod na jeho úspěšnou kompilaci je popsán v části II., kapitole 1. – Základní popis řešení.
33
Dodatek B. Dokumentace ke zdrojovému kódu Dokumentace ke zdrojovému kódu byla vygenerována s použitím programu Sandcastle (http://blogs.msdn.com/sandcastle/) a je k dispozici ve formátu Microsoft Compiled HTML Help (CHM) na přiloženém CD v adresáři /doc.
34
Dodatek C. Použitá literatura [1] W3C Consortium (2003): Scalable Vector Graphics (SVG) 1.1 Specification. http://www.w3.org/TR/SVG11/.
35