Hlavní navigace

Načítání dat z grafických souborů WMF

Pavel Tišnovský 18. 10. 2007

V dalším článku si ukážeme, jak načítat data - informace o uloženém obrázku z metaformátu WMF. Při práci v operačním systému MS Windows se o načítání WMF souborů nemusíme starat, protože stačí použít funkci z WinAPI, ovšem na jiných systémech je nutné data ve WMF souborech vhodně analyzovat a zpracovat.

Obsah

1. Rozbor obsahu jednoduchého souboru typu WMF
2. Program určený pro analýzu hlaviček souborů typu WMF
3. Analyzovaná hlavička demonstračního souboru typu WMF
4. Program určený pro výpis všech příkazů GDI v souborech WMF
5. Analyzované názvy všech GDI příkazů demonstračního souboru typu WMF
6. Interpretace jednotlivých příkazů GDI
7. Literatura a odkazy na internetu
8. Obsah dalšího pokračování tohoto seriálu

1. Rozbor obsahu jednoduchého souboru typu WMF

V předchozí části tohoto seriálu jsme si zevrubně popsali jak základní, tak i rozšiřující hlavičku používanou v grafických souborech typu WMF. Základní hlavičku obsahují všechny soubory, rozšiřující hlavička, která může (i když je to dnes málo pravděpodobné) způsobit problémy při interpretaci těchto souborů staršími aplikacemi, je přítomna pouze tehdy, když je do WMF vložena programově, protože funkce WinAPI, tj. aplikační programové rozhraní operačního systému Microsoft Windows, vytváří pouze soubory WMF se základní hlavičkou. Minule jsme si také řekli, jakým způsobem jsou uloženy jednotlivé příkazy GDI (GDI je grafický subsystém Microsoft Windows), které vlastně představují zápis barvových, geometrických i rastrových informací o uloženém obrázku. Dnes si na dvojici programů ukážeme, jakým způsobem je možné načítat údaje z obou hlaviček i z jednotlivých GDI příkazů. Demonstrační soubor typu WMF, který je použitý v dalším textu, je možné získat pod tímto odkazem. Další, většinou velmi jednoduché, grafické soubory uložené v tomto formátu si stáhněte zde.

2. Program určený pro analýzu hlaviček souborů typu WMF

Dnešní první demonstrační program slouží pro načtení základní i rozšiřující hlavičky souborů typu WMF. Základní hlavička je přečtena vždy, rozšiřující hlavička pouze v případě, že je na základě obsahu prvních čtyř bytů souborů detekována. Program pracuje velmi jednoduše: nejdříve se načte první čtveřice bytů, z jejíhož obsahu se pozná, jestli soubor obsahuje pouze základní hlavičku nebo i rozšiřující hlavičku. Pokud tato čtveřice má (po její interpretaci jako celého čísla uloženého ve formátu little-endian) hodnotu 0×9ac6cdd7, přečte se i rozšiřující hlavička. Posléze se program přesune opět na začátek souboru a načte rozšířenou hlavičku (pokud je přítomna) a základní hlavičku. Následně je vhodným způsobem inerpretován a vypsán obsah obou hlaviček (jsou provedeny délky uložené v twipsech na „lidské“ jednotky, proveden převod z dvoubytových slov na byty apod.). Předpokladem pro úspěšný překlad a běh programu je platforma, na které má datový typ int bitovou délku minimálně 32 bitů a short int bitovou délku minimálně 16 bitů. Také na platformách s pořadím bytů big-endian bude zapotřebí upravit funkce pro načtení slov a dvojslov.

// --------------------------------------------------------------------
// Demonstracni program urceny pro nacteni hlavicky a popr. i rozsirene
// hlavicky souboru typu WMF (Windows MetaFile)
// Autor: Pavel Tisnovsky
// --------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>

#define HR "-------------------------------------------"

typedef unsigned short Word;
typedef unsigned int Dword;

