/*
* Demonstracni priklad, ktery nacte a posleze vytiskne zakladni udaje
* o souboru typu JPEG. Vytvoreno s vyuzitim upravene funkce jpeginfo()
* Miloslava Vlcka a Zdenka Vladeky (FIT VUT v Brne).
*
* Autor: Pavel Tisnovsky (vse mimo funkci getJpegInfo())
*
* Pouziti:
* jpeg_info image.jpg
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Datova struktura se zakladnimi informacemi o JPEG souboru
*/
typedef struct JpegInfo {
int width; // sirka obrazku
int height; // vyska obrazku
char fname[200]; // jmeno zdrojoveho souboru
unsigned long size; // celkova velikost souboru
long p_data; // pozice zacatku obrazovychdat v souboru
long p_qtab_y; // pozice zacatku kvantizacni tabulky pro slozku Y
long p_qtab_c; // pozice zacatku kvantizacni tabulky pro slozku C
long p_htab_y_dc; // zacatek Huffmanovy kodove tabulky DC koeficientu slozky Y
long p_htab_y_ac; // zacatek Huffmanovy kodove tabulky AC koeficientu slozky Y
long p_htab_c_dc; // zacatek Huffmanovy kodove tabulky DC koeficientu slozek CbCr
long p_htab_c_ac; // zacatek Huffmanovy kodove tabulky AC koeficientu slozek CbCr
unsigned int rstinterval; // restart interval
unsigned char sf_y,sf_cb, sf_cr;
} JpegInfo;
JpegInfo jpegInfo;
/*
* Funkce pro ziskani zakladnich udaju 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: { // define restart marker
fread(&b1, 1, 1, fileJpeg);
fread(&b2, 1, 1, fileJpeg);
jpegInfo->rstinterval=(b1<<8)+b2;
break;
}
case 0xda: { // kodovana obrazova data
jpegInfo->p_data=fl;
return;
}
case 0xdb: { // kvantizacni 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 kodove 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: { // zakladni informace o obrazku
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 { // nenasli jsme znacku -> vadny JPEG soubor
return;
}
return;
}
/*
* Tisk hodnoty offsetu jako dekadicke a hexadecimalni hodnoty
*/
void printOffset(const char *str, unsigned int value)
{
printf("%s %10u\t0x%08x\n", str, value, value);
}
/*
* Tisk zakladnich informaci 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);
}
/*
* Tisk obsahu jedne kvantizacni tabulky
*/
void printQuantizationTable(FILE *fileJpeg, unsigned int seek)
{
#define DCTSIZE 8 // velikost bloku DCT
#define NUM_QUANT_TBLS 4 // kvantizacni tabulky jsou ocislovany 0..3
int n; // cislo kvantizacni tabulky
int prec; // bitova sirka kvantizacnich koeficientu
int i, j; // pocitadla smycek
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);
// neco je spatne, nekorektni cislo tabulky
if (n >= NUM_QUANT_TBLS) {
printf("nekorektni cislo kvantizacni tabulky %d!\n", n);
return;
}
// nacist vsech 8x8 kvantizacnich koeficientu
for (j=0; j<DCTSIZE; j++) {
for (i=0; i<DCTSIZE; i++) {
int tmp=fgetc(fileJpeg);
if (prec) // sestnactibitove koeficienty?
tmp=(tmp<<8)+fgetc(fileJpeg);
printf("%d\t", tmp);
}
// dalsich osm hodnot na radku
printf("\n");
}
}
/*
* Tisk kvantizacnich tabulek
*/
void printQuantizationTables(FILE *fileJpeg, JpegInfo *jpegInfo)
{
// nacist kvantizacni 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);
}
/*
* Tisk obsahu jedne 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 Huffmanovych kodovych 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); // vypis stromu
printf("\nHuffmanova tabulka pro DC koeficienty chrominance (Cb Cr):\n");
fseek(fileJpeg, jpegInfo->p_htab_c_dc-1, SEEK_SET);
printHuffmanTable(fileJpeg); // vypis stromu
printf("\nHuffmanova tabulka pro AC koeficienty luminance (Y):\n");
fseek(fileJpeg, jpegInfo->p_htab_y_ac-1, SEEK_SET);
printHuffmanTable(fileJpeg); // vypis stromu
printf("\nHuffmanova tabulka pro AC koeficienty chrominance (Cb Cr):\n");
fseek(fileJpeg, jpegInfo->p_htab_c_ac-1, SEEK_SET);
printHuffmanTable(fileJpeg); // vypis stromu
};
/*
* Hlavni funkce konzolove aplikace
*/
int main(int argc, char *argv[])
{
FILE *fileJpeg;
// kontrola, jestli je z prikazoveho radku zadano jmeno souboru
if (argc<=1) {
printf("Pouziti jpeg_info image.jpg\n");
return 1;
}
// pokus o otevreni souboru pro cteni
fileJpeg=fopen(argv[1], "rb");
if (!fileJpeg) {
printf("Chyba pri otevirani souboru %s pro cteni!\n", argv[1]);
return 1;
}
// ziskani informaci z JPEG souboru a jejich vypis
getJpegInfo(argv[1], fileJpeg, &jpegInfo);
printJpegInfo(&jpegInfo);
printQuantizationTables(fileJpeg, &jpegInfo);
printHuffmanTables(fileJpeg, &jpegInfo);
if (fclose(fileJpeg)==EOF) {
printf("Chyba pri zavirani souboru %s!\n", argv[1]);
return 1;
}
return 0;
}
/*
* finito
*/