Obsah
1. Práce s grafickým metaformátem EMF
2. Vytvoření jednoduchého souboru EMF pomocí funkcí GDI
3. Analýza binárního obsahu souboru EMF
4. Vytvoření souboru EMF obsahujícího metainformace o programu i vytvořeném výkrese
5. Vytvoření souboru EMF s více GDI objekty
6. Program pro čtení záznamů ze souborů typu EMF
7. Záznamy získané ze tří demonstračních souborů
8. Odkazy na další informační zdroje
9. Obsah následující části tohoto seriálu
1. Práce s grafickým metaformátem EMF
Minule jsme si řekli, že grafický metaformát EMF (Enhanced Windows Metafile) je primárně určen pro ukládání vektorových i rastrových objektů v třicetidvoubitových operačních systémech Microsoft Windows, přičemž už teď je nutné říci, že Windows 95 a Windows 98 soubory EMF vytváří poněkud odlišným způsobem než Windows NT a jejich následovníci. V těchto operačních systémech je EMF podporováno na úrovni GDI (Graphics Device Interface) a vytváření těchto souborů se prakticky neliší od vykreslování do okna nebo od výstupu na tiskárnu. Nás však bude zajímat i způsob uložení grafických informací v těchto souborech, protože EMF je samozřejmě možné zpracovávat i na dalších platformách (zajímavé je, že mnoho programů určených pro Linux či podobné systémy podporuje formát WMF, ale EMF už nikoli, takže zde stále existuje prostor pro vylepšování).
2. Vytvoření jednoduchého souboru EMF pomocí funkcí GDI
Nejprve se pokusme vytvořit několik souborů typu EMF. Následující příklad, který byl otestován s překladačem GCC 3.2 běžícím na Microsoft Windows 98 SE (v tomto případě je typ OS důležitý), vytvoří soubor o velikosti 108 bytů popř. 120 bytů na operačních systémech založených na Windows NT. Rozdíl ve velikostech souborů je způsobem rozsáhlejší hlavičkou. Vidíme, že při vytváření EMF si vystačíme s pouhými třemi funkcemi GDI, konkrétně CreateEnhMetaFile(), CloseEnhMetaFile() a DeleteEnhMetaFile(). Poslední zmíněná funkce nemaže soubor na disku, pouze jeho obraz v operační paměti. Narozdíl od většiny příkladů, které najdete v MSDN, se u EMF souboru nastavuje velikost na rozměry 10×10 cm (délkovou jednotkou je v tomto případě 0,01mm). O tom, že výkres má skutečně tuto velikost, se můžeme přesvědčit například po jeho importu do OpenOffice.org (viz první a druhý obrázek). Volba velikosti výkresu je mnohdy důležitá, zejména při tisku.
// ---------------------------------------------------------
// Demonstrační příklad číslo 1
// Vytvoření prázdného výkresu uloženého ve formátu EMF
// (Enhanced Windows MetaFile)
// Při překladu pomocí GCC je nutné použít volbu -lgdi32
// ---------------------------------------------------------
#include <windows.h>
#include <stdio.h>
int main(void)
{
// obdélník, pomocí kterého se nastavuje
// rozměr plátna (grafické plochy) výkresu
RECT rect;
// kontext zařízení, do kterého se bude kreslit
HDC dc;
// handle metasouboru
HENHMETAFILE henh;
// nastavení rozměrů kreslicího plátna
// jednotkou je 0,01 mm
rect.left=0;
rect.top=0;
rect.right=10000; // 10000 x 0.01 mm=10 cm
rect.bottom=10000;
// vytvoření výkresu navázaného na soubor
dc=CreateEnhMetaFile(NULL, "emf1.emf", &rect, NULL);
// v případě neúspěchu se vrátí hodnota NULL
if (!dc) {
puts("Nepodařilo se vytvořit výkres!");
return -1;
}
// uzavření výkresu a
// zápis obsahu souboru na disk
// s testem na úspěšnost
if (!(henh=CloseEnhMetaFile(dc))) {
puts("Nepodařilo se uzavřít výkres!\n"
"(pravděpodobně nedošlo k zápisu na disk)");
return -1;
}
if (!DeleteEnhMetaFile(henh)) {
puts("Nepodařilo se smazat informace o metasouboru!\n");
return -1;
}
// neuvěřitelné - došli jsme až do tohoto místa
puts("Zápis výkresu na disk OK");
// finito
return 0;
}
// ---------------------------------------------------------
Obrázek 1: EMF soubor vložený do OpenOffice.org
3. Analýza binárního obsahu souboru EMF
Vytvořený soubor typu EMF obsahuje pouze dva záznamy. Na offsetu 0, tj. na začátku souboru, se nachází hlavička o délce 88 bytů (v případě jeho vytvoření na Windows 98). Po hlavičce už následuje pouze ukončující blok o délce 20 bytů. Tento blok bývá buď zcela prázdný nebo může obsahovat barvovou paletu. Formát hlavičky odpovídá informacím uvedeným v předchozí části tohoto seriálu. Paleta je uložena s jednoduchým informačním blokem, který obsahuje počet barev (4 byty), offset od začátku barvové palety (4 byty), samotnou barvovou paletu a nakonec offset na začátek celého záznamu (4 byty). Náš soubor žádnou paletu neobsahuje, proto má ukončující záznam délku 20 bytů (4 byty pro číslo funkce, 4 byty pro délku záznamu, 4 byty pro počet barev, 4 byty pro offset barev a nakonec 4 byty pro uložení offsetu).
Obrázek 2: Velikost výkresu zjištěná OpenOffice.org
4. Vytvoření souboru EMF obsahujícího metainformace o programu i vytvořeném výkrese
Ve druhém demonstračním příkladu jsou ukázány dva nové postupy. Do EMF souboru je uložen řetězec, který obsahuje název aplikace i popis výkresu. Nejedná se o klasický céčkový řetězec, protože mezi názvem aplikace a popisem výkresu je vložen znak NUL a samotný řetězec je ukončen dvojicí znaků NUL (pozor tedy při použití funkcí ze standardní céčkové knihovny, ty budou pracovat korektně pouze pro první část řetězce). Dále je ukázán způsob výpočtu rozměrů výkresu v logických jednotkách přes obecnou funkci GetDeviceCaps(). Pro zadané rozměry 10×10 cm a rozlišení 96 DPI by měl rozsah logických jednotek být [0, 0]×[307, 307]. Ostatně tuto informaci je možné získat z panelu s vlastnostmi souboru (viz třetí obrázek). Je zajímavé, že se v tomto panelu nezobrazují popisné řetězce, i když jsou evidentně v souboru uloženy. Samotné vykreslení objektu přes MoveToEx() a LineTo() používá právě tyto vypočtené rozměry.
Obrázek 3: Vlastnosti vytvořeného souboru typu EMF// ---------------------------------------------------------
// Demonstrační příklad číslo 2
// Vytvoření výkresu uloženého ve formátu EMF
// (Enhanced Windows MetaFile)
// Výkres obsahuje jednu úsečku a popis
// Při překladu pomocí GCC je nutné použít volbu -lgdi32
// ---------------------------------------------------------
#include <windows.h>
#include <stdio.h>
// popisný řetězec, mezi názvem aplikace a popisem výkresu
// se musí nacházet jeden znak \0, na konci pak dvojice
// znaků \0\0
char *popis="SuperEdit v 0.01\0demonstrační výkres 2\0\0";
int main(void)
{
// obdélník, pomocí kterého se nastavuje
// rozměr plátna (grafické plochy) výkresu
RECT rect;
// kontext zařízení, do kterého se bude kreslit
HDC dc;
// handle metasouboru
HENHMETAFILE henh;
// parametry kontextu zařízení
int horzsize, vertsize, horzres, vertres;
// maximální hodnoty souřadnic v kreslicím plátně
float maxx, maxy;
// nastavení rozměrů kreslicího plátna
// jednotkou je 0,01 mm
rect.left=0;
rect.top=0;
rect.right=10000; // 10000 x 0.01 mm=10 cm
rect.bottom=10000;
// vytvoření výkresu navázaného na soubor
// v případě neúspěchu se vrátí hodnota NULL
if (!(dc=CreateEnhMetaFile(NULL, "emf2.emf", &rect, popis))) {
puts("Nepodařilo se vytvořit výkres!");
return -1;
}
// zjistit a vypsat informace o kontextu zařízení
printf("Horizontální velikost: %d\n", horzsize=GetDeviceCaps(dc, HORZSIZE));
printf("Vertikální velikost: %d\n", vertsize=GetDeviceCaps(dc, VERTSIZE));
printf("Horizontální rozlišení: %d\n", horzres=GetDeviceCaps(dc, HORZRES));
printf("Vertikální rozlišení: %d\n", vertres=GetDeviceCaps(dc, VERTRES));
printf("Maximální x-ová souřadnice: %d\n", (int)(maxx=100.0*horzres/horzsize));
printf("Maximální y-ová souřadnice: %d\n", (int)(maxy=100.0*vertres/vertsize));
// vykreslení úhlopříčné úsečky
if (!MoveToEx(dc, 0, 0, NULL)) {
puts("Chyba při vykreslování!");
return -1;
}
if (!LineTo(dc, maxx, maxy)) {
puts("Chyba při vykreslování!");
return -1;
}
// uzavření výkresu a
// zápis obsahu souboru na disk
// s testem na úspěšnost
if (!(henh=CloseEnhMetaFile(dc))) {
puts("Nepodařilo se uzavřít výkres!\n"
"(pravděpodobně nedošlo k zápisu na disk)");
return -1;
}
if (!DeleteEnhMetaFile(henh)) {
puts("Nepodařilo se smazat informace o metasouboru!\n");
return -1;
}
// neuvěřitelné - došli jsme až do tohoto místa
puts("Zápis výkresu na disk OK");
// finito
return 0;
}
// ---------------------------------------------------------
5. Vytvoření souboru EMF s více GDI objekty
Třetí příklad slouží pro vytvoření poněkud složitějšího obrázku, který obsahuje dvě úsečky, vyplněný objekt (konkrétně kružnici) a také jakousi obdobu bitmapy o rozměrech 64×64 jednotek. Můžete se sami přesvědčit, že se ve skutečnosti o bitmapu nejedná, protože pixely jsou zde chápány jako bezrozměrné body (resp. objekty, které se vždy zobrazí v jednom pixelu), což při zvětšení obrázku vede k rozpadu zdánlivé bitmapy na navzájem nespojené body, mezi nimiž prosvítá pozadí. Za zmínku stojí také fakt, že pokud by se pro elipsu explicitně nezvolil nový štětec (brush), kterým se vykresluje vnitřek objektu, byla by ve většině prohlížečů elipsa zobrazena s bílým vnitřkem, zatímco OpenOffice.org při importu zobrazí elipsu vyplněnou černě. Už jsem narazil na několik obrázků uložených v EMF, které nebylo možné z tohoto důvodu korektně zpracovat.
Obrázek 4: Vytvořený EMF soubor po importu do OpenOffice.org// ---------------------------------------------------------
// Demonstrační příklad číslo 3
// Vytvoření výkresu uloženého ve formátu EMF
// (Enhanced Windows MetaFile)
// Výkres obsahuje několik GDI objektů a popis
// Při překladu pomocí GCC je nutné použít volbu -lgdi32
// ---------------------------------------------------------
#include <windows.h>
#include <stdio.h>
// popisný řetězec, mezi názvem aplikace a popisem výkresu
// se musí nacházet jeden znak \0, na konci pak dvojice
// znaků \0\0
char *popis="SuperEdit v 0.01\0demonstrační výkres 3\0\0";
int main(void)
{
int ok=1;
// obdélník, pomocí kterého se nastavuje
// rozměr plátna (grafické plochy) výkresu
RECT rect;
// kontext zařízení, do kterého se bude kreslit
HDC dc;
// handle metasouboru
HENHMETAFILE henh;
// parametry kontextu zařízení
int horzsize, vertsize, horzres, vertres;
// maximální hodnoty souřadnic v kreslicím plátně
float maxx, maxy;
// nastavení rozměrů kreslicího plátna
// jednotkou je 0,01 mm
rect.left=0;
rect.top=0;
rect.right=10000; // 10000 x 0.01 mm=10 cm
rect.bottom=10000;
// vytvoření výkresu navázaného na soubor
// v případě neúspěchu se vrátí hodnota NULL
if (!(dc=CreateEnhMetaFile(NULL, "emf3.emf", &rect, popis))) {
puts("Nepodařilo se vytvořit výkres!");
return -1;
}
// zjistit a vypsat informace o kontextu zařízení
printf("Horizontální velikost: %d\n", horzsize=GetDeviceCaps(dc, HORZSIZE));
printf("Vertikální velikost: %d\n", vertsize=GetDeviceCaps(dc, VERTSIZE));
printf("Horizontální rozlišení: %d\n", horzres=GetDeviceCaps(dc, HORZRES));
printf("Vertikální rozlišení: %d\n", vertres=GetDeviceCaps(dc, VERTRES));
printf("Maximální x-ová souřadnice: %d\n", (int)(maxx=100.0*horzres/horzsize));
printf("Vertikální rozlišení: %d\n", (int)(maxy=100.0*vertres/vertsize));
// vykreslení několika GDI objektů
{
HPEN hpen=SelectObject(dc, CreatePen(PS_SOLID, 1, 0x000000c0));
ok&=MoveToEx(dc, 0, 0, NULL);
ok&=LineTo(dc, maxx, maxy);
ok&=MoveToEx(dc, maxx, 0, NULL);
ok&=LineTo(dc, 0, maxy);
DeleteObject(SelectObject(dc, hpen));
}
// změna kreslicího pera a štětce a vytvoření kružnice
{
HPEN hpen=SelectObject(dc, CreatePen(PS_SOLID, 3, 0x00c00000));
HBRUSH hbrush=SelectObject(dc, CreateSolidBrush(0x00e0ffff));
ok&=Ellipse(dc, 10, 10, maxx-10, maxy-10);
DeleteObject(SelectObject(dc, hbrush));
DeleteObject(SelectObject(dc, hpen));
}
// obarvení jednotlivých pixelů: práce na velmi nízké úrovni
{
int x, y;
for (x=0; x<64; x++)
for (y=0; y<64; y++)
SetPixel(dc, x, y, (x<<2)+((y<<2)<<16));
}
if (!ok) {
puts("Chyba při vykreslování!");
return -1;
}
// uzavření výkresu a
// zápis obsahu souboru na disk
// s testem na úspěšnost
if (!(henh=CloseEnhMetaFile(dc))) {
puts("Nepodařilo se uzavřít výkres!\n"
"(pravděpodobně nedošlo k zápisu na disk)");
return -1;
}
if (!DeleteEnhMetaFile(henh)) {
puts("Nepodařilo se smazat informace o metasouboru!\n");
return -1;
}
// neuvěřitelné - došli jsme až do tohoto místa
puts("Zápis výkresu na disk OK");
// finito
return 0;
}
// ---------------------------------------------------------
Obrázek 5: Vytvořený EMF soubor po zobrazení v prohlížeči obrázků
6. Program pro čtení záznamů ze souborů typu EMF
Dnešní poslední demonstrační příklad je možné použít na všech platformách s procesorem zpracovávajícím data v pořadí bytů little endian, což je dnes i Mac). V souboru typu EMF jsou nalezeny a vypsány hlavičky všech záznamů, včetně jejich umístění v souboru a názvu (pokud je ovšem název nalezen v tabulce). Je zajímavé sledovat, jaké informace ve skutečnosti některé soubory typu EMF obsahují, dokonce se dá přibližně zjistit, v jakém programu a operačním systému byly vytvořeny (o způsobu identifikace grafických souborů by mohl vyjít celý článek, jde o zajímavé téma i z hlediska např. ochrany informací).
// --------------------------------------------------------------------
// Demonstracni program urceny pro nacteni vsech zaznamu ze souboru
// typu EMF (Enhenced Windows MetaFile)
// Autor: Pavel Tisnovsky
// --------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#define HR "-------------------------------------------"
typedef unsigned short Word;
typedef unsigned int Dword;
// struktura hlavicky jednoho zaznamu ve EMF
typedef struct {
Dword Function;
Dword Size;
} EmfRecord;
// struktura popisujici prevodni tabulku nazev GDI funkce <-> cislo GDI funkce
typedef struct {
char *name;
Word function;
} EmfFunction;
// staticke naplneni prevodni tabulky
EmfFunction emfFunctions[]={
{"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 },
{"* nenalezeno *", 0x0000},
};
// --------------------------------------------------------------------
// prevod cisla GDI funkce na jeji nazev
// --------------------------------------------------------------------
char * getFunctionName(int function)
{
int j;
for (j=0; emfFunctions[j].function!=function && emfFunctions[j].function!=0x0000; j++)
;
return emfFunctions[j].name;
}
// --------------------------------------------------------------------
// funkce, ktera nacte a zobrazi informace z hlavicky a popr. i
// rozsirene hlavicky souboru typu WMF
// --------------------------------------------------------------------
int EmfRecordsInfo(char *path)
{
#define freadWord(fin) (fgetc((fin)) | fgetc((fin))<<8)
#define freadDword(fin) (fgetc((fin)) | fgetc((fin))<<8 | fgetc((fin))<<16 | fgetc((fin))<<24)
EmfRecord record;
int cnt=0;
FILE *fin;
// soubor nejprve otevreme
if ((fin=fopen(path, "rb"))==NULL) {
printf("Soubor %s nelze otevrit pro cteni!\n", path);
return 0;
}
// cteni vsech zbyvajicich dat v souborech typu WMF
while (!feof(fin)) {
record.Function=freadDword(fin);
record.Size=freadDword(fin);
if (feof(fin)) break;
printf("%5d\t%4d\t%5d\t%04x\t\t%s\n", cnt, (int)ftell(fin)-8, record.Size, record.Function, getFunctionName(record.Function));
cnt++;
// preskocit parametry
// 6 je delka hlavicky zaznamu
fseek(fin, record.Size-8, SEEK_CUR);
}
fclose(fin);
return 1;
}
// --------------------------------------------------------------------
// hlavni funkce, ve ktere se pokusime nacist a zobrazit zaznamy
// ulozene v souborech typu EMF
// --------------------------------------------------------------------
int main(int argc, char *argv[])
{
if (argc!=2) {
printf("Pouziti: emf_records soubor.emf\n");
return 0;
}
EmfRecordsInfo(argv[1]);
return 0;
}
// --------------------------------------------------------------------
// finito
// --------------------------------------------------------------------
7. Záznamy získané ze tří demonstračních souborů
Následuje opis výstupu programu uvedeného v předchozí kapitole, pokud byl spuštěn na tři obrázky typu EMF vytvořené pomocí dnešních prvních třech demonstračních příkladů. Všimněte si zejména posledního výpisu, ze kterého je zřejmé, že prakticky všechny operace GDI jsou v souboru uloženy, včetně výběru objektu (pera, štětce) a jeho smazání.
První demonstrační příklad (původní délka 108 bytů):
řádek offset délka číslo GDI funkce jméno GDI funkce
0 0 88 0001 EMR_HEADER
1 88 20 000e EMR_EOF
Druhý demonstrační příklad (původní délka 220 bytů):
řádek offset délka číslo GDI funkce jméno GDI funkce
0 0 168 0001 EMR_HEADER
1 168 16 001b EMR_MOVETOEX
2 184 16 0036 EMR_LINETO
3 200 20 000e EMR_EOF
Třetí demonstrační příklad (původní délka 82384 bytů):
řádek offset délka číslo GDI funkce jméno GDI funkce
0 0 168 0001 EMR_HEADER
1 168 16 001b EMR_MOVETOEX
2 184 28 0026 EMR_CREATEPEN
3 212 12 0025 EMR_SELECTOBJECT
4 224 16 0036 EMR_LINETO
5 240 16 001b EMR_MOVETOEX
6 256 16 0036 EMR_LINETO
7 272 12 0025 EMR_SELECTOBJECT
8 284 12 0028 EMR_DELETEOBJECT
9 296 28 0026 EMR_CREATEPEN
10 324 12 0025 EMR_SELECTOBJECT
11 336 24 0027 EMR_CREATEBRUSHINDIRECT
12 360 12 0025 EMR_SELECTOBJECT
13 372 24 002a EMR_ELLIPSE
14 396 12 0025 EMR_SELECTOBJECT
15 408 12 0028 EMR_DELETEOBJECT
16 420 12 0025 EMR_SELECTOBJECT
17 432 12 0028 EMR_DELETEOBJECT
18 444 20 000f EMR_SETPIXELV
... 4094 radku zaznamu stejneho typu (s jinym obsahem) ...
4113 82344 20 000f EMR_SETPIXELV
4114 82364 20 000e EMR_EOF
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ších několika dílech seriálu o grafických formátech se budeme věnovat především formátům určeným pro zápis trojrozměrných scén. Začneme velmi jednoduchými formáty typu RAW a přes VRML a VRML2 se dostaneme i k formátům binárním; například ke stále populárnímu formátu 3D Studia.