typedef struct {
   Word     FileTypeStorage;
   Word     HeaderSize;
   Word     Version;
   Dword    FileSize;
   Word     NumOfObjects;
   Dword    MaxRecordSize;
   Word     ParametersNumb;
} WmfHeader;

typedef struct {
   Dword    Password;
   Word     Handle;
   short    LeftCorn;
   short    TopCorn;
   short    RightCorn;
   short    BottomCorn;
   Word     Twip_p_Inch;
   Dword    Reserved;
   Word     Checksum;
} WmfExtra;



// --------------------------------------------------------------------
// prevod delkovych jednotek zadanych v "twipech" na palce
// --------------------------------------------------------------------
float twip2inch(short twip, Word Twip_p_Inch)
{
    return (float)twip/(float)Twip_p_Inch;
}



// --------------------------------------------------------------------
// prevod delkovych jednotek zadanych v "twipech" na milimetry
// --------------------------------------------------------------------
float twip2mm(short twip, Word Twip_p_Inch)
{
    return 25.4*(float)twip/(float)Twip_p_Inch;
}



// --------------------------------------------------------------------
// pomocna funkce pro vypis hodnoty jednoho z okraju obaloveho obdelniku
// --------------------------------------------------------------------
void showCorner(const char *msg, short twip, Word twip_p_Inch)
{
    printf("%s     %+6d twip(s) = %6.3f palcu = %6.2f mm\n",
        msg, twip, twip2inch(twip, twip_p_Inch), twip2mm(twip, twip_p_Inch)
    );
}



