Hlavní navigace

Programujeme JPEG: Načtení informací ze souborů typu JFIF/JPEG

1. 2. 2007
Doba čtení: 14 minut

Sdílet

V dnešním článku si ukážeme, jakým způsobem je možné vyčíst základní informace ze souborů typu JFIF/JPEG. Způsob načítání informací bude ukázán na dvou demonstračních aplikacích napsaných v programovacím jazyku C. První aplikace slouží k výpisu všech značek, druhá aplikace již dokáže načíst a vypsat údaje z hlavičky obrázku a tabulek.

Obsah

1. První ukázková aplikace pro výpis všech značek ze souboru typu JFIF/JPEG
2. Testovací obrázky a jejich zpracování první ukázkovou aplikací
3. Druhá ukázková aplikace pro výpis informací ze souborů typu JFIF/JPEG
4. Načtení a výpis základních informací o souboru typu JFIF/JPEG
5. Načtení a výpis obsahu kvantovacích tabulek
6. Načtení a výpis obsahu Huffmanových kódovacích tabulek
7. Výpis informací o testovacích obrázcích
8. Obsah dalšího pokračování tohoto seriálu

1. První ukázková aplikace pro výpis všech značek ze souboru typu JFIF/JPEG

V předchozí části tohoto seriálu jsme si na praktickém příkladu ukázali, jakým způsobem jsou v souborech typu JFIF/JPEG (JPEG Format Interchange File/Joint Photographics Experts Group) uložena všechna data, například kvantovací tabulky, tabulky s Huffmanovými kódovými slovy, komprimované obrazové informace atd. Již víme, že soubory tohoto typu se skládají z takzvaných segmentů (segments), přičemž každý segment má maximální délku rovnu 64kB (216 bytům). Délka segmentu je taktéž uložena v souboru, takže každá aplikace pracující s obrázky JPEG si může již dopředu určit například paměťové nároky pro uložení jednotlivých struktur obrázku. Na začátku každého segmentu se nachází značka (marker).

Značku je velmi snadné v obrazových souborech JFIF/JPEG najít, protože vždy začíná bytem s konstantní hodnotou 0×ff, za nímž následuje byte s hodnotou ležící v rozsahu 0×01–0×fe. Obě mezní hodnoty se zde tedy nemohou v žádném případě vyskytovat, protože by se nejednalo o značku. Mezi jednotlivými segmenty se mohou nacházet další blíže nespecifikované sekvence bytů (s oblibou je vytváří některé digitální fotoaparáty nebo interní enkodér JPEGu v systémech Microsoft Windows), korektně napsaný dekódovací program by to však nemělo zmást, protože po přečtení všech informací z daného segmentu musí v souboru vyhledat značku následujícího segmentu a nesmí se spoléhat na to, že segmenty leží těsně za sebou.

Použitým způsobem kódování dalších informací je zaručeno, že výše uvedená dvojice bytů vždy reprezentuje značku a nikoli jiné informace. Pokud by se v datech (například v kvantovacích tabulkách či přímo v zakódovaných obrazových datech) vyskytovala hodnota 0×ff, je za ní programem vytvářejícím soubor automaticky vložen byte (stuffle byte) s hodnotou 0×00 a – jak jsme si řekli v předchozím odstavci – touto dvojicí bytů žádná značka nezačíná. Sekvence dvou za sebou jdoucích bytů s hodnotami 0×ff, 0×ff by se v korektních souborech typu JFIF/JPEG nikdy neměla objevit, protože poněkud komplikuje synchronizaci dekodéru při výskytu chyby (například při přenosu obrázku po síti). Díky vkládaným bytům je výskyt takové sekvence v obrazových datech vyloučen, protože původní sekvence 0×ff 0×ff se změní na 0×ff 0×00 0×ff 0×00.

