| Bitmap (.bmp) File Format Explained by bkenwright@xbdev.net   One of the most popular...and of course simplest file formats today, is the 
bmp file format.  It comes in a number of flavours...which include 1bit.. 4 
bit...16 bit...32bit..etc  There's is also a compressed version of the bmp 
format, using run length encoding.  But don't worry, we'll explain all that 
as we go along.   Lets start by explaining a simple picture, and how its broken up.... If your reading this tutorial on your pc screen...well your well familiar 
that your screen is made up of pixels....where each pixel has a Red, Green Blue 
value (RGB) which makes up the colour of that pixel.  You have a lot of 
pixels on that screen!....lots and lots.... lets pick a nice number.... 640x480 
pixels...     Once you have a grasp of what those things....I mean pixels are...its just a 
matter of understanding how the bitmap file stores them.   The great thing about the bmp format is how it arranges these pixels....there 
is a header part...which is the first few bytes...that tells us the width, 
height etc of the image...then we would just have the raw data following 
this....simple eh?  Well its a little more complex than that if you use the 
encoded version or the palette version.. but for the 32 and 24 bit versions its 
exactly that.   Which type of bmp should we start with?... Well I think the best way is to 
start simple....which is the simplest?  Its the 24bit version of the bmp 
file format...well I think it is..  But don't worry, we'll do the other 
types...1 bit....8 bit etc.   Lets do a bit of code to get a feel for this bmp stuff....   
  
    | Code: main.cpp |  
    | 
    
    //////////////////////////////////////////////////////////////////////////////////////// 
    
    //                                                                                    
    // 
    
    // File: main.cpp                                                                     
    // 
    
    // Author: bkenwright@xbdev.net                                                       
    // 
    
    //                                                                            
            // 
    
    //////////////////////////////////////////////////////////////////////////////////////// 
    
      
    
    #include 
    <stdio.h>                             // So we can 
    use fopen and fread 
    
      
    
      
    
    // Simple Debug Feedback - writes to a simple text file located where the 
    exe is. 
    
    void 
    debug(char* str) 
    { 
          
    FILE* fp = fopen("info.txt", "a+"); 
          
    fprintf(fp, "%s\n", str); 
          
    fclose(fp); 
    }// 
    End of debug(..) 
    
      
    
      
    
    char 
    buf[500]; // Temp buffer for text output 
    
      
    
    // Program Entry Point - Where we always start! 
    
    void 
    main() 
    { 
          
    FILE* fp = fopen("cross.bmp", "rb"); 
      
         
    char readbuf[2]; 
    // Temp Buffer 
         
    //      +-  Buffer to put the data in 
         
    //      |      +- Size of each value read in bytes 
    (1 byte each) 
         
    //      |      |   +- How many times to read in 
    the value (e.g. twice read in 1 byte) 
         
    //      |      |   |    +- Stream souce 
         
    //      |      |   |    | 
          
    fread(readbuf, 1,  2,  fp); 
      
          
    debug("First Two Bytes:"); 
          
    sprintf(buf, "%c %c", readbuf[0], readbuf[1]); 
          
    debug(buf); 
      
          
    fclose(fp); 
    }// 
    End of main() |    
  
    | Output: info.txt |  
    | First Two Bytes: B M
 |    What on earth...well its simple...and it gives us a starting code from which 
we can explore the bmp file format.  All that I've done is read in the 
first two bytes of any bmp file and write them to an output file...in the above 
case called 'info.txt'.  As all bitmap files have two bytes with 'B' and 
'M' at the start of the file....so that where sure its a bmp file.  You can 
also open the bmp file in notepad and view it in there....it will be all 
jibberish...but you'll notice that the first two bytes are B and M.     Starting from common ground is a good think....now rather than just use any 
random bmp file...I think its best to create a custom one and then you know what 
your looking for when you read in the data...that way if the bytes or bits arn't 
aligned, then you'll now about it right away.  So open up your image editor 
and create a 24 bit bitmap that's 8x8 pixels wide as shown below:   
  
    | Image: cross.bmp |  
    |  |    Of course you can use your own demo image...but I think its best to start 