// --------------------------------------------------------------------
// funkce, ktera nacte a zobrazi informace z hlavicky a popr. i
// rozsirene hlavicky souboru typu WMF
// --------------------------------------------------------------------
int wmfHeaderInfo(char *path)
{
    // lokalni makro pro nacteni jednoho primitivniho datoveho typu
    // ze souboru s kontrolou, zda se nacteni opravdu podarilo
    // parametry: misto, kam se ma prectena informace ulozit
    //            delka typu
    //            vstupni soubor
    #define READ_ITEM(item, type, fin) \
        if ((fread(&item, sizeof(type), 1, fin))!=1) {\
            printf("Chyba pri cteni souboru!\n");\
            return 0;\
        }
    WmfHeader header;
    WmfExtra  extraHeader;
    Dword     firstBytes;
    FILE *fin;

    // soubor nejprve otevreme
    if ((fin=fopen(path, "rb"))==NULL) {
        printf("Soubor %s nelze otevrit pro cteni!\n", path);
        return 0;
    }

    // potom nacteme prvnich osm bytu, podle kterych je mozne
    // rozpoznat, zda je pritomna rozsirena hlavicka
    if ((fread(&firstBytes, 8, 1, fin))!=1) {
        printf("Chyba pri cteni ze souboru %s!\n", path);
        return 0;
    }

    // at je ci neni rozsirena hlavicka detekovana, musime se
    // presunout zpet na zacatek souboru
    fseek(fin, 0L, SEEK_SET);
    if (firstBytes==0x9ac6cdd7) {
        puts("Je pritomna rozsirujici hlavicka s obsahem:");
        puts(HR);

        // strukturu, ve ktere se stridaji polozky Word a Dword, nelze obecne
        // nacist jednim fread-em kvuli zarovnani na 32bitovych a 64bitovych
        // prekladacich
        READ_ITEM(extraHeader.Password,    Dword, fin)
        READ_ITEM(extraHeader.Handle,      Word,  fin)
        READ_ITEM(extraHeader.LeftCorn,    short, fin)
        READ_ITEM(extraHeader.TopCorn,     short, fin)
        READ_ITEM(extraHeader.RightCorn,   short, fin)
        READ_ITEM(extraHeader.BottomCorn,  short, fin)
        READ_ITEM(extraHeader.Twip_p_Inch, Word,  fin)
        READ_ITEM(extraHeader.Reserved,    Dword, fin)
        READ_ITEM(extraHeader.Checksum,    Word,  fin)

        // vypis nactenych informaci
        printf("Password:           %08x\n", extraHeader.Password);
        printf("Cislo souboru:      %08d\n", extraHeader.Handle);
        showCorner("Levy okraj:    ", extraHeader.LeftCorn,   extraHeader.Twip_p_Inch);
        showCorner("Horni okraj:   ", extraHeader.TopCorn,    extraHeader.Twip_p_Inch);
        showCorner("Pravy okraj:   ", extraHeader.RightCorn,  extraHeader.Twip_p_Inch);
        showCorner("Spodni okraj:  ", extraHeader.BottomCorn, extraHeader.Twip_p_Inch);
        printf("Twipu na palec:     %d\n",   extraHeader.Twip_p_Inch);
        printf("Rezervovano:        %08x\n", extraHeader.Reserved);
        printf("Kontrolni soucet:   %08x\n", extraHeader.Checksum);
        putchar('\n');
    }

    // nacteni standardni hlavicky formatu WMF
    // strukturu, ve ktere se stridaji polozky Word a Dword, nelze obecne
    // nacist jednim fread-em kvuli zarovnani na 32bitovych a 64bitovych prekladacich
    READ_ITEM(header.FileTypeStorage, Word,  fin);
    READ_ITEM(header.HeaderSize,      Word,  fin);
    READ_ITEM(header.Version,         Word,  fin);
    READ_ITEM(header.FileSize,        Dword, fin);
    READ_ITEM(header.NumOfObjects,    Word,  fin);
    READ_ITEM(header.MaxRecordSize,   Dword, fin);
    READ_ITEM(header.ParametersNumb,  Word,  fin);

    // vypis informaci nactenych ze standardni hlavicky
    printf("Obsah standardni hlavicky:\n");
    puts(HR);
    printf("Ulozeni souboru:    %s\n", header.FileTypeStorage==1 ? "na disku":"v RAM");
    printf("Velikost hlavicky:  %d slov = %d bytu\n", header.HeaderSize, header.HeaderSize<<1);
    printf("Verze OS:           %x\n", header.Version);
    printf("Velikost souboru:   %d slov = %d bytu\n", (int)header.FileSize, (int)header.FileSize<<1);
    printf("Pocet objektu:      %d\n", header.NumOfObjects);
    printf("Max. delka zaznamu: %d slov = %d bytu\n", header.FileSize, header.FileSize<<1);
    printf("Rezervovano:        %x\n", (int)header.ParametersNumb);
    fclose(fin);

    // makro READ_ITEM je celkem nebezpecne a nikdo jiny by ho nemel pouzit
    // -> zajistit jeho "lokalnost"
    #undef READ_ITEM
    return 1;
}



// --------------------------------------------------------------------
// hlavni funkce, ve ktere se pokusime nacist a zobrazit hlavicku
// souboru typu WMF
// --------------------------------------------------------------------
int main(int argc, char *argv[])
{
    if (argc!=2) {
        printf("Pouziti: wmf_head soubor.wmf\n");
        return 0;
    }
    wmfHeaderInfo(argv[1]);
    return 0;
}



// --------------------------------------------------------------------
// finito
// -------------------------------------------------------------------- 

3. Analyzovaná hlavička demonstračního souboru typu WMF

V první kapitole je uveden odkaz na demonstrační soubor typu WMF, který byl vytvořen v aplikaci OpenOffice.org. Po překladu prvního programu a jeho spuštění s parametrem wmf.wmf (což je onen WMF soubor z OpenOffice.org) je zjištěno, že tento WMF soubor obsahuje základní i rozšiřující hlavičku s následujícími údaji (všimněte si zejména rozměrů kreslicí plochy, kde pravděpodobně při exportu došlo k nepřesné interpretaci šířky, která byla nastavena přesně na 20 cm):