Ve specifikaci JFIF/JPEG (ISO 10918–1 či CCITT T.81) je popsáno mnoho různých typů značek (okolo čtyřiceti), zhruba polovina z nich však není v běžných obrazových souborech nikdy použita. Naopak existuje několik značek, které sice nejsou v normě popsány, ale například digitální fotoaparáty či další aplikace je používají. Mezi základní značky, které najdeme prakticky v každém obrázku, patří například značka SOI, SOS, APP0 (nebo APP1), DHT, DQT a nakonec také značka EOI. Dnešní první ukázková aplikace slouží k výpisu všech značek, které se nachází v zadaném souboru. Po překladu zdrojového kódu (zde se nachází HTML verze se zvýrazněnou syntaxí) libovolným překladačem jazyka C (vyzkoušeno na třicetidvoubitových platformách) se jeho spuštění provede podle následujícího vzo­ru:

jpeg_markers obrazek.jpg 

Program se po svém spuštění pokusí v zadaném souboru vyhledat všechny značky, tj. dvojici bytů začínající hodnotou 0×ff, a vypsat místo jejich výskytu (offset od začátku souboru zapsaný dekadicky i hexadecimálně – binární editory používají různé číselné soustavy), hexadecimální hodnotu značky, jméno značky podle specifikace a anglický význam jména nebo poznámku o podpoře či nepodpoře dané značky. Funkce, která vyhledává značky a přiřazuje jim příslušný identifikátor, je poměrně jednoduchá (to je ostatně dáno výše zmíněnými požadavky na binární tvar značky) a vypadá následovně:

/*
 * Funkce pro získání základních údajů (značek)
 * ze souboru typu JFIF/JPEG
 */
void printJpegMarkers(FILE *fileJpeg) {
    int i;
    unsigned char byte1=0, byte2=0;
    printf("Offset dec\tOffset hex\tZnacka\tJmeno\tText\n");
    // projít celým souborem
    while ((i=fgetc(fileJpeg))!=EOF) {
        // pokud byl předchozí byte nastavený na hodnotu 0xff
        // jedná se možná o začátek značky nebo o běžný datový
        // byte (to rozhodneme v dalším průchodu smyčkou)
        if (byte1==0xff) {
            byte2=i;
            // pokud je druhý byte je v rozsahu 0x01-0xfe
            // jde zcela jistě o značku
            if (byte2>=0x01 && byte2<=0xfe) {
                // výpis základních informací o značce
                printMarker(byte1, byte2, ftell(fileJpeg)-2);
            }
            // zabránit chybné detekci značky
            byte1=0;
        }
        // test, zda je načtený byte roven začátku značky
        if (i==0xff) {
            byte1=0xff;
        }
    }
}; 

Funkce, která k příslušnému identifikátoru značky vyhledá její jméno a anglický popis, je taktéž velmi jednoduchá, protože pouze prohledává pole se zarážkou v místě posledního prvku. Zarážka nám vlastně nahrazuje všechny neznámé značky. Přidání nové značky není problematické – postačí rozšířit pole markers[]. Pozor musíme dát pouze na to, aby na konci pole byla umístěna zarážka zajišťující korektní ukončení smyčky i v případě, že žádná značka není v poli nalezena. Funkce pro vyhledání značky k dané dvojici bytů má tvar:

/*
 * Tisk základních informací o nalezené značce
 */
void printMarker(unsigned char byte1, unsigned char byte2, unsigned long int offset)
{
    int i=0;
    // pokusit se najít značku v poli markers
    // (nebo alespoň zarážku místo neznámé značky)
    while (markers[i].value!=0 &&
           markers[i].value!=byte2)
        i++;
    printf("%10lu\t0x%08lx\t%02x%02x\t%s\t%s\n",
                offset,                 // offset decimálně
                offset,                 // offset hexadecimálně
                byte1,                  // první byte značky
                byte2,                  // druhý byte značky
                markers[i].marker,      // jméno značky
                markers[i].text);       // vysvětlující text
} 

2. Testovací obrázky a jejich zpracování první ukázkovou aplikací

V dnešním článku budeme používat celkem pět testovacích obrázků, jejichž základní vlastnosti jsou vypsány v následující tabulce:

Obrázek Velikost souboru Rozlišení Poznámka
1 344 B 16×16 čtyři barevné čtverce
2 720 B 16×16 obrázek, do kterého MS Windows přidaly rozšiřující informace mezi segmenty
3 2824 B 256×256 obrázek Lenny uložený v nízké kvalitě
4 9479 B 256×256 obrázek Lenny uložený ve střední kvalitě
5 43 833 B 256×256 obrázek Lenny uložený ve vysoké kvalitě

Obrázky si samozřejmě můžete stáhnout (nejedná se o náhledy, ale o „ostrá“ data) a prozkoumat v binárním editoru.

jpeg8_1

První testovací obrázek

jpeg8_2

Druhý testovací obrázek

jpeg8_3

Třetí testovací obrázek

jpeg8_4

Čtvrtý testovací obrázek

jpeg8_5

Pátý testovací obrázek

Následují ukázky zpracování těchto testovacích obrázků dnešní první ukázkovou aplikací. Všimněte si zejména vypsaných offsetů u druhého obrázku, do kterého operační systém Microsoft Windows vložil doplňkové informace mezi jednotlivé segmenty. Mimo to je u tohoto obrázku použit i blok EXIF informací, což je poněkud netypické, protože obrázky generované digitálními fotoaparáty většinou nemají segment APP0, ale pouze APP1 (EXIF). V samotném segmentu EXIF se pak může nacházet mnoho nespecifikovaných značek.

Struktura prvního testovacího obrázku

Offset dec  Offset hex  Znacka  Jmeno   Text
         0  0x00000000  ffd8    SOI Start Of Image
         2  0x00000002  ffe0    APP0    Application Marker 0
        20  0x00000014  ffdb    DQT Define Quantization Table
        89  0x00000059  ffdb    DQT Define Quantization Table
       158  0x0000009e  ffc0    SOF0    Start Of Frame (baseline JPEG)
       177  0x000000b1  ffc4    DHT Define Huffman Table
       202  0x000000ca  ffc4    DHT Define Huffman Table
       224  0x000000e0  ffc4    DHT Define Huffman Table
       246  0x000000f6  ffc4    DHT Define Huffman Table
       283  0x0000011b  ffda    SOS Start Of Scan
       342  0x00000156  ffd9    EOI End Of Image 

Struktura druhého testovacího obrázku

Offset dec  Offset hex  Znacka  Jmeno   Text
         0  0x00000000  ffd8    SOI Start Of Image
         2  0x00000002  ffe0    APP0    Application Marker 0
        20  0x00000014  ffe1    APP1    Application Marker 1 (EXIF)
        44  0x0000002c  ffdb    DQT Define Quantization Table
       113  0x00000071  ffdb    DQT Define Quantization Table
       182  0x000000b6  ffc0    SOF0    Start Of Frame (baseline JPEG)
       201  0x000000c9  ffc4    DHT Define Huffman Table
       234  0x000000ea  ffc4    DHT Define Huffman Table
       417  0x000001a1  ffc4    DHT Define Huffman Table
       450  0x000001c2  ffc4    DHT Define Huffman Table
       633  0x00000279  ffda    SOS Start Of Scan
       718  0x000002ce  ffd9    EOI End Of Image 

Struktura třetího testovacího obrázku

Offset dec  Offset hex  Znacka  Jmeno   Text
         0  0x00000000  ffd8    SOI Start Of Image
         2  0x00000002  ffe0    APP0    Application Marker 0
        20  0x00000014  ffdb    DQT Define Quantization Table
        89  0x00000059  ffdb    DQT Define Quantization Table
       158  0x0000009e  ffc0    SOF0    Start Of Frame (baseline JPEG)
       177  0x000000b1  ffc4    DHT Define Huffman Table
       203  0x000000cb  ffc4    DHT Define Huffman Table
       248  0x000000f8  ffc4    DHT Define Huffman Table
       273  0x00000111  ffc4    DHT Define Huffman Table
       300  0x0000012c  ffda    SOS Start Of Scan
      2822  0x00000b06  ffd9    EOI End Of Image 