small :)  We can always improve and alter it as we go along.   
  
    | Code: main.cpp |  
    |   
    
    #include 
    <stdio.h>                             // So we can 
    use fopen and fread 
    
      
    
    // Simple Debug Feedback - writes to a simple text file located where the 
    exe is. 
    
    void 
    debug(char* str) 
    { 
          
    FILE* fp = fopen("info.txt", "a+"); 
          
    fprintf(fp, "%s\n", str); 
          
    fclose(fp); 
    }// 
    End of debug(..) 
    
      
    
      
    
    char 
    buf[500]; // Temp buffer for text output 
    
      
    
    // Program Entry Point - Where we always start! 
    
    void 
    main() 
    { 
          
    FILE* fp = fopen("cross.bmp", "rb"); 
      
         
    char typeBM[2]; // 
    Temp Buffer 
          
    fread(typeBM, 1,  2,  fp); 
      
          
    sprintf(buf, "typeBM: %c %c", typeBM[0], typeBM[1]); 
          
    debug(buf); 
      
         
    unsigned int 
    iSize; // 4 Bytes 
          
    fread(&iSize, 4, 1, fp); 
      
          
    sprintf(buf, "iSize: %d", iSize); 
          
    debug(buf); 
      
          
    fclose(fp); 
    }// 
    End of main() |    
  
    | Output: info.txt |  
    | typeBM: B M iSize: 246
 |    Ooooo.....so if we read in the next two bytes from our file, as I've done 
before....they represent our exact file size....if you right click on the 
bitmap, and check its size in bytes...you'll see that its 246bytes.  Where 
getting there slowly...   Now bit by bit we read in the header information in...which tells us all the 
information about the bitmap...things like what type of bitmap it is...filesize...image 
width...offset to the image bits.... now rather than do it one by one... you can 
put the data into a structure and read it in, in one go.  Let me show you 
the definitions of the header data, as its broken up into two parts.     
  
  
    
      | BitmapFileHeader |  
      | Name | Size in Bytes | Small Description |  
      | bfType | 2 | Bitmap File Type Signature |  
      | bfSize | 4 | Whole size of the bitmap file on your pc |  
      | bfReserved1 | 2 | Unused - just ignore |  
      | bfReserved2 | 2 | Unused - just ignore |  
      | bfOffSetBits | 4 | Offset from the start of the file to our pixel data |      
  
  
    
      | BitmapInfoHeader |  
      | Name | Size in Bytes | Small Description |  
      | biSize | 4 | Size of this Header - 40 bytes |  
      | biWidth | 4 | Image Width |  
      | biHeight | 4 | Image Height |  
      | biPlanes | 2 |  |  
      | biBitCount | 2 | Bits per pixel - 1,4,8,16,24 or 32 |  
      | biCompression | 4 | Compression type - 0=RGB(No Compression), 1=RLE8, 2=RLE4, 
      3=BITFIELDS |  
      | biSizeImage | 4 | Size of image |  
      | biXPelsPerMeter | 4 | Preferred resolution in pixels per meter |  
      | biYPelsPerMeter | 4 | Preferred resolution in pixels per meter |  
      | biClrUsed | 4 | Number of entries in the colour map that are actually used |  
      | biClrImportant | 4 | Number of significant colours |    There you go.... a full description of the header information for a bitmap 