Je pritomna rozsirujici hlavicka s obsahem:
-------------------------------------------
Password:           9ac6cdd7
Cislo souboru:      00000000
Levy okraj:             +0 twip(s) =  0.000 palcu =   0.00 mm
Horni okraj:            +0 twip(s) =  0.000 palcu =   0.00 mm
Pravy okraj:        +19973 twip(s) =  7.863 palcu = 199.73 mm
Spodni okraj:       +28333 twip(s) = 11.155 palcu = 283.33 mm
Twipu na palec:     2540
Rezervovano:        00000000
Kontrolni soucet:   00007e55

Obsah standardni hlavicky:
-------------------------------------------
Ulozeni souboru:    na disku
Velikost hlavicky:  9 slov = 18 bytu
Verze OS:           300
Velikost souboru:   870 slov = 1740 bytu
Pocet objektu:      16
Max. delka zaznamu: 870 slov = 1740 bytu
Rezervovano:        0 

4. Program určený pro výpis všech příkazů GDI v souborech WMF

Dnešní druhý program je poněkud složitější než program předchozí, protože se v něm snažíme najít názvy všech funkcí GDI (grafického subsystému Microsoft Windows), které jsou v souboru typu WMF umístěny. Klíčovou část tohoto programu tvoří tabulka wmfFunctions, která obsahuje jak symbolické názvy GDI funkcí s prefixem META, tak i jejich číselný kód. Program nejprve přeskočí základní a popř. i rozšiřující hlavičku souboru a poté ve smyčce načítá hlavičky jednotlivých záznamů. Z nich zjistí, jak délku záznamu (ta je nutná pro přeskočení těla), tak i číslo GDI funkce, kterou se pokusí najít v již zmíněné tabulce wmfFunctions. Může se stát, že nějaká funkce nebude nalezena (trojský kůň?, neúplný hlavičkový soubor wingdi.h dodávaný k MinGW?), potom se vypíše informace „* nenalezeno *“. Posledním záznamem uloženým ve WMF souborech je záznam s číslem GDI funkce 0, a ten není nalezen nikdy (taková funkce neexistuje). I u tohoto programu je předpokladem pro jeho úspěšný překlad a běh platforma, na které má datový typ int bitovou délku minimálně 32 bitů a short int bitovou délku minimálně 16 bitů. Také na platformách s pořadím bytů big-endian bude zapotřebí upravit funkce pro načtení slov a dvojslov.

// --------------------------------------------------------------------
// Demonstracni program urceny pro nacteni vsech zaznamu ze souboru
// typu WMF (Windows MetaFile)
// Autor: Pavel Tisnovsky
// --------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>

#define HR "-------------------------------------------"

typedef unsigned short Word;
typedef unsigned int Dword;

// struktura standardni hlavicky WMF
typedef struct {
   Word     FileTypeStorage;
   Word     HeaderSize;
   Word     Version;
   Dword    FileSize;
   Word     NumOfObjects;
   Dword    MaxRecordSize;
   Word     ParametersNumb;
} WmfHeader;

// struktura rozsirujici hlavicky WMF
typedef struct {
   Dword    Password;
   Word     Handle;
   short    LeftCorn;
   short    TopCorn;
   short    RightCorn;
   short    BottomCorn;
   Word     Twip_p_Inch;
   Dword    Reserved;
   Word     Checksum;
} WmfExtra;

// struktura jednoho zaznamu ve WMF
typedef struct {
   Dword Size;
   Word  Function;
   Word  Parameters[];
} WmfRecord;

// struktura popisujici prevodni tabulku nazev GDI funkce <-> cislo GDI funkce
typedef struct {
    char *name;
    Word function;
} WmfFunction;

