Hlavní navigace

Práce s grafickým metaformátem EMF

Pavel Tišnovský 1. 11. 2007

V dnešní části seriálu o grafických formátech a metaformátech si na několika příkladech napsaných v jazyce C ukážeme, jak je možné pracovat s metasoubory typu EMF (Enhanced Windows Metafile). Některé programy pro Linux podporují formát WMF, ale EMF už ne, takže je zde stále prostor pro vylepšování.

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řicetidvou­bitový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ě CreateEnhMeta­File(), CloseEnhMetaFi­le() a DeleteEnhMeta­File(). 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;
}

// --------------------------------------------------------- 

gfx6201
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).

gfx6202
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.

gfx6203
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.

gfx6204
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;
}

// --------------------------------------------------------- 

gfx6205
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

  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ší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.

Anketa

Myslíte si, že má smysl, aby Linuxové aplikace podporovaly formát WMF či EMF?

V anketě nejsou žádné odpovědi!
Našli jste v článku chybu?
Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Podnikatel.cz: Udávání kvůli EET začalo

Udávání kvůli EET začalo

Vitalia.cz: „Připluly“ z Německa a možná obsahují jed

„Připluly“ z Německa a možná obsahují jed

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

Root.cz: Telegram spustil anonymní blog Telegraph

Telegram spustil anonymní blog Telegraph

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

Podnikatel.cz: Zavře krám u #EET Malá pokladna a Teeta?

Zavře krám u #EET Malá pokladna a Teeta?

120na80.cz: Co všechno ovlivňuje ženskou plodnost?

Co všechno ovlivňuje ženskou plodnost?

120na80.cz: Jak oddálit Alzheimera?

Jak oddálit Alzheimera?

Vitalia.cz: Znáte „černý detox“? Ani to nezkoušejte

Znáte „černý detox“? Ani to nezkoušejte

Lupa.cz: Insolvenční řízení kvůli cookies? Vítejte v ČR

Insolvenční řízení kvůli cookies? Vítejte v ČR

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

Měšec.cz: mBank cenzuruje, zrušila mFórum

mBank cenzuruje, zrušila mFórum

DigiZone.cz: ČRa DVB-T2 ověřeno: Hisense a Sencor

ČRa DVB-T2 ověřeno: Hisense a Sencor

Vitalia.cz: 9 největších mýtů o mase

9 největších mýtů o mase

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

Vitalia.cz: I církev dnes vyrábí potraviny

I církev dnes vyrábí potraviny

Podnikatel.cz: 1. den EET? Problémy s pokladnami

1. den EET? Problémy s pokladnami

Vitalia.cz: Spor o mortadelu: podle Lidlu falšovaná nebyla

Spor o mortadelu: podle Lidlu falšovaná nebyla