Struktura čtvrtého testovacího obrázku

Offset dec  Offset hex  Znacka  Jmeno   Text
         0  0x00000000  ffd8    SOI Start Of Image
         2  0x00000002  ffe0    APP0    Application Marker 0
        20  0x00000014  ffdb    DQT Define Quantization Table
        89  0x00000059  ffdb    DQT Define Quantization Table
       158  0x0000009e  ffc0    SOF0    Start Of Frame (baseline JPEG)
       177  0x000000b1  ffc4    DHT Define Huffman Table
       206  0x000000ce  ffc4    DHT Define Huffman Table
       266  0x0000010a  ffc4    DHT Define Huffman Table
       293  0x00000125  ffc4    DHT Define Huffman Table
       332  0x0000014c  ffda    SOS Start Of Scan
      9477  0x00002505  ffd9    EOI End Of Image 

Struktura pátého testovacího obrázku

Offset dec  Offset hex  Znacka  Jmeno   Text
         0  0x00000000  ffd8    SOI Start Of Image
         2  0x00000002  ffe0    APP0    Application Marker 0
        20  0x00000014  ffdb    DQT Define Quantization Table
        89  0x00000059  ffdb    DQT Define Quantization Table
       158  0x0000009e  ffc0    SOF0    Start Of Frame (baseline JPEG)
       177  0x000000b1  ffc4    DHT Define Huffman Table
       210  0x000000d2  ffc4    DHT Define Huffman Table
       313  0x00000139  ffc4    DHT Define Huffman Table
       344  0x00000158  ffc4    DHT Define Huffman Table
       426  0x000001aa  ffda    SOS Start Of Scan
     43831  0x0000ab37  ffd9    EOI End Of Image 

3. Druhá ukázková aplikace pro výpis informací ze souborů typu JFIF/JPEG

Dnešní druhá ukázková aplikace, jejíž zdrojový text si opět můžete stáhnout, stejně jako HTML verzi se zvýrazněnou syntaxí, je již poněkud složitější než aplikace první, protože se snaží analyzovat a posléze vypsat některé důležité datové struktury umístěné v obrázcích typu JFIF/JPEG. Podrobnější informace o funkcích této aplikace budou uvedeny v dalších kapitolách. Ve čtvrté kapitole bude popsán způsob vyčtení základních informací o obrázku (včetně jeho hlavičky a offsetů dalších segmentů), v páté kapitole se budeme věnovat výpisu kvantovacích tabulek a konečně v kapitole šesté načtení a výpisu obsahu Huffmanových kódovacích tabulek.

4. Načtení a výpis základních informací o souboru typu JFIF/JPEG

Základní údaje o souboru typu JFIF/JPEG a o obrázku, který je v tomto souboru uložený, se získají zejména z obsahu začátku SOF0 (Start Of Frame). Zde nás zajímá především informace o rozlišení obrázku (tato informace není uložena v hlavičce, jak by se mohlo zdát logické) a o tom, které barvové složky jsou v obrázku (zde nazývaném frame) použity. Dále se zjišťují offsety důležitých datových struktur obsažených v souboru, zejména začátek definic Huffmanových kódových tabulek (segment DHT), kvantizačních tabulek (segment DQT), kódovaných obrazových datech (segment SOS) aj. O načtení těchto informací se stará funkce nazvaná getJpegInfo(). Všechny načtené informace jsou uloženy v datové struktuře pojmenované příznačně jpegInfo:

/*
 * Funkce pro získání základních údajů o souboru typu JFIF/JPEG
 */