file - so from the first 54 bytes we can determine the file size...image 
format..width...height etc...which can be extremely useful.  So lets create 
a structure to represent all this data and read it in...and spit it out into our 
text file and see what we have:   
  
    | Code: main.cpp |  
    | 
    
    #include 
    <stdio.h>                             // So we can 
    use fopen and fread 
    
      
    
      
    
    // Simple Debug Feedback - writes to a simple text file located where the 
    exe is. 
    
    void 
    debug(char* str) 
    { 
          
    FILE* fp = fopen("info.txt", "a+"); 
          
    fprintf(fp, "%s\n", str); 
          
    fclose(fp); 
    }// 
    End of debug(..) 
    
      
    
      
    
    char 
    buf[500]; // Temp buffer for text output 
    
      
    
    // All our data structures will be packed on a 1 byte boundary 
    
    #pragma
    pack(1) 
    
    struct 
    stBMFH // BitmapFileHeader 
    { 
         
    char         bmtype[2];    
    // 2 bytes - 'B' 'M' 
         
    unsigned int 
    iFileSize;     // 4 bytes 
         
    short int    
    reserved1;     // 2 bytes 
         
    short int    
    reserved2;     // 2 bytes 
         
    unsigned int 
    iOffsetBits;   // 4 bytes 
    
      
    };// 
    End of stBMFH structure - size of 18 bytes 
    
    #pragma
    pack() 
      
    
    #pragma
    pack(1) 
    
    struct 
    stBMIF // BitmapInfoHeader 
    { 
         
    unsigned int 
    iSizeHeader;    // 4 bytes - 40 
         
    unsigned int 
    iWidth;         // 4 bytes 
         
    unsigned int 
    iHeight;        // 4 bytes 
         
    short int    
    iPlanes;        // 2 bytes 
         
    short int    
    iBitCount;      // 2 bytes 
         
    unsigned int 
    Compression;    // 4 bytes 
         
    unsigned int 
    iSizeImage;     // 4 bytes 
         
    unsigned int 
    iXPelsPerMeter; // 4 bytes 
         
    unsigned int 
    iYPelsPerMeter; // 4 bytes 
         
    unsigned int 
    iClrUsed;       // 4 bytes 
         
    unsigned int 
    iClrImportant;  // 4 bytes 
    
      
    };// 
    End of stBMIF structure - size 40 bytes 
    
    #pragma
    pack() 
      
    
    // Program Entry Point - Where we always start! 
    
    void 
    main() 
    { 
         
    // Read in our header information 
          
    FILE* fp = fopen("cross.bmp", "rb"); 
      
          
    stBMFH BMHF; 
          
    stBMIF BMINFO; 
      
          
    fread(&BMHF,   1, sizeof(stBMFH), fp); 
          
    fread(&BMINFO, 1, sizeof(stBMIF), fp); 
      
          
    fclose(fp); 
      
         
    // Dump or read in data to our txt file. 
         
    // First the File Header Part 
          
    debug("BITMAPFILEHEADER"); 
          
    sprintf(buf, "bmtype: %c %c", BMHF.bmtype[0], BMHF.bmtype[1]); 
          
    debug(buf); 
          
    sprintf(buf, "iFileSize: %d", BMHF.iFileSize); 
          
    debug(buf); 
          
    sprintf(buf, "iOffsetBits: %d", BMHF.iOffsetBits); 
          
    debug(buf); 
      
         
    // Now the Bitmap File Info Header Section 
          
    debug("BITMAPINFOHEADER"); 
          
    sprintf(buf, "iSizeHeader: %d", BMINFO.iSizeHeader); 
          
    debug(buf); 
          
    sprintf(buf, "iWidth: %d", BMINFO.iWidth); 
          
    debug(buf); 
          
    sprintf(buf, "iHeight: %d", BMINFO.iHeight); 
          
    debug(buf); 
          
    sprintf(buf, "iPlanes: %d", BMINFO.iPlanes); 
          
    debug(buf); 
          
    sprintf(buf, "iBitCount: %d", BMINFO.iBitCount); 
          
    debug(buf); 
          
    sprintf(buf, "Compression: %d", BMINFO.Compression); 
          
    debug(buf); 
      
    }// 
    End of main() |    
  
    | Output: info.txt |  
    | BITMAPFILEHEADER bmtype: B M
 iFileSize: 246
 iOffsetBits: 54
 
 BITMAPINFOHEADER
 iSizeHeader: 40
 iWidth: 8
 iHeight: 8
 iPlanes: 1
 iBitCount: 24
 Compression: 0
 |    Well there you have it.... all the header information has been read in... its 
not so bad when you use a structure and just read it in, in one big go :)  
We can see from our output file that we have an image which is 8 pixels wide and 
8 pixels height....its compression value is 0...which tells us that there is no 
compression.  Using this information we can determine what bmp file we have 
on our hands.  Of couse we created the custom 'cross.bmp' file here....so 
this is just confirming what we already know...but try it with some other bitmap 
files...it will give you its secret info of what it is.   On the coding front...those who are sort of new to coding will notice a few 
lines which will scare you...those are the lines which contain
'#pragam pack(1)'...which makes sure our structure 
data follows each other...so exactly after we do a character data, the following 
data will be exactly after it.....aligning on 1 byte boundaries.   Let me give you an example:   
  
  
    
      | 
      
      struct 
      stNotPacked 
      { 
           
      char a; 
           
      int  z; 
      }; 
      // sizeof(stNotPacked) == 8 bytes   | 
      
      #pragma
      pack(1) 
      
      struct 
      stPacked 
      { 
           
      char a; 
           
      int z; 
      }; 
      
      #pragma
      pack() 
      // sizeof(stPacked) == 5 bytes |      As the default for structures in C is to align the data to the following data 
type, so in the above example where we would have a char (1 byte) followed by a 
int (4 bytes)... the char is padded with 3 empty spaces so the int is aligned on 
a 4 byte boundary.   Note: The alignment of data is compiler and platform 
dependent - so be sure to check if you compiling with OS or Linux etc for 
example.   Hmmm...well all we have to do now is read in the pixel data....those red, 
green, blue value things....you haven't forgot have you...hehe..  But how 
do we find in the file where they are?  Well the "iOffsetBits" value we 
read in from our header data tells us exactly that.  It tells us the 
location of the colour bytes.  In the example above note that its 54 
bytes...and remember or header data is also 54 bytes...which tells us that our 
image data comes exactly after or header data in this case.   Where should we put all this data though?  Well I thought I'd create a 
structure called stImage which we can use to hold or image data....and it will 
keep hold of only the essential information.  Storing an array of rgb 
values.... but I'm going to store the colour information with 8 bits (or 1 byte) 
per index colour (red, green and blue = 24 bytes).  So if we read in a 16 
bit bitmap later on, and we decide to store the image in here, we'll convert it.   
  
    | Common Errors: |  
    | 
         
    // Allocate some memory for our image bits 
          
    ImageBits.pARGB = new
    unsigned int[ 
    ImageBits.iWidth * ImageBits.iHeight * 3 ]; 
      
         
    // ERROR ERROR ERROR - Data is DWORD aligned on 
    the width - as when data is saved to disk, the 
          
    // the width is padded with 0's so it aligned to 32 bits....or 4 bytes...so 
    you have to be 
          
    // careful of this 
          
    fread(&(ImageBits.pARGB),   1, ImageBits.iWidth * ImageBits.iHeight * 3, fp);   |    Be careful with the above error, as it won't show in our example as its 8x8 
