how read the GIF and JPG image size?

Pages: 123
from the JPG format:
1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct _JFIFHeader
{
  BYTE SOI[2];          /* 00h  Start of Image Marker     */
  BYTE APP0[2];         /* 02h  Application Use Marker    */
  BYTE Length[2];       /* 04h  Length of APP0 Field      */
  BYTE Identifier[5];   /* 06h  "JFIF" (zero terminated) Id String */
  BYTE Version[2];      /* 07h  JFIF Format Revision      */
  BYTE Units;           /* 09h  Units used for Resolution */
  BYTE Xdensity[2];     /* 0Ah  Horizontal Resolution     */
  BYTE Ydensity[2];     /* 0Ch  Vertical Resolution       */
  BYTE XThumbnail;      /* 0Eh  Horizontal Pixel Count    */
  BYTE YThumbnail;      /* 0Fh  Vertical Pixel Count      */
} JFIFHEAD;

the Xdensity is width?
Peeking at the first few bytes in a 500x386 pixel jpg image gives:

SOI     : ff d8
APP0    : ff e0
Length  : 00 10
Ident   : 4a 46  49 46 00  "JFIF"
Version : 01 01
Units   : 00
Xdensity: 00 01
Ydensity: 00 01
XThumb  : 00
YThumb  : 00

The values are all stored in "big endian" format, so the values of Xdensity and Ydensity are both 1.

Doing a quick google it's not immediately obvious where the height and width of the image are stored.
Last edited on
true isn't easy i did the search that why i found these structure :(
Personally I would just use a library like STBI (STB Image): https://github.com/nothings/stb

But anyway, according to http://vip.sugovica.hu/Sardi/kepnezo/JPEG%20File%20Layout%20and%20Format.htm
you are looking for SOF0 or SOF1 segment, which will contain the image width/height
SOF0 (Start Of Frame 0) marker:

 
            Field                      Size                      Description

        
         Marker Identifier           2 bytes    0xff, 0xc0 to identify SOF0 marker

         Length                      2 bytes   This value equals to 8 + components*3 value

         Data precision              1 byte     This is in bits/sample, usually 8

                                                                        (12 and 16 not supported by most software).

         Image height                2 bytes    This must be > 0

         Image Width                 2 bytes    This must be > 0

         Number of components        1 byte      Usually 1 = grey scaled, 3 = color YcbCr or YIQ

                                                                          4 = color CMYK
         Each component              3 bytes     Read each component data of 3 bytes. It contains,

                                                             (component Id(1byte)(1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q),   

                                                              sampling factors (1byte) (bit 0-3 vertical., 4-7 horizontal.),

                                                             quantization table number (1 byte)). 
Last edited on
how many bytes are to Image Height?
I found some code that reads the image size. http://carnage-melon.tom7.org/stuff/jpegsize.c
I translated it from C to C++.
It just finds the first section with a code in the following cases and reads the size info from that section.
1
2
3
            case 0xC0: case 0xC1: case 0xC2: case 0xC3: case 0xC5:
            case 0xC6: case 0xC7: case 0xC9: case 0xCA: case 0xCB:
            case 0xCD: case 0xCE: case 0xCF:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <iostream>
#include <fstream>

inline bool readbyte( int& byte, std::istream& in )
{
    return (byte = in.get()) >= 0;
}

inline bool readword( int& word, std::istream& in )
{
    int cc = 0, dd = 0;
    if( (cc = in.get()) < 0 || (dd = in.get()) < 0 )
        return false;
    word = (cc << 8) + dd;
    return true;
}

bool scanhead( std::istream& in, int& image_width, int& image_height )
{
    int marker = 0, dummy = 0;

    if ( in.get() != 0xFF || in.get() != 0xD8 )
        return 0;

    while (true)
    {
        int discarded_bytes = 0;
        readbyte(marker, in);

        while (marker != 0xFF)
        {
            ++discarded_bytes;
            readbyte(marker, in);
        }

        do readbyte(marker, in); while (marker == 0xFF);

        if (discarded_bytes != 0)
            return 0;
   

        switch (marker)
        {
            case 0xC0: case 0xC1: case 0xC2: case 0xC3: case 0xC5:
            case 0xC6: case 0xC7: case 0xC9: case 0xCA: case 0xCB:
            case 0xCD: case 0xCE: case 0xCF:
            {
                readword( dummy, in );    // usual parameter length count
                readbyte( dummy, in );
                readword( image_height, in );
                readword( image_width, in );
                readbyte( dummy, in );
                return true;
            }

            case 0xDA: case 0xD9:
                return false;

            default:
            {
                int length;
                readword(length, in);

                if (length < 2)
                    return 0;
                length -= 2;

                for ( ; length > 0; --length)
                    readbyte(dummy, in);
            }
        }
    }
}