// naplneni prevodni tabulky
WmfFunction wmfFunctions[]={
    {"META_SETBKCOLOR",              0x0201},
    {"META_SETBKMODE",               0x0102},
    {"META_SETMAPMODE",              0x0103},
    {"META_SETROP2",                 0x0104},
    {"META_SETRELABS",               0x0105},
    {"META_SETPOLYFILLMODE",         0x0106},
    {"META_SETSTRETCHBLTMODE",       0x0107},
    {"META_SETTEXTCHAREXTRA",        0x0108},
    {"META_SETTEXTCOLOR",            0x0209},
    {"META_SETTEXTJUSTIFICATION",    0x020A},
    {"META_SETWINDOWORG",            0x020B},
    {"META_SETWINDOWEXT",            0x020C},
    {"META_SETVIEWPORTORG",          0x020D},
    {"META_SETVIEWPORTEXT",          0x020E},
    {"META_OFFSETWINDOWORG",         0x020F},
    {"META_SCALEWINDOWEXT",          0x0410},
    {"META_OFFSETVIEWPORTORG",       0x0211},
    {"META_SCALEVIEWPORTEXT",        0x0412},
    {"META_LINETO",                  0x0213},
    {"META_MOVETO",                  0x0214},
    {"META_EXCLUDECLIPRECT",         0x0415},
    {"META_INTERSECTCLIPRECT",       0x0416},
    {"META_ARC",                     0x0817},
    {"META_ELLIPSE",                 0x0418},
    {"META_FLOODFILL",               0x0419},
    {"META_PIE",                     0x081A},
    {"META_RECTANGLE",               0x041B},
    {"META_ROUNDRECT",               0x061C},
    {"META_PATBLT",                  0x061D},
    {"META_SAVEDC",                  0x001E},
    {"META_SETPIXEL",                0x041F},
    {"META_OFFSETCLIPRGN",           0x0220},
    {"META_TEXTOUT",                 0x0521},
    {"META_BITBLT",                  0x0922},
    {"META_STRETCHBLT",              0x0B23},
    {"META_POLYGON",                 0x0324},
    {"META_POLYLINE",                0x0325},
    {"META_ESCAPE",                  0x0626},
    {"META_RESTOREDC",               0x0127},
    {"META_FILLREGION",              0x0228},
    {"META_FRAMEREGION",             0x0429},
    {"META_INVERTREGION",            0x012A},
    {"META_PAINTREGION",             0x012B},
    {"META_SELECTCLIPREGION",        0x012C},
    {"META_SELECTOBJECT",            0x012D},
    {"META_SETTEXTALIGN",            0x012E},
    {"META_CHORD",                   0x0830},
    {"META_SETMAPPERFLAGS",          0x0231},
    {"META_EXTTEXTOUT",              0x0a32},
    {"META_SETDIBTODEV",             0x0d33},
    {"META_SELECTPALETTE",           0x0234},
    {"META_REALIZEPALETTE",          0x0035},
    {"META_ANIMATEPALETTE",          0x0436},
    {"META_SETPALENTRIES",           0x0037},
    {"META_POLYPOLYGON",             0x0538},
    {"META_RESIZEPALETTE",           0x0139},
    {"META_DIBBITBLT",               0x0940},
    {"META_DIBSTRETCHBLT",           0x0b41},
    {"META_DIBCREATEPATTERNBRUSH",   0x0142},
    {"META_STRETCHDIB",              0x0f43},
    {"META_EXTFLOODFILL",            0x0548},
    {"META_SETLAYOUT",               0x0149},
    {"META_DELETEOBJECT",            0x01f0},
    {"META_CREATEPALETTE",           0x00f7},
    {"META_CREATEPATTERNBRUSH",      0x01F9},
    {"META_CREATEPENINDIRECT",       0x02FA},
    {"META_CREATEFONTINDIRECT",      0x02FB},
    {"META_CREATEBRUSHINDIRECT",     0x02FC},
    {"META_CREATEREGION",            0x06FF},
    {"* nenalezeno *",               0x0000},
};



// --------------------------------------------------------------------
// prevod delkovych jednotek zadanych v "twipech" na palce
// --------------------------------------------------------------------
float twip2inch(short twip, Word Twip_p_Inch)
{
    return (float)twip/(float)Twip_p_Inch;
}