pixels, so it aligns on the 4 byte boundary - but on occasion you'll open an 
image which isn't aligned, and you'll wonder why!  But don't worry I've 
added 2 lines in which checks for it, using the % modulus operation - which 
tells us how many remainders there are     
  
    | Code: main.cpp
    (DownloadSourceCode) |  
    | 
    
    #include 
    <stdio.h>                             // So we can 
    use fopen and fread 
    
    #include 
    <assert.h>                            // Few 
    simple debugging tests 
    
      
    
      
    
    // Simple Debug Feedback - writes to a simple text file located where the 
    exe is. 
    
    void 
    debug(char* str) 
    { 
          
    FILE* fp = fopen("info.txt", "a+"); 
          
    fprintf(fp, "%s", str); 
          
    fclose(fp); 
    }// 
    End of debug(..) 
    
      
    
      
    
    char 
    buf[500]; // Temp buffer for text output 
    
      
    
    // All our data structures will be packed on a 1 byte boundary 
    
    #pragma
    pack(1) 
    
    struct 
    stBMFH // BitmapFileHeader 
    { 
         
    char         bmtype[2];    
    // 2 bytes - 'B' 'M' 
         
    unsigned int 
    iFileSize;     // 4 bytes 
         
    short int    
    reserved1;     // 2 bytes 
         
    short int    
    reserved2;     // 2 bytes 
         
    unsigned int 
    iOffsetBits;   // 4 bytes 
    
      
    };// 
    End of stBMFH structure - size of 18 bytes 
    
    #pragma
    pack() 
      
    
    #pragma
    pack(1) 
    
    struct 
    stBMIF // BitmapInfoHeader 
    { 
         
    unsigned int 
    iSizeHeader;    // 4 bytes - 40 
         
    unsigned int 
    iWidth;         // 4 bytes 
         
    unsigned int 
    iHeight;        // 4 bytes 
         
    short int    
    iPlanes;        // 2 bytes 
         
    short int    
    iBitCount;      // 2 bytes 
         
    unsigned int 
    Compression;    // 4 bytes 
         
    unsigned int 
    iSizeImage;     // 4 bytes 
         
    unsigned int 
    iXPelsPerMeter; // 4 bytes 
         
    unsigned int 
    iYPelsPerMeter; // 4 bytes 
         
    unsigned int 
    iClrUsed;       // 4 bytes 
         
    unsigned int 
    iClrImportant;  // 4 bytes 
    
      
    };// 
    End of stBMIF structure - size 40 bytes 
    
    #pragma
    pack() 
      
    
    struct 
    stImage 
    { 
         
    unsigned int 
    iWidth; 
         
    unsigned int 
    iHeight; 
      
         
    unsigned int* 
    pARGB; // Alpha Red Green Blue 
    
      
    };// 
    End of stImage 
    
      
    
    // Program Entry Point - Where we always start! 
    
    void 
    main() 
    { 
         
    // Read in our header information 
          
    FILE* fp = fopen("cross.bmp", "rb"); 
      
          
    stBMFH BMFH; 
          
    stBMIF BMINFO; 
      
          
    fread(&BMFH,   1, sizeof(stBMFH), fp); 
          
    fread(&BMINFO, 1, sizeof(stBMIF), fp); 
      
      
         
    // Dump or read in data to our txt file. 
         
    // First the File Header Part 
          
    debug("BITMAPFILEHEADER"); 
          
    sprintf(buf, "bmtype: %c %c\n", BMFH.bmtype[0], BMFH.bmtype[1]); 
          
    debug(buf); 
          
    sprintf(buf, "iFileSize: %d\n", BMFH.iFileSize); 
          
    debug(buf); 
          
    sprintf(buf, "iOffsetBits: %d\n", BMFH.iOffsetBits); 
          
    debug(buf); 
      
         
    // Now the Bitmap File Info Header Section 
          
    debug("BITMAPINFOHEADER"); 
          
    sprintf(buf, "iSizeHeader: %d\n", BMINFO.iSizeHeader); 
          
    debug(buf); 
          
    sprintf(buf, "iWidth: %d\n", BMINFO.iWidth); 
          
    debug(buf); 
          
    sprintf(buf, "iHeight: %d\n", BMINFO.iHeight); 
          
    debug(buf); 
          
    sprintf(buf, "iPlanes: %d\n", BMINFO.iPlanes); 
          
    debug(buf); 
          
    sprintf(buf, "iBitCount: %d\n", BMINFO.iBitCount); 
          
    debug(buf); 
          
    sprintf(buf, "Compression: %d\n", BMINFO.Compression); 
          
    debug(buf); 
      
         
    // Read in our image data 
    
      
         
    //     +- File Stream 
         
    //     |          +- Offset to our data 
         
    //     |          |             +- Where or offset 
    is from (SEEK_CUR, SEEK_END  
         
    //     |          |             
    |                                  or SEEK_SET) 
         
    //     |          |             | 
          
    fseek( fp, BMFH.iOffsetBits, SEEK_SET); 
      
          
    stImage ImageBits; 
          
    ImageBits.iWidth  = BMINFO.iWidth; 
          
    ImageBits.iHeight = BMINFO.iHeight; 
      
         
    // Allocate some memory for our image bits 
          
    ImageBits.pARGB = new
    unsigned int[ 
    ImageBits.iWidth * ImageBits.iHeight]; 
      
          
    assert( !(ImageBits.pARGB == NULL) && "Error allocating memory for image" ); 
    
                 
      
         
    int iNumPaddedBytes = (ImageBits.iWidth * 3) 
    % 4; 
          
    sprintf(buf, "iNumPaddedBytes: %d\n\n", iNumPaddedBytes); 
          
    debug(buf); 
         
    // For example 8*3 = 24...which is 24 bytes.... 
    24/4=6 exactly 
         
    // but if our image was 9 pixels wide, then we'd 
    have: 
         
    // 9*3 = 27, and 27/4= 24 remainder 3, so we would 
    have 1 padded byte 
    
      
         
    for(unsigned
    int  h=0; h<ImageBits.iHeight; h++) 
          { 
    
                for(unsigned
    int  w=0; w<ImageBits.iWidth; w++) 
    
                { 
    
                      // So in this loop - if our data 
    isn't aligned to 4 bytes, then its been padded 
    
                      // in the file so it aligns...so 
    we check for this and skip over the padded 0's 
    
                      // Note here, that the data is 
    read in as b,g,r and not rgb as you'd think! 
    
                      unsigned
    char r,g,b; 
    
                      fread(&b, 1, 1, fp); 
    
                      fread(&g, 1, 1, fp); 
    
                      fread(&r, 1, 1, fp); 
    
                       
    
                      ImageBits.pARGB[ w + h*ImageBits.iWidth ] = (r<<16 | g<<8 
    | b); 
      
    
                }// End of for loop w 
    
      
    
                //If there are any padded bytes - we 
    skip over them here 
    
                if( iNumPaddedBytes != 0 ) 
    
                { 
    
                      unsigned
    char skip[4]; 
    
                      fread(skip, 1, 4 - iNumPaddedBytes, fp); 
    
                }// End of if reading padded bytes 
    
      
          }// 
    End of for loop h 
    
      
         
    // Now to proove that we have all our bytes read 
    in, and of course that they are the 
         
    // bytes that they are suppose to be, we'll write 
    them out to a text file - of course 
         
    // you would only do this for a small bitmap - 
    e.g. our demo cross.bmp bitmap :) 
         
    for(h=0; h<ImageBits.iHeight; h++) 
          { 
    
                for(unsigned
    int  w=0; w<ImageBits.iWidth; w++) 
    
                { 
    
                      unsigned
    char r = (ImageBits.pARGB[ w + h*ImageBits.iWidth 
    ] >> 16) & 0xff; 
    
                      unsigned
    char g = (ImageBits.pARGB[ w + h*ImageBits.iWidth 
    ] >>  8) & 0xff; 
    
                      unsigned
    char b = (ImageBits.pARGB[ w + h*ImageBits.iWidth 
    ] >>  0) & 0xff; 
      
    
                      sprintf(buf, "%.2x%.2x%.2x ", r,g,b); 
    
                      debug(buf); 
      
    
                }// End of for loop w 
    
                debug("\n"); 
          }// 
    End of for loop h 
    
      
         
    delete[] ImageBits.pARGB; 
      
          
    fclose(fp); 
      
    }// 
    End of main() |    
  
    | Output: info.txt |  
    | BITMAPFILEHEADERbmtype: B M iFileSize: 246
 iOffsetBits: 54
 
 BITMAPINFOHEADER
 iSizeHeader: 40
 iWidth: 8
 iHeight: 8
 iPlanes: 1
 iBitCount: 24
 Compression: 0
 iNumPaddedBytes: 0
 
 ff0000 000000 000000 000000 000000 000000 000000 ff0000
 000000 ff0000 000000 000000 000000 000000 ff0000 000000
 000000 000000 ff0000 000000 000000 ff0000 000000 000000
 000000 000000 000000 ff0000 ff0000 000000 000000 000000
 000000 000000 000000 ff0000 ff0000 000000 000000 000000
 000000 000000 ff0000 000000 000000 ff0000 000000 000000
 000000 ff0000 000000 000000 000000 000000 ff0000 000000
 ff0000 000000 000000 000000 000000 000000 000000 ff0000
 |    Can you see the resemblance in our raw text output with our cross.bmp image?  