int main( int argc, char** argv )
{
    if( argc != 2 )
    {
        std::cerr << "Usage: jpeg_size FILENAME\n";
        return 1;
    }

    std::ifstream fin( argv[1] );
    if( !fin )
    {
        std::cerr << "Cannot open file: " << argv[1] << '\n';
        return 1;
    }

    int height = 0, width = 0;
    if( !scanhead( fin, width, height ) )
    {
        std::cerr << "Error scanning file.\n";
        return 1;
    }

    std::cout << "width: " << width << "   height: " << height << '\n';
}

Last edited on
If you don't mind a windows only solution have a look at the Image class in GDI+
https://docs.microsoft.com/en-us/windows/win32/api/gdiplusheaders/nl-gdiplusheaders-image
from here: http://vip.sugovica.hu/Sardi/kepnezo/JPEG%20File%20Layout%20and%20Format.htm
i belive the width is 13 byte... but i don't get the right results :(
what i'm doing wrong?
Last edited on
heres what i did:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
struct BMPSize
{
    int Width=0;
    int Height=0;
};

BMPSize GetBMPSize(const char *filename)
{
    BMPSize bmp;
    FILE* img = fopen(filename, "rb");   //read the file
    char header[54];
    fread(header, sizeof(unsigned char), 54, img); // read the 54-byte header
    int stringsize=strlen(filename);
    char format[4]={filename[stringsize-3],filename[stringsize-2],filename[stringsize-1],'\0'};
    int width=0;
    int height=0;
    if(strcmp(format, "bmp")==0 || strcmp(format, "BMP")==0)
    {
        // extract image height and width from header
        width = *(int*)&header[18];
        height= *(int*)&header[22];
        printf("File format BMP:\nWidth: %d\nHeight: %d", width,height);
    }
    else if(strcmp(format, "jpg")==0 || strcmp(format, "JPG")==0)
    {
        size_t i =0;
        do
        {
            if( header[i] == 0xc0 || header[i] == 0xc1)
            {
                width = *(int*)&header[i+2];
                height= *(int*)&header[i+4];
                break;
            }
            i++;
        }while(i<strlen(header));
        // extract image height and width from header
        width = *(int*)&header[13];
        height= *(int*)&header[15];
        printf("File format JPG:\nWidth: %d\nHeight: %d", width,height);
    }
    else if(strcmp(format, "gif")==0 || strcmp(format, "GIF")==0)
    {
        // extract image height and width from header
        int test=sizeof(GIFHEAD) + sizeof(BYTE) + sizeof(WORD)*3;
        width = *(int*)&header[test];
        height= *(int*)&header[test+sizeof(WORD)];
        printf("File format GIF:\nWidth: %d\nHeight: %d", width,height);
    }

    fclose(img);
    bmp.Width=width;
    bmp.Height=height;
    return bmp;
}