void getJpegInfo(const char *fileName, FILE *fileJpeg, JpegInfo *jpegInfo)
{
    unsigned char b1,b2,so;
    long l,ll,fl;
    int ii,i;
    jpegInfo->width=0;
    jpegInfo->height=0;
    fseek(fileJpeg, 0, SEEK_END);
    ll=ftell(fileJpeg);
    jpegInfo->size=ll;
    fseek(fileJpeg, 0, SEEK_SET);
    fread(&b1, 1, 1, fileJpeg);
    fread(&b2, 1, 1, fileJpeg);
    fl=2;
    if ((b1==0xff) && (b2==0xd8)){
        strcpy(jpegInfo->fname, fileName);
        while (fl<ll){
            fseek(fileJpeg, fl, SEEK_SET);
            fread(&b1, 1, 1, fileJpeg);
            fread(&so, 1, 1, fileJpeg);
            if (b1==0xff){
                fread(&b1, 1, 1, fileJpeg);
                fread(&b2, 1, 1, fileJpeg);
                fl+=2+((long)b1<<8)+b2;
                switch (so) {
                    case 0xdd: { // interval synchronizačních značek
                                   fread(&b1, 1, 1, fileJpeg);
                                   fread(&b2, 1, 1, fileJpeg);
                                   jpegInfo->rstinterval=(b1<<8)+b2;
                                   break;
                               }
                    case 0xda: { // kódovaná obrazová data
                                   jpegInfo->p_data=fl;
                                   return;
                               }
                    case 0xdb: { // kvantizační tabulky
                                   fread(&b1,1,1,fileJpeg);
                                   if (b1==0)
                                       jpegInfo->p_qtab_y=ftell(fileJpeg);
                                   else
                                           jpegInfo->p_qtab_c=ftell(fileJpeg);
                                   if (fl>ftell(fileJpeg)+65){
                                       fseek(fileJpeg, 64, SEEK_CUR);
                                       fread(&b1, 1, 1, fileJpeg);
                                       if (b1==0)
                                           jpegInfo->p_qtab_y=ftell(fileJpeg);
                                       else
                                           jpegInfo->p_qtab_c=ftell(fileJpeg);
                                   }
                                   break;
                               }
                    case 0xc4: { // Huffmanovy kódové tabulky
                                   for (ii=0; ii<4; ii++) {
                                       fread(&b1, 1, 1, fileJpeg);
                                       switch (b1){
                                           case 0:  jpegInfo->p_htab_y_dc=ftell(fileJpeg);break;
                                           case 1:  jpegInfo->p_htab_c_dc=ftell(fileJpeg);break;
                                           case 16: jpegInfo->p_htab_y_ac=ftell(fileJpeg);break;
                                           case 17: jpegInfo->p_htab_c_ac=ftell(fileJpeg);break;

                                       };
                                       l=0;
                                       for(i=0; i<16; i++) {
                                           fread(&b1, 1, 1, fileJpeg);
                                           l+=b1;
                                       };
                                       fseek(fileJpeg,l,SEEK_CUR);
                                       if (ftell(fileJpeg)>=fl) break;
                                   };
                                   break;
                               }
                    case 0xc0: { // základní informace o obrázku
                                   fread(&b1, 1, 1, fileJpeg);
                                   fread(&b1, 1, 1, fileJpeg);
                                   fread(&b2, 1, 1, fileJpeg);
                                   jpegInfo->height=((long)b1<<8)+b2;
                                   fread(&b1, 1, 1, fileJpeg);
                                   fread(&b2, 1, 1, fileJpeg);
                                   jpegInfo->width=((long)b1<<8)+b2;
                                   fseek(fileJpeg, 2, SEEK_CUR);
                                   fread(&jpegInfo->sf_y, 1, 1, fileJpeg);
                                   fseek(fileJpeg, 2, SEEK_CUR);
                                   fread(&jpegInfo->sf_cb, 1, 1, fileJpeg);
                                   fseek(fileJpeg, 2, SEEK_CUR);
                                   fread(&jpegInfo->sf_cr, 1, 1, fileJpeg);
                                   break;
                               }
                };
            }
        }
    }
    else {                              // nenašli jsme značku -> vadný JPEG soubor
        return;
    }
    return;
} 

O výpis načtených informací se stará funkce printJpegInfo(), jejíž tvar je následující:

/*
 * Tisk základních informací o souboru typu JFIF/JPEG
 */