// --------------------------------------------------------------------
// prevod delkovych jednotek zadanych v "twipech" na milimetry
// --------------------------------------------------------------------
float twip2mm(short twip, Word Twip_p_Inch)
{
    return 25.4*(float)twip/(float)Twip_p_Inch;
}



// --------------------------------------------------------------------
// pomocna funkce pro vypis hodnoty jednoho z okraju obaloveho obdelniku
// --------------------------------------------------------------------
void showCorner(const char *msg, short twip, Word twip_p_Inch)
{
    printf("%s     %+6d twip(s) = %6.3f palcu = %6.2f mm\n",
        msg, twip, twip2inch(twip, twip_p_Inch), twip2mm(twip, twip_p_Inch)
    );
}



// --------------------------------------------------------------------
// prevod cisla GDI funkce na jeji nazev
// --------------------------------------------------------------------
char * getFunctionName(int function)
{
    int j;
    for (j=0; wmfFunctions[j].function!=function && wmfFunctions[j].function!=0x0000; j++)
        ;
    return wmfFunctions[j].name;
}



// --------------------------------------------------------------------
// funkce, ktera nacte a zobrazi informace z hlavicky a popr. i
// rozsirene hlavicky souboru typu WMF
// --------------------------------------------------------------------
int wmfRecordsInfo(char *path)
{
    // delka standardni hlavicky i rozsirujici hlavicky WMF souboru
    #define HEADER_LENGTH       18
    #define EXT_HEADER_LENGTH   22

    #define freadWord(fin) (fgetc((fin)) | fgetc((fin))<<8)
    #define freadDword(fin) (fgetc((fin)) | fgetc((fin))<<8 | fgetc((fin))<<16 | fgetc((fin))<<24)

    WmfRecord record;
    Dword     firstBytes;
    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;
    }

    // potom nacteme prvnich osm bytu, podle kterych je mozne
    // rozpoznat, zda je pritomna rozsirena hlavicka
    if ((fread(&firstBytes, 8, 1, fin))!=1) {
        printf("Chyba pri cteni ze souboru %s!\n", path);
        return 0;
    }

    // presunout se za souborove hlavicky
    if (firstBytes==0x9ac6cdd7) {
        fseek(fin, EXT_HEADER_LENGTH+HEADER_LENGTH, SEEK_SET);
    }
    else
        fseek(fin, HEADER_LENGTH, SEEK_SET);

    puts(HR);
    puts("Record\toffset\tsize\tfunction#\tfunction name");


    // cteni vsech zbyvajicich dat v souborech typu WMF
    while (!feof(fin)) {
        record.Size=freadDword(fin);
        record.Function=freadWord(fin);
        if (feof(fin)) break;
        printf("%5d\t%4d\t%5d\t%04x\t\t%s\n", cnt, (int)ftell(fin), record.Size<<1, record.Function, getFunctionName(record.Function));
        cnt++;
        // preskocit parametry
        // 6 je delka hlavicky zaznamu
        fseek(fin, record.Size*2-6, SEEK_CUR);
    }
    fclose(fin);
    return 1;
}



// --------------------------------------------------------------------
// hlavni funkce, ve ktere se pokusime nacist a zobrazit hlavicku
// souboru typu WMF
// --------------------------------------------------------------------
int main(int argc, char *argv[])
{
    if (argc!=2) {
        printf("Pouziti: wmf_head soubor.wmf\n");
        return 0;
    }
    wmfRecordsInfo(argv[1]);
    return 0;
}



// --------------------------------------------------------------------
// finito
// -------------------------------------------------------------------- 

5. Analyzované názvy všech GDI příkazů demonstračního souboru typu WMF

