how read the GIF and JPG image size?

Pages: 123
sorry no...
No what?

I asked multiple questions, don't you understand any of the issues I asked?

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?


i'm sorry i don't know, because i never study about it i even didn't knew about it
No what? I asked multiple questions, don't you understand any of the issues I asked?

The guy is retarded.
Lets try with an example:
When we write "347" we mean (in base 10 number system)
100*3 + 10*4 + 7

Think what happens if "reverse the order" so that "347" means 3 + 10*4 + 100*7.
(That is 743 in our normal order.)

Integer value is usually stored in more than one byte, just like the "347" was written with three digits.
Some systems take the first byte of an integer as the least important bits.
Some systems take the first byte of an integer as the most important bits.

Does that help you see why the order (that is used) does make a difference?
thank you so much for the explication.. thank you
WHY do you need to create your own image manipulation functions? Even reading a bitmapped image from a file is complicated, and a BMP is one of the simplest image formats.

A class for reading a bitmap using Windows GDI, header file (written for Win98):
Bitmap.hpp
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
#pragma once

#include <windows.h>

// custom data types
struct BITMAPINFO_256
{
   BITMAPINFOHEADER bmiHeader;
   RGBQUAD          bmiColors[256];
};

class Bitmap
{
protected:
   HBITMAP m_hBitmap;
   int     m_iWidth, m_iHeight;

   void Free();

public:
            Bitmap();
            Bitmap(HDC hDC, LPCTSTR szFileName);
            Bitmap(HDC hDC, UINT uiResID, HINSTANCE hInstance);
            Bitmap(HDC hDC, int iWidth, int iHeight, COLORREF crColor = RGB(0, 0, 0));
   virtual ~Bitmap();

   BOOL Create(HDC hDC, LPCTSTR szFileName);
   BOOL Create(HDC hDC, UINT uiResID, HINSTANCE hInstance);
   BOOL Create(HDC hDC, int iWidth, int iHeight, COLORREF crColor);
   void Draw(HDC hDC, int x, int y);

   int  GetWidth()  { return m_iWidth; };
   int  GetHeight() { return m_iHeight; };
};

The code needed to create a bitmap object from a file name, the rest of the code is elided:
Bitmap.cpp
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
99
100
101
102
103
104
105
106
107
#include "Bitmap.hpp"

Bitmap::Bitmap()
   : m_hBitmap(NULL), m_iWidth(0), m_iHeight(0)
{ }


// create a bitmap from a file
Bitmap::Bitmap(HDC hDC, LPCTSTR szFileName)
   : m_hBitmap(NULL), m_iWidth(0), m_iHeight(0)
{
   Create(hDC, szFileName);
}

Bitmap::~Bitmap()
{
   Free();
}

void Bitmap::Free()
{
   // delete the bitmap graphics object
   if (m_hBitmap != NULL)
   {
      DeleteObject(m_hBitmap);
      m_hBitmap = NULL;
   }
}


BOOL Bitmap::Create(HDC hDC, LPCTSTR szFileName)
{
   // free any previous bitmap info
   Free();

   // open the bitmap file
   HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

   if (hFile == INVALID_HANDLE_VALUE)
   {
      return FALSE;
   }

   // read the bitmap file header
   BITMAPFILEHEADER bmfHeader;
   DWORD            dwBytesRead;
   BOOL             bOK = ReadFile(hFile, &bmfHeader, sizeof(BITMAPFILEHEADER),
                                   &dwBytesRead, NULL);

   if ((!bOK) || (dwBytesRead != sizeof(BITMAPFILEHEADER)) || (bmfHeader.bfType != 0x4D42))
   {
      CloseHandle(hFile);
      return FALSE;
   }

   BITMAPINFO* pBitmapInfo = (BITMAPINFO*) (new BITMAPINFO_256);

   if (pBitmapInfo != NULL)
   {
      // read the bitmap info header
      bOK = ReadFile(hFile, pBitmapInfo, sizeof(BITMAPINFOHEADER), &dwBytesRead, NULL);

      if ((!bOK) || (dwBytesRead != sizeof(BITMAPINFOHEADER)))
      {
         CloseHandle(hFile);
         Free();

         return FALSE;
      }

      // store the width and height of the bitmap
      m_iWidth  = (int) pBitmapInfo->bmiHeader.biWidth;
      m_iHeight = (int) pBitmapInfo->bmiHeader.biHeight;

      // skip (forward or backward) to the color info, if necessary
      if (pBitmapInfo->bmiHeader.biSize != sizeof(BITMAPINFOHEADER))
      {
         SetFilePointer(hFile, pBitmapInfo->bmiHeader.biSize - sizeof(BITMAPINFOHEADER), NULL, FILE_CURRENT);
      }

      // read the color info
      bOK = ReadFile(hFile, pBitmapInfo->bmiColors, pBitmapInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD),
                     &dwBytesRead, NULL);

      // get a handle to the bitmap and copy the image bits
      PBYTE pBitmapBits;

      m_hBitmap = CreateDIBSection(hDC, pBitmapInfo, DIB_RGB_COLORS, (PVOID*) &pBitmapBits, NULL, 0);

      if ((m_hBitmap != NULL) && (pBitmapBits != NULL))
      {
         SetFilePointer(hFile, bmfHeader.bfOffBits, NULL, FILE_BEGIN);

         bOK = ReadFile(hFile, pBitmapBits, pBitmapInfo->bmiHeader.biSizeImage, &dwBytesRead, NULL);

         if (bOK)
         {
            return TRUE;
         }
      }
   }

   // something went wrong, so cleanup everything
   Free();
   return FALSE;
}