void printJpegInfo(JpegInfo *jpegInfo)
{
    printf("Jmeno souboru:    %s\n",        jpegInfo->fname);
    printf("Delka souboru:    %ld bytu\n",  jpegInfo->size);
    printf("Sirka obrazku:    %d pixelu\n", jpegInfo->width);
    printf("Vyska obrazku:    %d pixelu\n", jpegInfo->height);
    printOffset("Offset zacatku obrazovych dat:            ", jpegInfo->p_data);
    printOffset("Offset zacatku kvantizacni tabulky Y:     ", jpegInfo->p_qtab_y);
    printOffset("Offset zacatku kvantizacni tabulky CbCr:  ", jpegInfo->p_qtab_c);
    printOffset("Offset zacatku Huffmanovy tabulky DC/Y:   ", jpegInfo->p_htab_y_dc);
    printOffset("Offset zacatku Huffmanovy tabulky AC/Y:   ", jpegInfo->p_htab_y_ac);
    printOffset("Offset zacatku Huffmanovy tabulky DC/CbCr:", jpegInfo->p_htab_c_dc);
    printOffset("Offset zacatku Huffmanovy tabulky AC/CbCr:", jpegInfo->p_htab_c_ac);
} 

5. Načtení a výpis obsahu kvantovacích tabulek

Výpis kvantovacích tabulek je v ukázkové aplikaci implementován ve funkcích printQuantiza­tionTable() a printQuantiza­tionTables(). Kvantizační tabulky začínají segmentem s hlavičkou DQT, typ tabulky je určen svým číslem a také hodnotou udávající, jestli jsou jednotlivé koeficienty uloženy na osm bitů či šestnáct bitů (to je však nezvyklé). Jak již víme z předchozí části tohoto seriálu, jsou kvantovací koeficienty uloženy v poli 8×8 hodnot, ale způsobem cik-cak, takže hodnoty jsou ve výsledné matici zpřeházeny:

/*
 * Tisk obsahu jedné kvantizační tabulky
 */
void printQuantizationTable(FILE *fileJpeg, unsigned int seek)
{
#define DCTSIZE         8       // velikost bloku DCT
#define NUM_QUANT_TBLS  4       // kvantizační tabulky jsou očíslovány 0..3
    int n;                      // číslo kvantizační tabulky
    int prec;                   // bitová šířka kvantizačních koeficientů
    int i, j;                   // počitadla smyček
    fseek(fileJpeg, seek, SEEK_SET);
    n=fgetc(fileJpeg);
    n&=0x0F;
    prec=n>>4;
    printf("kvantizacni tabulka cislo %d, presnost %d bitu\n", n, prec==0 ? 8:16);
    // něco je špatně, nekorektní číslo tabulky
    if (n >= NUM_QUANT_TBLS) {
        printf("nekorektni cislo kvantizacni tabulky %d!\n", n);
        return;
    }
    // načíst všech 8x8 kvantizačních koeficientů
    for (j=0; j<DCTSIZE; j++) {
        for (i=0; i<DCTSIZE; i++) {
            int tmp=fgetc(fileJpeg);
            if (prec) // šestnáctibitové koeficienty?
                tmp=(tmp<<8)+fgetc(fileJpeg);
            printf("%d\t", tmp);
        }
        // dalších osm hodnot na řádku
        printf("\n");
    }
}



/*
 * Tisk kvantizačních tabulek
 */
void printQuantizationTables(FILE *fileJpeg, JpegInfo *jpegInfo)
{
    // načíst kvantizační tabulky
    printf("\nKvantizacni tabulka luminance Y (sekvence cik-cak):\n");
    printQuantizationTable(fileJpeg, jpegInfo->p_qtab_y-1);
    printf("\nKvantizacni tabulka chrominance Cb Cr (sekvence cik-cak):\n");
    printQuantizationTable(fileJpeg, jpegInfo->p_qtab_c-1);
} 

6. Načtení a výpis obsahu Huffmanových kódovacích tabulek

