LIRE LA TAILLE D'UN FICHIER JPEG

Comment faire pour lire les dimensions d'une image JPEG, si on ne dispose pas des bibliothes adaptées (libjpeg...) ?
Nous allons voir comment le le faire en s'attaquant directement au header d'un de ces fichier. How to read the sizes of a JPEG image without bibiotheq like libjpeg.
We will see how this can be done bty parsing byte by byte the header

Structure des fichiers JPEG, les FRAMES

Les fichiers JPEG commencent par 0xff et 0xd8, c'est le Start of Image

Ensuite ils sont composés de blocs (frame) qui commencent par 0xff. Le char 0xff de début de bloc est suivit d'un indicateur de type de bloc.
Ensuite vient la longueur du bloc, en octet. Elle est ecrite sur deux octet, en Big Endien.
Donc on retrouve séquentiellement la même structure de 4 octets :

La longueur est le nombre d'octets du frame Non compris les deux premiers octets, c'est comme ça...
Donc vous pouvez vérifier en comptant qu'on retrouve bien un nouveau SOF à la bonne place. Sur l'exemple on a des frames qui font successivement 16 octets, puis 67 et à nouveau 67 octets.

A JPEG file begin with 0xff and 0xd8. Those bytes are the Start of Image

After they are made of frames beginning with 0xff.
The byte first frame, 0xff is followed by an frame type identifier on one byte
After come the lenght of the bloc in byte. It's writted on 2 bytes in big endian
So we will find repeatdly the frame structure :

Le frame de dimension

Le bloc qui contient la taille est indiqué par 0xc0, 0xc1, 0xc2 ou 0xc3.

Il contient les éléments habituel d'une frame (SOF, identifier, longueur) et enfin ce que nous cherchons :

On pourrait essayer de chercher simplement la première occurence de cette chaine.

MAIS : si l'image est précédée d'une miniature, il risque d'y avoir un bloc contenant des données brutes (codage de l'image miniature).
Et avec un peu de malchance il pourrait y avoir des données qui s'écrivent ff et c0 dedans : tous l'espace de chiffres sur un octets est utilisé.
Donc en procédant ainsi on risque bien de tomber sur des chiffres qui ne sont pas un Start Of Frame.

DONC :

SI C'EST NOTRE FRAME DE DIMENSION : Dimension frame This frame is identified by one of those bytes : 0xc0, 0xc1, 0xc2 or 0xc3
It contains the usual frame beginning (SOF, Identifier, lenght) and what we are searching for :

We could have a temptation : just search for the first occurence of those two byte in the file.

BUT : Some image are preceded by a thunbail.
If we are unlucky some data in the thunbial could contains 0xff anf 0xc0 : the full numeration space of a byte is used within a frame.
So, working like this, we can get numbers who are not the start of the dimension frame.

We have to read each start of frame If it's not the frame that we are searching for, We read it's lenght We skip all the octets of this uninterresting frame.

Exemple de code source


#include <stdlib.h>
#include <stdio.h>
 
int main(int argc, char * argv[] )
 
{
  FILE * fp ;
  int i;
  int c1, c2 , be , le , W , H ;
  int OFS;
  fp = fopen(argv[1],"r");
 
  c1 =    fgetc( fp);
  c2 =    fgetc( fp);
  if(c1==0xff && c2==0xd8) printf("OK, JPEG"); /*Check JPEG format*/
  
  for (i=0 ; i < 20 ; i++){ 
    /* arbitrary stop at 20 here, just to stop the program in case of bug...   */
    c1 =    fgetc( fp);
    // printf("%d\t%#0X\t%#c",i,c1,c1);
    
    if (c1==0xff) { /* We detect a SOF*/
      c2 =    fgetc( fp);
      if ( c2 >= 0xc0 && c2 <= 0xc3){
	/* It's the size frame we read his dimensions, print them and stop */
	fseek (fp, 3, SEEK_CUR);
	be =    fgetc( fp);
	le =    fgetc( fp);
	H = 256*be + le ;
	be =    fgetc( fp);
	le =    fgetc( fp);
	W = 256*be + le ;
	printf ("\t<-- +++ HxW : %d x %d\n",H,W);
	break ;
      }else{
	/* It's not the size bloc, we just read his size to skip it */
	be =    fgetc( fp);
	le =    fgetc( fp);
	OFS = 256*be + le ;
	// printf ("\t OFFSET = %d",OFS);
	fseek (fp, OFS-2, SEEK_CUR);
      }
    }
    // printf("\n");
  }
  return 1; 
}