Pokud spustíme druhý program popsaný v předchozí kapitole na náš demonstrační WMF soubor vytvořený v OpenOffice.org, získáme sekvenci GDI příkazů vypsanou v odstavci níže. Poslední řádek je ve skutečnosti korektní (i když se vypisuje zpráva, že GDI funkce nebyla nalezena), protože WMF soubory skutečně končí záznamem, u nějž je číslo GDI funkce nastaveno na nulu a záznam neobsahuje žádná data – jeho skutečná délka je tedy rovna šesti bytům, což odpovídá velikosti hlavičky každého záznamu. Dále můžeme z výpisu vidět, že původní dokonalá kružnice je rozdělena na polygon s délkou záznamu 1034 bytů (z tohoto údaje lze jednoduše zjistit počet vrcholů), takže zpětný import souboru nutně povede ke ztrátě geometrické informace o původní kružnici.

-------------------------------------------
Record  offset  size    function#       function name
    0     46       10   020b            META_SETWINDOWORG
    1     56       10   020c            META_SETWINDOWEXT
    2     66        8   0102            META_SETBKMODE
    3     74        8   0104            META_SETROP2
    4     82       16   02fa            META_CREATEPENINDIRECT
    5     98        8   012d            META_SELECTOBJECT
    6    106       14   02fc            META_CREATEBRUSHINDIRECT
    7    120        8   012d            META_SELECTOBJECT
    8    128       56   02fb            META_CREATEFONTINDIRECT
    9    184        8   012d            META_SELECTOBJECT
   10    192        8   012e            META_SETTEXTALIGN
   11    200       10   0209            META_SETTEXTCOLOR
   12    210        8   0107            META_SETSTRETCHBLTMODE
   13    218        6   001e            META_SAVEDC
   14    224       14   0416            META_INTERSECTCLIPRECT
   15    238       16   02fa            META_CREATEPENINDIRECT
   16    254        8   012d            META_SELECTOBJECT
   17    262        8   01f0            META_DELETEOBJECT
   18    270       14   02fc            META_CREATEBRUSHINDIRECT
   19    284        8   012d            META_SELECTOBJECT
   20    292        8   01f0            META_DELETEOBJECT
   21    300     1034   0538            META_POLYPOLYGON
   22   1334       16   02fa            META_CREATEPENINDIRECT
   23   1350        8   012d            META_SELECTOBJECT
   24   1358        8   01f0            META_DELETEOBJECT
   25   1366       14   02fc            META_CREATEBRUSHINDIRECT
   26   1380        8   012d            META_SELECTOBJECT
   27   1388        8   01f0            META_DELETEOBJECT
   28   1396      252   0325            META_POLYLINE
   29   1648       16   0325            META_POLYLINE
   30   1664       16   02fa            META_CREATEPENINDIRECT
   31   1680        8   012d            META_SELECTOBJECT
   32   1688        8   01f0            META_DELETEOBJECT
   33   1696       14   02fc            META_CREATEBRUSHINDIRECT
   34   1710        8   012d            META_SELECTOBJECT
   35   1718        8   01f0            META_DELETEOBJECT
   36   1726       28   0324            META_POLYGON
   37   1754        8   0127            META_RESTOREDC
   38   1762        6   0000            * nenalezeno * 

6. Interpretace jednotlivých příkazů GDI

Nejpracnější část analýzy WMF souborů spočívá v interpretaci jednotlivých GDI příkazů. Každý příkaz má obecně jiný počet a typ parametrů, takže samotné zpracování prakticky nelze univerzálně napsat (většinou se skončí u obřího příkazu switch). V následující tabulce je vypsán způsob interpretace parametrů některých nejčastěji používaných GDI příkazů. Každý parametr je uveden indexem či indexy bytů následujících za hlavičkou záznamu.

