Grafický metaformát EMF

25. 10. 2007
Doba čtení: 9 minut

Sdílet

V dnešním článku o grafických formátech si popíšeme nástupce WMF, kterým je grafický metaformát nazvaný jednoduše EMF. V tomto formátu, který byl primárně vytvořen pro potřeby třicetidvoubitových operačních systémů MS Windows, je již možné pracovat s cestami a bitmapami nezávislými na zařízení.

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 CreateEnhMeta­File(), o jeho uzavření (s případným zápisem na disk) se postará funkce CloseEnhMetaFi­le(). 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_CREATEBRUS­HINDIRECT 39
EMR_POLYTEXTOUTA 96
EMR_CREATEDIB­PATTERNBRUSHPT 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_SCALEVIEW­PORTEXTEX 31
EMR_EXCLUDECLIPRECT 29
EMR_SCALEWINDO­WEXTEX 32
EMR_EXTCREATE­FONTINDIRECTW 82
EMR_SELECTCLIPPATH 67
EMR_EXTCREATEPEN 95
EMR_SELECTOBJECT 37
EMR_EXTFLOODFILL 53
EMR_SELECTPALETTE 48
EMR_EXTSELECTCLIP­RGN 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_SETCOLORAD­JUSTMENT 23
EMR_FLATTENPATH 65
EMR_SETDIBITSTO­DEVICE 80
EMR_FRAMERGN 72
EMR_SETMAPMODE 17
EMR_GDICOMMENT 70
EMR_SETMAPPERFLAGS 16
EMR_HEADER 1
EMR_SETMETARGN 28
EMR_INTERSECTCLIP­RECT 30
EMR_SETMITERLIMIT 58
EMR_INVERTRGN 73
EMR_SETPALETTE­ENTRIES 50
EMR_LINETO 54
EMR_SETPIXELV 15
EMR_MASKBLT 78
EMR_SETPOLYFILLMODE 19
EMR_MODIFYWOR­LDTRANSFORM 36
EMR_SETROP2 20
EMR_MOVETOEX 27
EMR_SETSTRETCHBLTMO­DE 21
EMR_OFFSETCLIPRGN 26
EMR_SETTEXTALIGN 22
EMR_PAINTRGN 74
EMR_SETTEXTCOLOR 24
EMR_PIE 47
EMR_SETVIEWPOR­TEXTEX 11
EMR_PLGBLT 79
EMR_SETVIEWPOR­TORGEX 12
EMR_POLYBEZIER 2
EMR_SETWINDOWEXTEX 9
EMR_POLYBEZIER16 85
EMR_SETWINDOWORGEX 10
EMR_POLYBEZIERTO 5
EMR_SETWORLDTRAN­SFORM 35
EMR_POLYBEZIERTO16 88
EMR_STRETCHBLT 77
EMR_POLYDRAW 56
EMR_STRETCHDIBITS 81
EMR_POLYDRAW16 92
EMR_STROKEANDFIL­LPATH 63
EMR_POLYGON 3
EMR_STROKEPATH 64
EMR_POLYGON16 86
EMR_WIDENPATH 66

bitcoin_skoleni

8. Odkazy na další informační zdroje

  1. Microsoft Corporation: Platform SDK,
    Microsoft Corporation, 1995–2007
  2. Microsoft Corporation: Microsoft Windows: A Guide to Programming,
    Microsoft Windows Programmer's Re­ference Library, Microsoft Press, Redmond, WA, 1990
  3. Microsoft Corporation: Microsoft Windows: Programmer's Re­ference, Volume 4: Resources,
    Microsoft Windows Programmer's Re­ference Library, Microsoft Press, Redmond, WA, 1990
  4. Microsoft Corporation: Microsoft Windows: Programming Tools, Microsoft Windows Programmer's Re­ference Library,
    Microsoft Press, Redmond, WA, 1990
  5. Petzold Charles: Programming Windows,
    Microsoft Press, 1998
  6. Swan Tom: Inside Windows File Formats,
    Sams Publishing, Indianapolis, IN, 1993
  7. FreeHEP VectorGraphics, (High Energy Physics)
    http://java.fre­ehep.org/vector­graphics/
  8. Microsoft Windows Metafile,
    http://wvware­.sourceforge.net/ca­olan/ora-wmf.html
  9. Windows Metafiles, a guide for non-windows programmers,
    http://wvware­.sourceforge.net/ca­olan/index.html
  10. Metafile Reference,
    http://msdn2.mi­crosoft.com/en-us/library/ms534300­.aspx
  11. yFiles 2.3.x graph visualization library and WMF,
    http://www.ywor­ks.com/en/pro­ducts_yfiles_ep_yw­mf.htm
  12. yFiles gallery,
    http://www.ywor­ks.com/en/pro­ducts_yfiles_prac­ticalinfo_galle­ry.htm
  13. libwmf – library for converting WMF files,
    http://wvware­.sourceforge.net/lib­wmf.html
  14. Wikipedia EN: Windows Metafile,
    http://en.wiki­pedia.org/wiki/Win­dows_Metafile
  15. Wikipedia EN: Enhanced Metafile,
    http://en.wiki­pedia.org/wiki/En­hanced_Metafi­le
  16. Wikipedia EN: Windows Media Format,
    http://en.wiki­pedia.org/wiki/Win­dows_Media_For­mat
  17. Wikipedia EN: Unicode,
    http://en.wiki­pedia.org/wiki/U­nicode
  18. Wikipedia EN: UTF-16/UCS-2,
    http://en.wiki­pedia.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).

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.