Well its only to check that where making progress and that we haven't made any 
drastic mistakes.   Whahooo...well we have our image more or less, there is one more detail about 
flipping which I'll mention in a sec.... but with what we have here we could 
create a nice re-usable function called Load24BitBitmap(..) ....   bool Load24BitBitmap(stImage* pImage, char* szFileName);   Where it would return bool true if all went okay, and false if an error 
occured.  Of course you'd add error checking to your image loading function 
so you would check the bitcount and that the image starts with 'B' and 'M' 
etc... but we'll get there.   Upside down?  You can't really see it in the txt output that I've shown 
above... but our image is in fact flipped upside down... so the very first pixel 
we read in, is the bottom, and the last row pixel bytes we read in, is the top 
of our image.  So to fix this, all we have to do is flip our y value as we 
read in our data and it will fix it, as show:   
  
    | 
         
    for(unsigned
    int  h=0; h<ImageBits.iHeight; h++) 
          { 
    
                for(unsigned
    int  w=0; w<ImageBits.iWidth; w++) 
    
                { 
    
                      // So in this loop - if our data 
    isn't aligned to 4 bytes, then its been padded 
    
                      // in the file so it aligns...so 
    we check for this and skip over the padded 0's 
    
                      // Note here, that the data is 
    read in as b,g,r and not rgb as you'd think! 
    
                      unsigned
    char r,g,b; 
    
                      fread(&b, 1, 1, fp); 
    
                      fread(&g, 1, 1, fp); 
    
                      fread(&r, 1, 1, fp); 
    
                       
    
                      //** Flips our data so its the 
    correct way around - note the off by one  **// 
    
                      //** as arrays go from 0 to 
    n-1.                                         **// 
    
                      int hInverted = 
    (ImageBits.iHeight-1) - h;; 
    
                      ImageBits.pARGB[ w + hInverted*ImageBits.iWidth ] = (r<<16 
    | g<<8 | b); 
      
    
                }// End of for loop w 
    
      
    
                //If there are any padded bytes - we 
    skip over them here 
    
                if( iNumPaddedBytes != 0 ) 
    
                { 
    
                      unsigned
    char skip[4]; 
    
                      fread(skip, 1, 4 - iNumPaddedBytes, fp); 
    
                }// End of if reading padded bytes 
    
      
          }// 
    End of for loop h |      So with that one change added we can throw all the code into a nice function 