i get allways 65536;65537... why that i'm doing wrong?
i'm tiried changing the i position and allways get the same result... these don't make sence only a head pain :(
Firstly, just looking for the first c0 or c1 byte is, well, idiotic.

Secondly, did you see how that program in my last post works? There's no guarantee that the size will be available in the first 54 bytes. In my example jpg the size info isn't until around byte 166.
Last edited on
dutch i understand that i'm doing some errors, but can you correct me for i learn more?
There are so many errors in your code that I would have to write an essay on what you did wrong, and I worry that even an essay may not be helpful for you since you seem to never listen to people's helpful advice. There is really nothing to learn from your code, other than to avoid writing code like that ever again. Make your code so clean and readable that even if you had alzheimer's you could follow what the code is doing. And it isn't just for yourself, but for the sake of people reading your code too. So may bugs and errors could be fixed by just looking at your code, pointing out what part of the code looks off, like a "hack", then cleaning it up. Complicated code isn't difficult to write, writing simple code is the much more difficult. The first step to simple code is to stop reinventing the wheel.
poteto i'm using Code Blocks with Graphics.h and GNU compiler:
1- Graphics.h is for learn... and doing these function for get the image size is learning too;
2 - GNU compiler is free and i use for personal propose.
and now i changed the function\structure names for be more easy:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
struct Size
{
    int Width=0;
    int Height=0;
};

Size GetImageSize(const char *filename)
{

    //Get File Data:
    FILE* ImageFile = fopen(filename, "rb");   //read the file
    char header[256];
    fread(header, sizeof(unsigned char), 256, ImageFile); // read the 256-byte header

    //Get Image Format:
    int stringsize=strlen(filename);
    char format[4]={filename[stringsize-3],filename[stringsize-2],filename[stringsize-1],'\0'};


    //getting the size, by it's own format:
    int width=0;
    int height=0;

    if(strcmp(format, "bmp")==0 || strcmp(format, "BMP")==0)
    {
        // extract image BMP height and width from header from 18 and 22 bytes:
        width = *(int*)&header[18];
        height= *(int*)&header[22];
        printf("File format BMP:\nWidth: %d\nHeight: %d", width,height);
    }

    else if(strcmp(format, "jpg")==0 || strcmp(format, "JPG")==0)
    {
        size_t index =0;

        do
        {
            if( strcmp(header, "SOF0")==0)
            {
                printf("hello");
                width = *(int*)&header[index+2];
                height= *(int*)&header[index+4];
                break;
            }
            index++;
        }while(index<strlen(header));
        // extract image height and width from header
        printf("File format JPG:\nWidth: %d\nHeight: %d", width,height);
    }

    else if(strcmp(format, "gif")==0 || strcmp(format, "GIF")==0)
    {
        // extract image height and width from header
        int test=sizeof(GIFHEAD) + sizeof(BYTE) + sizeof(WORD)*3;
        width = *(int*)&header[test];
        height= *(int*)&header[test+sizeof(WORD)];
        printf("File format GIF:\nWidth: %d\nHeight: %d", width,height);
    }

    fclose(ImageFile);

    //return the image size:
    Size Image;
    Image.Width=width;
    Image.Height=height;
    return Image;
}

lets see the mark for we see the size values is on:
"SOF0 (Start Of Frame 0) marker:"
i must test and see where is the 'SOF0'.
so i did these loop:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
size_t index =0;

        do
        {
            if( strcmp(header, "SOF0")==0)
            {
                printf("hello");
                width = *(int*)&header[index+2];
                height= *(int*)&header[index+4];
                break;
            }
            index++;
        }while(index<strlen(header));
        // extract image height and width from header
        printf("File format JPG:\nWidth: %d\nHeight: %d", width,height);

is my comparation method correct?
is my comparation method correct?


Have you even looked at a sample file using a hex editor/dumper?

Here is the first few hundred bytes of a random jpeg. Do you see your "SOFO" anywhere within this small section of this particular file?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
00000000   FF D8 FF E0  00 10 4A 46  49 46 00 01  02 01 00 48  00 48 00 00  ......JFIF.....H.H..
00000014   FF EE 00 0E  41 64 6F 62  65 00 64 40  00 00 00 01  FF DB 00 84  ....Adobe.d@........
00000028   00 02 02 02  02 02 02 02  02 02 02 03  02 02 02 03  04 03 02 02  ....................
0000003C   03 04 05 04  04 04 04 04  05 06 05 05  05 05 05 05  06 06 07 07  ....................
00000050   08 07 07 06  09 09 0A 0A  09 09 0C 0C  0C 0C 0C 0C  0C 0C 0C 0C  ....................
00000064   0C 0C 0C 0C  0C 01 03 03  03 05 04 05  09 06 06 09  0D 0A 09 0A  ....................
00000078   0D 0F 0E 0E  0E 0E 0F 0F  0C 0C 0C 0C  0C 0F 0F 0C  0C 0C 0C 0C  ....................
0000008C   0C 0F 0C 0C  0C 0C 0C 0C  0C 0C 0C 0C  0C 0C 0C 0C  0C 0C 0C 0C  ....................
000000A0   0C 0C 0C 0C  0C 0C 0C 0C  0C 0C FF C0  00 11 08 00  5D 00 5E 03  ................].^.
000000B4   01 11 00 02  11 01 03 11  01 FF DD 00  04 00 0C FF  C4 01 A2 00  ....................
000000C8   00 00 07 01  01 01 01 01  00 00 00 00  00 00 00 00  04 05 03 02  ....................
000000DC   06 01 00 07  08 09 0A 0B  01 00 02 02  03 01 01 01  01 01 00 00  ....................
000000F0   00 00 00 00  00 01 00 02  03 04 05 06  07 08 09 0A  0B 10 00 02  ....................
00000104   01 03 03 02  04 02 06 07  03 04 02 06  02 73 01 02  03 11 04 00  .............s......
00000118   05 21 12 31  41 51 06 13  61 22 71 81  14 32 91 A1  07 15 B1 42  .!.1AQ..a"q..2.....B 


