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 vzoru:
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.
První testovací obrázek
Druhý testovací obrázek
Třetí testovací obrázek
Čtvrtý testovací obrázek
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 printQuantizationTable() a printQuantizationTables(). 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 printHuffmanTable() a printHuffmanTables(), 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.
- Podrobné informace o prvním testovacím obrázku
- Podrobné informace o druhém testovacím obrázku
- Podrobné informace o třetím testovacím obrázku
- Podrobné informace o čtvrtém testovacím obrázku
- 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.