The author admits he needed help to get the correct code for this.

Leveraging the GDI features makes for a lot less error-prone code:
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
BOOL Bitmap::Create(LPCTSTR szFileName)
{
   // free any previous bitmap info
   Free();

   // load the bitmap file
   m_hBitmap = (HBITMAP) LoadImage(NULL, szFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);

   if (m_hBitmap == NULL)
   {
      // something went wrong, so cleanup everything
      Free();

      return FALSE;
   }

   BITMAP bitmap;

   GetObject(m_hBitmap, sizeof(BITMAP), &bitmap);

   // store the width and height of the bitmap
   m_iWidth  = (int) bitmap.bmWidth;
   m_iHeight = (int) bitmap.bmHeight;

   return TRUE;
}

Which version would you prefer to use? I know which one I'd use. I know which one MS recommends using.

HINT: It isn't the first version.

GDI+ extends the types of image formats that can be used.
https://docs.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-types-of-bitmaps-about

If you need image manipulation for an OS other than Windows there are libraries available. Don't reinvent the wheel, especially when you are not an expert programmer.
now i have 1 working code for getting the BMP image size(the method that i use is file reading manually):
1
2
3
4
5
6
7
8
9
10
11
12
13
if(strFormat== "bmp"|| strFormat=="BMP")
    {
        string test=little_endianstring::read_word( FileImage,2 );

        if(test=="BM")
        {
            FileImage.seekg(18);
            width = little_endian::read_word( FileImage );
            FileImage.seekg(22);
            height= little_endian::read_word( FileImage );
            printf("File format BMP:\nWidth: %d\nHeight: %d", width,height);
        }
    }
i did the same for ico files:
1
2
3
4
FileImage.seekg( 6 );
            height = little_endian::read_word( FileImage );
            FileImage.seekg( 7);
            width  = little_endian::read_word( FileImage );

but the output is zero, zero.
i did the same and i know the file uses a little endian method.
i get the file position from here: https://en.wikipedia.org/wiki/ICO_(file_format)
I thought we were just getting image dimensions...
true... the 6, from link, i think, is the position for i get the image width.
but corre me on these lines, is for a learn more and understand what i did wrong
Last edited on
i did the same for ico files:

Why?

The ico file structure is not the same as a bmp file.

i did the same and i know the file uses a little endian method.

So?

Don't you realize that the sizes of the images are contained in one byte, not two or more? I'd guess this is why taking someone else's code and using it without understanding exactly what it is doing is problematic.

i get the file position from here: https://en.wikipedia.org/wiki/ICO_(file_format)

Also doesn't the first image's ICONDIRENTRY structure (the part that holds the height and width) start at offset 7?

Maybe you need to study your documentation a little closer?

the offset is 7, but the position isn't the byte counted until there?
What? Your question makes no sense to me, please rephrase.

i get the GIF and BMP and JPG images size.
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
if(strFormat== "bmp"|| strFormat=="BMP")
    {
        string test=little_endianstring::read_word( FileImage,2 );

        if(test=="BM")
        {
            FileImage.seekg(18);
            width = little_endian::read_word( FileImage );
            FileImage.seekg(22);
            height= little_endian::read_word( FileImage );
            printf("File format BMP:\nWidth: %d\nHeight: %d", width,height);
        }
    }