Příkaz Popis Parametry
META_SETBKCOLOR barva pozadí RGB – byty 0, 1, 2
META_CREATEBRUS­HINDIRECT volba štětce (výplň) RGB – byty 0, 1, 2
META_CREATEBRUSH volba štětce (výplň) RGB – byty 0, 1, 2
META_CREATEPE­NINDIRECT volba pera (obrys) RGB – byty 0, 1, 2
META_MOVETO přes gfx. kurzoru bez kreslení x – byty 0 a 1, y – byty 2 a 3
META_LINETO přes gfx. kurzoru s kreslením x – byty 0 a 1, y – byty 2 a 3
META_POLYLINE kresba lomené čáry počet čar – byt 0, následují souřadnice x a y (každá má dva byty)
META_POLYGON kresba vyplněného mnohoúhelníku stejné jako v předchozím případě
META_ARC eliptický oblouk x1 – byty 0 a 1, y1 – byty 2 a 3, x2 – byty 4 a 5, y2 – byty 6 a 7, xs – byty 8 a 9, ys – byty 10 a 11, xe – byty 12 a 13, ye – byty 14 a 15

7. Literatura a odkazy na internetu

  1. Charles Petzold: Programming Windows,
    Microsoft Press, 1998
  2. Microsoft: Platform SDK,
    Microsoft, 1995–2007
  3. Svoboda Bronislav a kol.: Grafické formáty,
    Nakladatelství KOOP, České Budějovice
  4. Wikipedia EN: Windows Metafile,
    http://en.wiki­pedia.org/wiki/Win­dows_Metafile
  5. Wikipedia EN: Windows Media Format,
    http://en.wiki­pedia.org/wiki/Win­dows_Media_For­mat
  6. Microsoft Windows Metafile,
    http://wvware­.sourceforge.net/ca­olan/ora-wmf.html
  7. Windows Metafiles, a guide for non-windows programmers,
    http://wvware­.sourceforge.net/ca­olan/index.html
  8. Metafile Reference,
    http://msdn2.mi­crosoft.com/en-us/library/ms534300­.aspx
  9. yFiles 2.3.x graph visualization library and WMF,
    http://www.ywor­ks.com/en/pro­ducts_yfiles_ep_yw­mf.htm
  10. yFiles gallery,
    http://www.ywor­ks.com/en/pro­ducts_yfiles_prac­ticalinfo_galle­ry.htm
  11. libwmf – library for converting WMF files,
    http://wvware­.sourceforge.net/lib­wmf.html

8. Obsah dalšího pokračování tohoto seriálu

V následujícím pokračování seriálu o grafických formátech a metaformátech si popíšeme ideového nástupce formátu WMF, kterým je grafický metaformát EMF. Také budou uvedeny jednoduché demonstrační příklady na načítání informací ze souborů typu EMF.

Našli jste v článku chybu?
Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

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

I církev dnes vyrábí potraviny

Vitalia.cz: Jak koupit Mikuláše a nenaletět

Jak koupit Mikuláše a nenaletět

Vitalia.cz: Žloutenka v Brně: Nakaženo bylo 400 lidí

Žloutenka v Brně: Nakaženo bylo 400 lidí

Lupa.cz: E-shopy: jen sleva už nestačí

E-shopy: jen sleva už nestačí

120na80.cz: Pánové, pečujte o svoje přirození a prostatu

Pánové, pečujte o svoje přirození a prostatu

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

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

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

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

DigiZone.cz: Další dva kanály nabídnou HbbTV

Další dva kanály nabídnou HbbTV

Podnikatel.cz: Platební brány a EET? Stále s otazníkem

Platební brány a EET? Stále s otazníkem

DigiZone.cz: NG natáčí v Praze seriál o Einsteinovi

NG natáčí v Praze seriál o Einsteinovi

Podnikatel.cz: EET zvládneme, budou horší zákony

EET zvládneme, budou horší zákony

Měšec.cz: Finančním poradcům hrozí vracení provizí

Finančním poradcům hrozí vracení provizí

Vitalia.cz: Chtějí si léčit kvasinky. Lék je jen v Německu

Chtějí si léčit kvasinky. Lék je jen v Německu

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

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

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

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

120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

Lupa.cz: UX přestává pro firmy být magie

UX přestává pro firmy být magie

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte

Podnikatel.cz: Na poslední chvíli šokuje vyjímkami v EET

Na poslední chvíli šokuje vyjímkami v EET