Obsah
1. Grafický metaformát EMF
2. Formát EMF a funkce WinAPI
3. Struktura souborů typu EMF
4. Údajová hlavička a popisný řetězec
5. Záznamy o grafických objektech
6. Ukončující záznam (blok)
7. Čísla jednotlivých záznamů
8. Odkazy na další informační zdroje
9. Obsah následující části tohoto seriálu
1. Grafický metaformát EMF
Grafický metaformát EMF neboli Enhanced Windows Metafile vznikl rozšířením původního formátu WMF (Windows Metafile), který jsme si popsali v předchozích dvou částech tohoto seriálu. Zatímco WMF vycházel z poměrně omezených možností grafického subsystému (GDI) šestnáctibitových Windows, konkrétně Microsoft Windows 2.0 a posléze Microsoft Windows 3.11, je EMF postaven na třicetidvoubitovém grafickém subsystému, který je plně podporován od Microsoft Windows NT (na Windows 95 a Windows 98 existují v GDI určitá omezení, ty se ovšem při zpracování souborů typu EMF většinou neprojeví). Mezi zajímavé rozšíření GDI patří především práce s cestami, podpora rastrových obrázků nezávislých na zařízení a také podpora Unikódu (nejprve textů kódovaných v UCS-2, posléze i plný UTF-16, i když s ním mají některé programy velké problémy). Firma Microsoft doporučuje, aby se na třicetidvoubitových Windows používal především formát EMF, avšak mnoho vektorových obrázků je stále uloženo v jeho starším bratříčkovi WMF.
Porozumět interní struktuře souborů typu EMF je poměrně důležité, ať už pro jejich zpracování v programech, které z různých důvodů nemohou použít přímo funkce WinAPI (spouštění na odlišném operačním systému, tvorba přenositelných programů, programů psaných v Javě bez využití JNI apod.), nebo při ovládání některých tiskáren (laserových, inkoustových), protože mnoho jednodušších tiskáren, které nepodporují PostScript nebo PCL, využívá pro komunikaci právě formát EMF. V následující kapitole si krátce popíšeme způsob použití EMF pomocí funkcí nabízených aplikačním programovým rozhraním (API) Microsoft Windows a v dalších kapitolách si již ukážeme interní strukturu těchto souborů.
2. Formát EMF a funkce WinAPI
Přímo v systému Microsoft Windows je práce s formátem EMF velmi jednoduchá, protože pro jeho vytvoření stačí zavolat dvě nové funkce z API. Veškeré kreslení se provádí stejným způsobem, jako kreslení na obrazovku (přesněji řečeno do kontextu zařízení obrazovky) nebo tisk obrázku na tiskárně. Pro vytvoření EMF se používá funkce CreateEnhMetaFile(), o jeho uzavření (s případným zápisem na disk) se postará funkce CloseEnhMetaFile(). Následující programový kód ukazuje, jak se v operační paměti vytvoří výkres ve formátu EMF a jak se do něj vykreslí jednoduchý obrázek:
HENHMETAFILE hemf=NULL;
HDC hdcEMF=NULL;
// vytvoření kontextu zařízení pro vykreslování
hdcEMF=CreateEnhMetaFile(NULL, NULL, NULL, NULL);
// prázdný čtverec
Rectangle(hdcEMF, 100, 100, 200, 200);
// úhlopříčky čtverce
MoveToEx(hdcEMF, 100, 100, NULL);
LineTo(hdcEMF, 200, 200);
MoveToEx(hdcEMF, 200, 100, NULL);
LineTo(hdcEMF, 100, 200);
// uzavření výkresu a vrácení handlu na datovou strukturu
hemf=CloseEnhMetaFile(hdcEMF);
Vykreslení takto získaného výkresu (obsahu EMF souboru) je stejně jednoduché jako při práci s původními soubory typu WMF, pouze se zavolá odlišná funkce z WinAPI:
// kontext zařízení je nutné před použitím naplnit
HDC hdc;
// překreslovaná oblast
PAINTSTRUCT ps ;
RECT rect;
// získat kontext zařízení obrazovky
hdc=BeginPaint(hwnd, &ps);
// vypočítat oblast, do které se EMF "nazoomuje"
GetClientRect(hwnd, &rect);
rect.left = rect.right /4;
rect.right = 3 * rect.right /4;
rect.top = rect.bottom/4;
rect.bottom = 3 * rect.bottom/4;
// vlastní vykreslení obsahu EMF souboru
PlayEnhMetaFile(hdc, hemf, &rect);
// oznámit OS, že je vykreslování ukončeno
EndPaint(hwnd, &ps);
// a smazat metasoubor z operační paměti
DeleteEnhMetaFile(hemf);
3. Struktura souborů typu EMF
Soubory typu EMF používají (spolu s formátem typu WMF) binárně uložená data, což je pro vektorové výkresy, které jsou hlavním důvodem, proč se EMF mimo OS Windows vůbec používá, poněkud netypické. Další vektorové souborové formáty, například PostScript, SVG, DXF, HPGL apod. jsou totiž založeny na textovém popisu a zdá se, že se vývoj v oblasti souborových formátů ubírá právě tímto směrem (samozřejmě s možností použít na výsledná data uložená převážně ve strukturované textové podobě nějaký běžný komprimační algoritmus typu LZW či LZ77). Interní struktura souborů EMF je poměrně jednoduchá. Binárně kódovaná data jsou uložena v blocích, přičemž každý blok obsahuje hlavičku, ve které je uložena identifikace typu záznamu a současně i délka bloku. To znamená, že i bez znalosti konkrétní struktury jednotlivých bloků je možné souborem EMF „projít“ a nalézt pouze hledané údaje, například texty či souřadnice těch grafických entit, které program dokáže vykreslit.
Samotná hlavička celého souboru (která je popsána v následující kapitole) i ukončující záznam (popsaný v kapitole šesté) jsou taktéž tvořeny bloky s přiřazeným číslem. Rozšíření struktury hlavičky do budoucnosti je tedy možné provést jednoduše – buď se zavede nový typ bloku, nebo se stávající blok hlavičky rozšíří a tím se zvětší i jeho délka.
4. Údajová hlavička a popisný řetězec
Jak jsem se již zmínil v předchozí kapitole, je samotná údajová hlavička umístěná na začátku souboru EMF, taktéž považována za běžný blok, tj. obsahuje svoji jednoznačnou identifikaci a délku. Minimální délka hlavičky je 80 bytů, ke kterým je nutné připočíst osm bytů pro uložení samotné identifikace a délky, ovšem její maximální rozsah není předem známý, což si ukážeme v následující části tohoto seriálu na praktických příkladech. Struktura části hlavičky, která musí být dodržena ve všech souborech typu EMF je vypsána v tabulce níže. Datové typy, které jsou v hlavičce použity, odpovídají konvencím typů používaným v hlavičkových souborech windows.h, wingdi.h a wtypes.h, tj. WORD je šestnáctibitové celé číslo bez znaménka (unsigned short), DWORD je třicetidvoubitové celé číslo bez znaménka (unsigned long) a LONG je třicetidvoubitové celé číslo se znaménkem (signed long).
Offset | Velikost (typ) | Jméno | Popis |
---|---|---|---|
0 | DWORD | RecordType | vždy nastaveno na 0×00000001 |
4 | DWORD | RecordSize | délka v bytech |
8 | LONG | BoundsLeft | souřadnice levého okraje kresby |
12 | LONG | BoundsRight | souřadnice pravého okraje kresby |
16 | LONG | BoundsTop | souřadnice horního okraje kresby |
20 | LONG | BoundsBottom | souřadnice spodního okraje kresby |
24 | LONG | FrameLeft | souřadnice levého okraje rámce |
28 | LONG | FrameRight | souřadnice pravého okraje rámce |
32 | LONG | FrameTop | souřadnice horního okraje rámce |
36 | LONG | FrameBottom | souřadnice spodního okraje rámce |
40 | DWORD | Signature | vždy nastaveno na 0×464D4520 (‚EMF‘) |
44 | DWORD | Version | verze metasouboru, většinou 0×00000100 |
48 | DWORD | Size | velikost celého souboru v bytech |
52 | DWORD | NumOfRecords | celkový počet záznamů (bloků) včetně hlavičky |
56 | WORD | NumOfHandles | celkový počet GDI handlů (v souboru je zde 0) |
58 | WORD | Reserved | vždy nastaveno na 0×00000000 |
60 | DWORD | SizeOfDescrip | počet znaků umístěných v popisném řetězci (včetně koncové nuly) |
64 | DWORD | OffsOfDescrip | umístění popisného řetězce (offset od začátku souboru) |
68 | DWORD | NumPalEntries | velikost barvové palety |
72 | LONG | WidthDevPixels | šířka zobrazovacího zařízení v pixelech |
76 | LONG | HeightDevPixels | výška zobrazovacího zařízení v pixelech |
80 | LONG | WidthDevMM | šířka zobrazovacího zařízení v milimetrech |
84 | LONG | HeightDevMM | výška zobrazovacího zařízení v milimetrech |
Pomocí hodnot SizeOfDescrip a OffsOfDescrip je určeno, zda a popř. kde je umístěn takzvaný popisný řetězec (description string), který je v lecčemž podobný poznámkám ukládaným do souborů typu GIF či PNG. Tento řetězec je ukončen dvěma znaky NULL, protože jeden znak NULL je použit pro oddělení jeho jednotlivých částí. Většinou bývá v první části řetězce uloženo jméno aplikace, která daný soubor vytvořila a ve druhé části pak popis obrázku. Teoreticky je tento řetězec uložen v kódování UTF-16, mnoho programů však počítá s tím, že je použito kódování UCS-2. Rozdíl mezi oběma kódováními je v praxi malý a pro běžné znaky (mám dojem, že včetně zjednodušené čínštiny) je můžeme zaměnit.
5. Záznamy o grafických objektech
Každý záznam (tj. blok informací) o grafickém objektu začíná hlavičkou záznamu, která obsahuje dvě třicetidvoubitová čísla uložená v pořadí little-endian, tj. tak, jak je to běžné na platformě i386. V prvním třicetidvoubitovém číslu je uložena identifikace funkce, tj. většinou GDI příkazu reprezentujícího vykreslení grafického objektu, změnu stavu kontextu kreslicího zařízení atd. Ve standardních souborech EMF se používá 97 různých příkazů. Druhé třicetidvoubitové slovo obsahuje délku záznamu uvedenou v bytech. Vzhledem k tomu, že se do této délky započítává i hlavička, musí zde být uložena číslo o hodnotě minimálně 8 (bytů). Po této velmi jednoduché hlavičce záznamu již následují jednotlivé parametry. Jejich počet a struktura se samozřejmě pro různé funkce liší.
6. Ukončující záznam (blok)
Na konci každého souboru typu EMF by měl být umístěn takzvaný ukončující záznam, jehož číslo je 14. V tomto záznamu nejsou uloženy žádné další informace, proto je jeho délka pouhých osm bytů. Při spojování více EMF souborů je nutné z každého připojovaného souboru (kromě posledního) odstranit ukončující záznam, ze všech souborů kromě prvního odstranit hlavičku a ve zbývající (jediné) hlavičce změnit údaje o délce souboru a celkovém počtu záznamů.
7. Čísla jednotlivých záznamů
Ve standardních souborech typu EMF se může vyskytovat celkem 97 různých typů záznamů (kromě hlavičky a ukončujícího záznamu). Ty jsou specifikovány symbolickými konstantami a čísly vypsanými v následující tabulce. Všimněte si, že čísla záznamů by klidně mohla být uložena na pouhém jednom bytu a dá se předpokládat, že i délka záznamů může být uložena na 24 bitech, tj. jak číslo záznamu, tak i jeho délku by bylo možné uložit do jednoho třicetidvoubitového čísla a snížit tak velikost souboru. V souborech typu EMF se tedy dalo přednost rychlosti zpracování před velikostí.
Symbolická konstanta | Hodnota |
---|---|
EMR_ABORTPATH | 68 |
EMR_POLYLINE | 4 |
EMR_ANGLEARC | 41 |
EMR_POLYLINE16 | 87 |
EMR_ARC | 45 |
EMR_POLYLINETO | 6 |
EMR_ARCTO | 55 |
EMR_POLYLINETO16 | 89 |
EMR_BEGINPATH | 59 |
EMR_POLYPOLYGON | 8 |
EMR_BITBLT | 76 |
EMR_POLYPOLYGON16 | 91 |
EMR_CHORD | 46 |
EMR_POLYPOLYLINE | 7 |
EMR_CLOSEFIGURE | 61 |
EMR_POLYPOLYLINE16 | 90 |
EMR_CREATEBRUSHINDIRECT | 39 |
EMR_POLYTEXTOUTA | 96 |
EMR_CREATEDIBPATTERNBRUSHPT | 94 |
EMR_POLYTEXTOUTW | 97 |
EMR_CREATEMONOBRUSH | 93 |
EMR_REALIZEPALETTE | 52 |
EMR_CREATEPALETTE | 49 |
EMR_RECTANGLE | 43 |
EMR_CREATEPEN | 38 |
EMR_RESIZEPALETTE | 51 |
EMR_DELETEOBJECT | 40 |
EMR_RESTOREDC | 34 |
EMR_ELLIPSE | 42 |
EMR_ROUNDRECT | 44 |
EMR_ENDPATH | 60 |
EMR_SAVEDC | 33 |
EMR_EOF | 14 |
EMR_SCALEVIEWPORTEXTEX | 31 |
EMR_EXCLUDECLIPRECT | 29 |
EMR_SCALEWINDOWEXTEX | 32 |
EMR_EXTCREATEFONTINDIRECTW | 82 |
EMR_SELECTCLIPPATH | 67 |
EMR_EXTCREATEPEN | 95 |
EMR_SELECTOBJECT | 37 |
EMR_EXTFLOODFILL | 53 |
EMR_SELECTPALETTE | 48 |
EMR_EXTSELECTCLIPRGN | 75 |
EMR_SETARCDIRECTION | 57 |
EMR_EXTTEXTOUTA | 83 |
EMR_SETBKCOLOR | 25 |
EMR_EXTTEXTOUTW | 84 |
EMR_SETBKMODE | 18 |
EMR_FILLPATH | 62 |
EMR_SETBRUSHORGEX | 13 |
EMR_FILLRGN | 71 |
EMR_SETCOLORADJUSTMENT | 23 |
EMR_FLATTENPATH | 65 |
EMR_SETDIBITSTODEVICE | 80 |
EMR_FRAMERGN | 72 |
EMR_SETMAPMODE | 17 |
EMR_GDICOMMENT | 70 |
EMR_SETMAPPERFLAGS | 16 |
EMR_HEADER | 1 |
EMR_SETMETARGN | 28 |
EMR_INTERSECTCLIPRECT | 30 |
EMR_SETMITERLIMIT | 58 |
EMR_INVERTRGN | 73 |
EMR_SETPALETTEENTRIES | 50 |
EMR_LINETO | 54 |
EMR_SETPIXELV | 15 |
EMR_MASKBLT | 78 |
EMR_SETPOLYFILLMODE | 19 |
EMR_MODIFYWORLDTRANSFORM | 36 |
EMR_SETROP2 | 20 |
EMR_MOVETOEX | 27 |
EMR_SETSTRETCHBLTMODE | 21 |
EMR_OFFSETCLIPRGN | 26 |
EMR_SETTEXTALIGN | 22 |
EMR_PAINTRGN | 74 |
EMR_SETTEXTCOLOR | 24 |
EMR_PIE | 47 |
EMR_SETVIEWPORTEXTEX | 11 |
EMR_PLGBLT | 79 |
EMR_SETVIEWPORTORGEX | 12 |
EMR_POLYBEZIER | 2 |
EMR_SETWINDOWEXTEX | 9 |
EMR_POLYBEZIER16 | 85 |
EMR_SETWINDOWORGEX | 10 |
EMR_POLYBEZIERTO | 5 |
EMR_SETWORLDTRANSFORM | 35 |
EMR_POLYBEZIERTO16 | 88 |
EMR_STRETCHBLT | 77 |
EMR_POLYDRAW | 56 |
EMR_STRETCHDIBITS | 81 |
EMR_POLYDRAW16 | 92 |
EMR_STROKEANDFILLPATH | 63 |
EMR_POLYGON | 3 |
EMR_STROKEPATH | 64 |
EMR_POLYGON16 | 86 |
EMR_WIDENPATH | 66 |
8. Odkazy na další informační zdroje
- Microsoft Corporation: Platform SDK,
Microsoft Corporation, 1995–2007 - Microsoft Corporation: Microsoft Windows: A Guide to Programming,
Microsoft Windows Programmer's Reference Library, Microsoft Press, Redmond, WA, 1990 - Microsoft Corporation: Microsoft Windows: Programmer's Reference, Volume 4: Resources,
Microsoft Windows Programmer's Reference Library, Microsoft Press, Redmond, WA, 1990 - Microsoft Corporation: Microsoft Windows: Programming Tools, Microsoft Windows Programmer's Reference Library,
Microsoft Press, Redmond, WA, 1990 - Petzold Charles: Programming Windows,
Microsoft Press, 1998 - Swan Tom: Inside Windows File Formats,
Sams Publishing, Indianapolis, IN, 1993 - FreeHEP VectorGraphics, (High Energy Physics)
http://java.freehep.org/vectorgraphics/ - Microsoft Windows Metafile,
http://wvware.sourceforge.net/caolan/ora-wmf.html - Windows Metafiles, a guide for non-windows programmers,
http://wvware.sourceforge.net/caolan/index.html - Metafile Reference,
http://msdn2.microsoft.com/en-us/library/ms534300.aspx - yFiles 2.3.x graph visualization library and WMF,
http://www.yworks.com/en/products_yfiles_ep_ywmf.htm - yFiles gallery,
http://www.yworks.com/en/products_yfiles_practicalinfo_gallery.htm - libwmf – library for converting WMF files,
http://wvware.sourceforge.net/libwmf.html - Wikipedia EN: Windows Metafile,
http://en.wikipedia.org/wiki/Windows_Metafile - Wikipedia EN: Enhanced Metafile,
http://en.wikipedia.org/wiki/Enhanced_Metafile - Wikipedia EN: Windows Media Format,
http://en.wikipedia.org/wiki/Windows_Media_Format - Wikipedia EN: Unicode,
http://en.wikipedia.org/wiki/Unicode - Wikipedia EN: UTF-16/UCS-2,
http://en.wikipedia.org/wiki/UTF-16/UCS-2
9. Obsah následující části tohoto seriálu
V další části seriálu o grafických formátech a metaformátech si ukážeme, jakým způsobem je možné načítat data, tj. binárně kódované informace o uloženém obrázku, z dnes popsaného metaformátu EMF (Enhanced Windows MetaFile).