else if(strFormat== "JPG"|| strFormat=="jpg" || strFormat== "JPEG" || strFormat== "jpeg" )
    {
        //is JPEG:
        // must be a JFIF
        if (big_endian::read_word( FileImage ) != 0xFFD8)
        {
            width=0;
            height=0;
        }
        else
        {
            while (FileImage)
            {
                // seek for next marker
                int b;
                while (FileImage and (     FileImage.get()  != 0xFF)) /* no body */ ;
                while (FileImage and ((b = FileImage.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))
                {
                    FileImage.seekg( 3, std::ios::cur );
                    height = big_endian::read_word( FileImage );
                    width  = big_endian::read_word( FileImage );
                }

                // Otherwise we must skip stuff (like thumbnails...)
                else
                {
                  FileImage.seekg( big_endian::read_word( FileImage ) - 2, std::ios::cur );
                }
              }
        }
        // extract image height and width from header
        cout <<"File format JPG:\n" << "Width: " << width << "\nHeight: " << height;
    }

    else if(strFormat== "GIF"|| strFormat=="gif")
    {
        std::string s( 6, '\0' );
        FileImage.read( &s[0], 6 );
        if ((s != "GIF89a") and (s != "GIF97a"))
        {
            width=0;
            height=0;
        }
        else
        {
            // next four bytes are the image dimensions
            width  = little_endian::read_word( FileImage );
            height = little_endian::read_word( FileImage );
        }

        printf("File format GIF:\nWidth: %d\nHeight: %d", width,height);
    }

and they work.
from what i have learned, i try the same for ICO from https://en.wikipedia.org/wiki/ICO_(file_format)
from that i know the file uses the little-endian method and the ICONDIRENTRY structure have the image size.
in these file the position byte is 7 for width and 8 for the height:
1
2
3
4
5
6
7
8
9
10
11
12
else if(strFormat== "ICO"|| strFormat=="ico")
    {
        FileImage.seekg(2);
        if(little_endian::read_word( FileImage )==1)//testing if is realy an ICO
        {
            FileImage.seekg( 7, std::ios::cur );
            height = little_endian::read_word( FileImage );
            width  = little_endian::read_word( FileImage );

            cout <<"File format ICO:\n" << "Width: " << width << "\nHeight: " << height;
        }
    }

but i get the wrong results.... the number is too big....
so what i'm doing wrong?
if the h/w are in 7/8 bytewise, then 1) it cannot have an endian issue, which shows that you do not understand endian even after all this ^^^ chatter about it, and 2) read-word is probably wrong: word is either 'int' or 'register size on your machine' (8 bytes if a modern computer) or something like that. Its not one byte, for sure. just read 1 unsigned char. Or call read-word and peel off the 2 bytes you need from the read-word call.
Last edited on
but i get the wrong results.... the number is too big....
so what i'm doing wrong?

Pretty much everything.

What do you think little_endian::read_word( FileImage ); is actually doing?

What do you think FileImage.seekg( 7, std::ios::cur ); is actually doing?

Do you realize that the first ICONDIRENTRY structure entry starts right after the ICONDIR structure?

Do you realize that there may be multiple images contained within a single file?

"What do you think little_endian::read_word( FileImage ); is actually doing?"
moves de last bit to the 1st, by 8 positions.

"What do you think FileImage.seekg( 7, std::ios::cur ); is actually doing?"
moves the position file to 7(or on 7 byte).

"Do you realize that the first ICONDIRENTRY structure entry starts right after the ICONDIR structure?"
that's why i counted 6(even that before i said 7, i get the wrong values too).

"Do you realize that there may be multiple images contained within a single file?"
even if theres more than 1, i'm just reading the 1st one
Last edited on
"What do you think little_endian::read_word( FileImage ); is actually doing?"
moves de last bit to the 1st, by 8 positions.

So you really don't understand what the function is actually doing.

It is not moving the last "bit" to the first by 8 positions.

First do you know the difference between a byte and a bit?

Look closely at the function in question:

1
2
3
4
5
6
7
8
namespace little_endian {
  unsigned read_word( std::istream& ins )
  {
    unsigned a = ins.get();
    unsigned b = ins.get();
    return b << 8 | a;
  }
}


Do you understand that ins.get() reads a single character (in this case a single byte).

So then it follows that the function is reading two different bytes into two different variables, right? That "two" is a very important observation.

It then shifts the second byte left by 8 bits, don't forget that unsigned, is actually an unsigned int that has a maximum value of at least 65535 (0xFFFF). So if the value read was 0x1 you have "0000 0001" in binary.

Now when you shift this value left by 8 bits you would have "0001 0000".

Now say that the value read for a was 2 ("0010), when this value is ORed with b you would have "0001 0010" or decimal 18, or 0x12.

Does this make sense to you so far?

Now remember I said that "two" was important?

How many bytes does it take to hold one of the values of interest in this image file?

"What do you think FileImage.seekg( 7, std::ios::cur ); is actually doing?"
moves the position file to 7(or on 7 byte).

No, it moves to a position 7 bytes from the current position.

What is your current position?

"Do you realize that the first ICONDIRENTRY structure entry starts right after the ICONDIR structure?"
that's why i counted 6(even that before i said 7, i get the wrong values too).

So you counted 6, do you understand that this puts you at the last byte of the ICONDIR structure, not at the beginning of first ICONDIRENTRY structure?

You're getting the wrong values because you're reading two bytes.




Pages: 123