and give it a run.... Putting our bitmap reading code into bitmap24.h/.cpp we 
find that our main.cpp function suddenly becomes really empty....with the 
exception of our debug code it would only be a few lines long.  Shall we take a look at our 24 bit bmp loader function code:     
  
    | Code: main.cpp
    (DownloadSourceCode) |  
    |   
    
    #include 
    <stdio.h>                             // So we can 
    use fopen and fread 
    
    #include 
    "bitmap24.h"                          // Our 
    function that reads in our 24 bit 
    
                                                   // 
    bitmap 
    
      
    
    // Simple Debug Feedback - writes to a simple text file located where the 
    exe is. 
    
    void 
    debug(char* str) 
    { 
          
    FILE* fp = fopen("info.txt", "a+"); 
          
    fprintf(fp, "%s", str); 
          
    fclose(fp); 
    }// 
    End of debug(..) 
    
      
    
    char 
    buf[500]; // Temp buffer for text output 
    
      
    
    // Program Entry Point - Where we always start! 
    
    void 
    main() 
    { 
      
          
    stImage Image; 
          
    Load24BitBitmap(&Image, "cross.bmp"); 
      
         
    // These lines are nothing more than debug output 
    -------------------------------- 
          
    sprintf(buf, "Width: %d, Height: %d\n\n", Image.iWidth, Image.iHeight); 
          
    debug(buf); 
      
         
    // Now to proove that we have all our bytes read 
    in, and of course that they are the 
         
    // bytes that they are suppose to be, we'll write 
    them out to a text file - of course 
         
    // you would only do this for a small bitmap - 
    e.g. our demo cross.bmp bitmap :) 
         
    for(unsigned
    int h=0; h<Image.iHeight; h++) 
          { 
    
                for(unsigned
    int  w=0; w<Image.iWidth; w++) 
    
                { 
    
                      unsigned
    char r = (Image.pARGB[ w + h*Image.iWidth ] 
    >> 16) & 0xff; 
    
                      unsigned
    char g = (Image.pARGB[ w + h*Image.iWidth ] 
    >>  8) & 0xff; 
    
                      unsigned
    char b = (Image.pARGB[ w + h*Image.iWidth ] 
    >>  0) & 0xff; 
      
    
                      sprintf(buf, "%.2x%.2x%.2x ", r,g,b); 
    
                      debug(buf); 
      
    
                }// End of for loop w 
    
                debug("\n"); 
          }// 
    End of for loop h 
    
      
         
    delete[] Image.pARGB; 
      
    }// 
    End of main() |    
  
    | Output: Info.txt |  
    | Width: 8, Height: 8 
 00ff00 000000 000000 000000 000000 000000 000000 ff0000
 000000 ff0000 000000 000000 000000 000000 ff0000 000000
 000000 000000 ff0000 000000 000000 ff0000 000000 000000
 000000 000000 000000 ff0000 ff0000 000000 000000 000000
 000000 000000 000000 ff0000 ff0000 000000 000000 000000
 000000 000000 ff0000 000000 000000 ff0000 000000 000000
 000000 ff0000 000000 000000 000000 000000 ff0000 000000
 ff0000 000000 000000 000000 000000 000000 000000 ff0000
 |      Its sweet isn't it.... we can now do a 1 bit....4 bit version....and work 