I o způsobu uložení kódových slov pro Huffmanovy kódové tabulky jsme si povídali v předchozí části tohoto seriálu. V dnešní druhé demonstrační aplikaci se kódová slova, jež jsou uložena v segmentech začínajících značkou DHT, načítají a vypisují ve funkcích printHuffmanTa­ble() a printHuffmanTa­bles(), které mají následující tvar:

/*
 * Tisk obsahu jedné Huffmanovy tabulky
 */
void printHuffmanTable(FILE *fileJpeg)
{
    int i, j;
    int count=0;
    int bits_a[16];
    printf("tabulka cislo: 0x%02x\n", fgetc(fileJpeg));
    puts("hodnoty pro bitove delky:");
    for (i=0; i<16; i++) {
        int bits=fgetc(fileJpeg);
        count+=bits;
        printf("Hodnoty pro bitove sekvence delky %02d bitu: %02x\n", i+1, bits);
        bits_a[i]=bits;
    }
    if (count>256) {
        printf("Nekorektni celkovy pocet ulozenych hodnot!");
        return;
    }
    else {
        printf("celkem je v tabulce ulozeno %d hodnot\n", count);
    }
    puts("\nHodnoty pro konstrukci binarniho stromu:");
    for (j=0; j<16; j++) {
        printf("sekvence delky %02d bitu: ", j+1);
        for (i=0; i<bits_a[j]; i++) {
            printf("%02x  ", fgetc(fileJpeg));
        }
        putchar('\n');
    }
    putchar('\n');
}



/*
 * Tisk všech nalezených Huffmanových kódových tabulek
 */
void printHuffmanTables(FILE *fileJpeg, JpegInfo *jpegInfo)
{
    printf("\nHuffmanova tabulka pro DC koeficienty luminance (Y):\n");
    fseek(fileJpeg, jpegInfo->p_htab_y_dc-1, SEEK_SET);
    printHuffmanTable(fileJpeg); // výpis stromu

    printf("\nHuffmanova tabulka pro DC koeficienty chrominance (Cb Cr):\n");
    fseek(fileJpeg, jpegInfo->p_htab_c_dc-1, SEEK_SET);
    printHuffmanTable(fileJpeg); // výpis stromu

    printf("\nHuffmanova tabulka pro AC koeficienty luminance (Y):\n");
    fseek(fileJpeg, jpegInfo->p_htab_y_ac-1, SEEK_SET);
    printHuffmanTable(fileJpeg); // výpis stromu

    printf("\nHuffmanova tabulka pro AC koeficienty chrominance (Cb Cr):\n");
    fseek(fileJpeg, jpegInfo->p_htab_c_ac-1, SEEK_SET);
    printHuffmanTable(fileJpeg); // výpis stromu
}; 

7. Výpis informací o testovacích obrázcích

V následujících textových souborech skrytých pod jednotlivými odkazy jsou uvedeny výpisy informací, které jsou zjištěny druhou demonstrační aplikací na pětici testovacích obrázků. Nejdříve jsou vypsány základní informace o souboru (rozlišení obrázku, celková délka, offsety k důležitým segmentům) a posléze hodnoty uložené v kvantovacích tabulkách a kódová slova uložená v Huffmanových kódových tabulkách. Tato kódová slova by dekodér použil pro výstavbu prefixového Huffmanova kódu.

CS24_early

  1. Podrobné informace o prvním testovacím obrázku
  2. Podrobné informace o druhém testovacím obrázku
  3. Podrobné informace o třetím testovacím obrázku
  4. Podrobné informace o čtvrtém testovacím obrázku
  5. Podrobné informace o pátém testovacím obrázku

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

V následujícím pokračování tohoto seriálu ukončíme poměrně dlouhou sérii dílů věnovaných grafickému formátu JFIF a komprimaci pomocí JPEG. Řekneme si podrobnější informace o progresivním JPEGu i o segmentech EXIF, do kterých mnohé aplikace a především digitální fotoaparáty ukládají dodatečná data (či spíše metadata) o pořízeném snímku.

Byl pro vás článek přínosný?

Autor článku

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