No, because it's not there.

By the way even your "bitmap" reading code looks flawed as well. I suggest that you stop trying to handle the multiple file types in one function and let the user tell you the file name with the proper extension and then use the provided extension to call the appropriate functions for the different types of files.

And when dealing with graphics files you need to know the type of integer ordering, low byte - high byte or high byte - low byte. A lot of the modern graphic files use network byte ordering.

By the way your "graphics" package is of no consequence for anything to do with these graphic formats, since your "graphics" package predates all of the mentioned graphic formats. I really suggest you drop that fossil and find a modern package that will help you with this kind of endeavor.


Sigh.

GIF dimensions are easy.

JFIF is also pretty easy, but you must traipse the tag tree for the SOF to avoid reading any thumbnail's dimensions.

Here're a couple of fairly trimmed-down methods to find image dimensions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <ciso646>
#include <fstream>
#include <iostream>
#include <string>

namespace little_endian {
  unsigned read_word( std::istream& ins )
  {
    unsigned a = ins.get();
    unsigned b = ins.get();
    return b << 8 | a;
  }
}

namespace big_endian {
  unsigned read_word( std::istream& ins )
  {
    unsigned a = ins.get();
    unsigned b = ins.get();
    return a << 8 | b;
  }
}

bool gif_size( const std::string& filename, int& width, int& height )
{
  std::ifstream f( filename, std::ios::binary );

  // must be a GIF
  std::string s( 6, '\0' );
  f.read( &s[0], 6 );
  if ((s != "GIF89a") and (s != "GIF97a")) return false;

  // next four bytes are the image dimensions
  width  = little_endian::read_word( f );
  height = little_endian::read_word( f );

  return f.good();
}

bool jpg_size( const std::string& filename, int& width, int& height )
{
  std::ifstream f( filename, std::ios::binary );

  // must be a JFIF
  if (big_endian::read_word( f ) != 0xFFD8) return false;

  while (f)
  {
    // seek for next marker
    int b;
    while (f and (     f.get()  != 0xFF)) /* no body */ ;
    while (f and ((b = f.get()) == 0xFF)) /* no body */ ;

    // the SOF marker contains the image dimensions
    if ((0xC0 <= b) and (b <= 0xCF) and (b != 0xC4) and (b != 0xC8) and (b != 0xCC))
    {
      f.seekg( 3, std::ios::cur );
      width  = big_endian::read_word( f );
      height = big_endian::read_word( f );
      return f.good();
    }

    // Otherwise we must skip stuff (like thumbnails...)
    else
    {
      f.seekg( big_endian::read_word( f ) - 2, std::ios::cur );
    }
  }

  // EOF: could not find SOF
  return false;
}

int main( int argc, char** argv )
{
  int width, height;
  if (gif_size( argv[1], width, height )
  or  jpg_size( argv[1], width, height ))
  {
    std::cout << width << "," << height << "\n";
    return 0;
  }

  std::cerr << "unrecognized or corrupt image\n";
  return 1;
}

Hope this helps.

[edit] Attribution: https://wiki.tcl-lang.org/page/Reading+JPEG+image+dimensions
Last edited on
Duthomhas: i'm sorry, but can you explain to me the little_endian() and big_endian() functions?
what i understands is the Big Endian is from 0 to 10 and the Little Endian is from 10 to 0... they are the data order
Last edited on
Okay do you understand why the order makes a difference?

Do you know what "order" your computer uses?

Do you know what "order" the various graphics types use?



Do you understand what happens when you shift an unsigned value left 8 bits?

Do you understand what happens when you OR one unsigned value to another?



Pages: 123