towards creating a full library...  But before we continue, I think there's 
one thing we should do...we should make a GUI windows version where we can open 
a 24 bit bitmap and render it to the screen in its full glory.  Hopefully 
it won't require to much overhead code, but it will help you believe how much 
power this gives us.     
  
    | DownloadSourceCode   
    By adding in some Win32 MFC code we able to create a simple Bitmap Loader 
    application, which we can use to test our 24 Bit Bitmap Loader Function we 
    created earlier.  A screen shot of the application can be seen on the 
    right. |  |      1 Bit Bitmap Our next mission....if you haven't ran off..hehe....is to work on our 1 Bit 
Loader code.....we've done most of the hard work now...its just a matter of 
building from our previous errors.  It would almost be a task of changing a 
few lines from our previous code here...but for one little thing.... 1,4 and 8 
bit bitmaps also store palette information, which is stored as an array of 
RGBQUAD values.... the number of palette values is 2bitcount.   struct RGBQUAD // 4 bytes {         unsigned char alpha, red, green, 
blue; };   This palette information, follows our header file data immediately.... For 
our 1 bit file format here...we should have 2 palette entries...which will be 
referenced by our image data.  Remember our 1 bit image doesn't have to be 
black and white...it can be green and blue for example....any two colours.   So the two starting points of our code are following on from before.... but 
this time we'll create a 1 bit Loading function.   
  
    | code: DownloadSourceCode |  
    | 
    
    bool 
    Load1BitBitmap(stImage* pImage, char* 
    szFileName) 
    { 
      
    }// 
    Load1BitBitmap(..) 
    
      
    
    // Program Entry Point - Where we always start! 
    
    int
    __stdcall WinMain(HINSTANCE, HINSTANCE, 
    LPSTR, int) 
    { 
      
          
    stImage Image; 
          
    Load1BitBitmap(&Image, "cross.bmp"); 
      
    }// 
    End of main() |    In creating our new Load1BitBitmap(..) function....the two main 
conciderations are the alignment of data so its width is on a 32 bit 
boundary...and we skip any padded bytes....second, is the reading in of our 
palette data, and using it for a reference.   Now I read the data in, and store it as a 32Bit ARGB value.....so after we've 
read in each pixel value and discovered its colour, we can delete the palette 
data in this case.  The first part's the same...reading in this header 
data... but then straight after this, we get our palette data.  The tricky 
bit of code to really step through...or maybe print out and look at for a while, 
is the inner loop, which does a bit of bit shifting so that we take each bit and 
get its value.... as we can't read in 1 bit at a time...we the smallest value we 
can read in, is 1 byte (8 bits)...and hence for each 8 bits...we do bit wise 
operations to get the data.     
  
    | code:
    DownloadSouceCode |  
    | 
    
    bool 
    Load1BitBitmap(stImage* pImage, char* 
    szFileName) 
    { 
          // 
    Read in our header information 
          
    FILE* fp = fopen(szFileName, "rb"); 
      
          
    stBMFH BMFH; 
          
    stBMIF BMINFO; 
      
          
    fread(&BMFH,   1, sizeof(stBMFH), fp); 
          
    fread(&BMINFO, 1, sizeof(stBMIF), fp); 
      
         
    // ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** 
    NEW ** NEW ** NEW ** NEW ** NEW ** NEW 
         
    // ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** 
    NEW ** NEW ** NEW ** NEW ** NEW ** NEW 
         
    // Now straight after our header information, 
    follows our Palette Info, which 
         
    // we'll use as we read in our data. 
         
    // 1 bit -> 2^1 = 2 ARGB Palette Entries to read 
    in 
    
      
         
    // Allocate memory for our palette 
         
    unsigned int* 
    pARGB = new 
    unsigned int[2]; 
      
         
    // Read in all the palette values 
          
    fread(pARGB,   2, sizeof(unsigned
    int), fp); 
      
      
         
    // Now read in our image data 
         
    //     +- File Stream 
         
    //     |          +- Offset to our data 
         
    //     |          |             +- Where or offset 
    is from (SEEK_CUR, SEEK_END  
         
    //     |          |             
    |                                  or SEEK_SET) 
         
    //     |          |             | 
          
    fseek( fp, BMFH.iOffsetBits, SEEK_SET); 
      
          
    pImage->iWidth  = BMINFO.iWidth; 
          
    pImage->iHeight = BMINFO.iHeight; 
      
         
    // Allocate some memory for our image bits 
          
    pImage->pARGB = new 
    unsigned int[ pImage->iWidth * pImage->iHeight]; 
      
          
    assert( !(pImage->pARGB == NULL) && "Error allocating memory for image" ); 
      
      
         
    int iNumPaddedBits = (32-(pImage->iWidth * 
    1)) % (4*8); 
      
         
    int iNumPaddedBytes = iNumPaddedBits/8; 
         
    // Bit tricker to work out the number of padded 
    bytes..as remember.. 
         
    // where working with bits...so 8 bits are a byte. 
       
    // So I calculate how many bits will pad the 
    end...bits..not bytes.. 
         
    // then I convert it to bytes, by dividing by 8. 
         
    // Something worth thinking about if your new to 
    C/C++...is the rounding 
         
    // of digits....as notice if we do: 
         
    // 15/8...we get 1 
         
    // 16/8...we get 2 
         
    // As we don't hold decimal places in int's 
         
    // We round down the numbers!  Why...well you 
    really have to look at the code 
         
    // carefully...but if we only use 7 bits for the 
    width...then we read in 
         
    // groups of 8 bits...so we would read in 8 
    bits...leaving 24 for the padding 
    
      
         
    for(unsigned
    int  h=0; h<pImage->iHeight; h++) 
          { 
    
                for(unsigned
    int  w=0; w<pImage->iWidth; w+=8 )
    // 8 pixels at a time 
    
                { 
    
                      // Well the smallest value we 
    can read in, is 1 byte...so we read it in, and 
    
                      // convert the 8 bits to there 
    seperate values 
    
                      unsigned
    char value; 
    
                      fread(&value, 1, 1, fp); 
      
    
                      int i = pImage->iWidth - w 
    ; 
    
                      if( i>8) 
    
                            i=8; 
      
    
                      for(int 
    j=0; j<i; j++) 
    
                      { 
    
                            //** Flips our data so its 
    the correct way around - note the off by one  **// 
    
                            //** as arrays go from 0 
    to n-1.    
    
                            int hInverted = (pImage->iHeight-1) 
    - h;; 
    
                            pImage->pARGB[ (w+j) + hInverted * pImage->iWidth ] 
    = pARGB[(value>>j)&0x01]; 
    
                            // w+j is because in this 
    little inside loop, where reading in 
    
                            // bit at a time....so we 
    read in 8 bits...and we have to share them 
    
      
    
                      }// End for loop j 
    
      
    
                }// End of for loop w 
    
      
    
                //If there are any padded bytes - we 
    skip over them here 
    
                if( iNumPaddedBytes != 0 ) 
    
                { 
    
                      unsigned
    char skip[4]; 
    
                      fread(skip, 1, iNumPaddedBytes, fp); 
    
                }// End of if reading padded bytes 
    
      
          }// 
    End of for loop h 
    
      
         
    delete[] pARGB;
    
    // 
    Delete allocated memory for the palette data 
      
          
    fclose(fp); 
      
         
    return true;
    // All went okay :) 
    
      
    }// 
    Load1BitBitmap(..) |    For the demo's...I did a simple square black and white demo image...and I 
also tested the code with a 33x8 black and white image....just to make sure the 
alignment code was okay.  Again, because I'm using simple test images, it 
means I can single step through the code, and compare with what values I 
expect...and what values I have.     From 1 bit to 4 bit isn't so bad....and 8 bit should be easy....as we read in 
1 byte at a time...so where in fact reading in a pixel at a time and finding its 
palette value as we go along.     {Under Construction}     |