Thread: Why is file size of bmp always zero?

  1. #1
    C lover
    Join Date
    Oct 2007
    Location
    Virginia
    Posts
    266

    Why is file size of bmp always zero?

    I've been looking into the file structure of BMP images and everything I'm reading says that the 4 bytes following the signature are designated as the filesize of the bmp file... It's always zero for me regardless of the BMP file. The signature is always correct though. What gives?

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <stdint.h>
    
    #define BUF_SIZ 1024
    
    typedef struct
    {
        uint16_t sig;
        uint32_t filesize;
        uint16_t reserved1;
        uint16_t reserved2;
        uint32_t offset;
    
    }BitMapFileHeader;
    
    int main(int argc, char ** argv)
    {
    
        FILE * rdfile;
        char rdbuffer[BUF_SIZ];
        size_t rdbytes;
        size_t filesize;
        BitMapFileHeader * header;
    
        if(!(rdfile = fopen("test.bmp", "r")))
        {
    
            fprintf(stderr, "Error opening file\n");
            exit(EXIT_FAILURE);
    
        }
    
        fseek(rdfile, 0, SEEK_END);
        filesize = ftell(rdfile);
        rewind(rdfile);
    
        //printf("Filesize: %u bytes\n", filesize);
    
        if((rdbytes = fread(rdbuffer, 1, BUF_SIZ, rdfile)))
        {
    
            header = (BitMapFileHeader *) rdbuffer;
    
            fprintf(stdout,
                    "Signature: %c%c\n"
                    "FileSize: %u\n"
                    "Reserved1: %u\n"
                    "Reserved2: %u\n"
                    "Offset: %u\n\n\n",
                    header->sig, (header->sig >> 8),
                    header->filesize,
                    header->reserved1,
                    header->reserved2,
                    header->offset);
    
    
    
        }
        else
        {
    
            fprintf(stderr, "fread:", strerror(errno));
            fclose(rdfile);
            exit(EXIT_FAILURE);
    
        }
    
    #if 0
        while(rdbytes = fread(rdbuffer, 1, BUF_SIZ, rdfile))
        {
    
            fwrite(rdbuffer, 1, rdbytes, stdout);
    
        }
        if(rdbytes == 0)
        {
    
            fprintf(stderr, "fread:", strerror(errno));
            fclose(rdfile);
            exit(EXIT_FAILURE);
        }
    #endif
    
        fclose(rdfile);
    
        return 0;
    }

  2. #2
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Apparently sig in your struct is being padded to 32 bits. So when you fread the struct the BM is going into sig and the first two bytes of filesize are going into the padding after sig, leaving only the last two bytes in the high-order bytes of filesize. Due to the litte-endian byte-order of the integer as stored in the bmp and the fact that your test bmps are (I'm guessing) less than 65536 bytes in size, you end up with a displayed value of 0.

    There are two ways to correct this. You can instruct the compiler not to pad the structs with a pragma. This is implementation-specific, but you might try:
    Code:
    #pragma pack(1)
    The (somewhat) more portable solution is to read each of the members separately with it's own fread. This is still not completely portable since if you're on a machine with the opposite endianness as the data in the BMP then you'll have to swap the bytes around too.

    BTW. there's no need for rdbuffer. You can (if you go the pack-it-up-and-read-the-struct route) read it directly into header.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  3. #3
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by Syscal View Post
    I've been looking into the file structure of BMP images and everything I'm reading says that the 4 bytes following the signature are designated as the filesize of the bmp file... It's always zero for me regardless of the BMP file. The signature is always correct though. What gives?

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <stdint.h>
    
    #define BUF_SIZ 1024
    
    typedef struct
    {
        uint16_t sig;
        uint32_t filesize;
        uint16_t reserved1;
        uint16_t reserved2;
        uint32_t offset;
    
    }BitMapFileHeader;
    
    int main(int argc, char ** argv)
    {
    
        FILE * rdfile;
        char rdbuffer[BUF_SIZ];
        size_t rdbytes;
        size_t filesize;
        BitMapFileHeader * header;
    
        if(!(rdfile = fopen("test.bmp", "r")))
        {
    
            fprintf(stderr, "Error opening file\n");
            exit(EXIT_FAILURE);
    
        }
    
        fseek(rdfile, 0, SEEK_END);
        filesize = ftell(rdfile);
        rewind(rdfile);
    
        //printf("Filesize: %u bytes\n", filesize);
    
        if((rdbytes = fread(rdbuffer, 1, BUF_SIZ, rdfile)))
        {
    
            header = (BitMapFileHeader *) rdbuffer;
    
            fprintf(stdout,
                    "Signature: %c%c\n"
                    "FileSize: %u\n"
                    "Reserved1: %u\n"
                    "Reserved2: %u\n"
                    "Offset: %u\n\n\n",
                    header->sig, (header->sig >> 8),
                    header->filesize,
                    header->reserved1,
                    header->reserved2,
                    header->offset);
    
    
    
        }
        else
        {
    
            fprintf(stderr, "fread:", strerror(errno));
            fclose(rdfile);
            exit(EXIT_FAILURE);
    
        }
    
    #if 0
        while(rdbytes = fread(rdbuffer, 1, BUF_SIZ, rdfile))
        {
    
            fwrite(rdbuffer, 1, rdbytes, stdout);
    
        }
        if(rdbytes == 0)
        {
    
            fprintf(stderr, "fread:", strerror(errno));
            fclose(rdfile);
            exit(EXIT_FAILURE);
        }
    #endif
    
        fclose(rdfile);
    
        return 0;
    }
    First of all, anytime you read a structure from a file in raw binary, you have to think about structure padding that may be added by the compiler. Most compilers provide some sort of means to override the defaults (ie: #pragma pack, et al) for such cases. Second, if you want your code to be portable, you should take into account endian issues (for the BMP format that means reversing bytes on big-endian machines). For both of the above problems you might consider just reading the file byte by byte to build up the data structures. Finally, open the file with a hex-editor while you work - makes debugging so much easier...
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  4. #4
    Ultraviolence Connoisseur
    Join Date
    Mar 2004
    Posts
    555
    EDIT: Explained more clearly above.
    Last edited by nonpuz; 10-06-2013 at 10:41 PM. Reason: Point was redundant and had some bad information

  5. #5
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    Short of searching for a library, this is how I would go about reading a BMP header: http://codepad.org/tAfZBQed (Uploaded to codepad since the website seems to think I didn't use [code] tags.)

  6. #6
    C lover
    Join Date
    Oct 2007
    Location
    Virginia
    Posts
    266
    #pragma pack(1) did the trick... I appreciate the help guys. Interesting I never heard of structs being padded like this. Time to do some further research.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Just remember that there is no pragma to fix endian issues (as Sebastiani pointed out in post #3).

    Also, a packed structure is likely to have a run-time performance penalty (the padding holes were there to begin with to make it efficient, ergo removing the holes must be less efficient).
    It's not likely to be an issue if you just read/write the struct, but if you start passing it around your entire program, there may be some cost.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    C lover
    Join Date
    Oct 2007
    Location
    Virginia
    Posts
    266
    So here's another question... Why aren't the other fields padded as well? sizeof(BitMapFileHeader) returns 16 (2 additional bytes from the padding of sig).

    Additionally, fread on the header is producing the same problem:

    Code:
    if((rdbytes = fread(&bmpheader, 1, BMP_HDR_SIZ, rdfile)))
        {
    
            fprintf(stdout,
                    "Signature: %c%c\n"
                    "FileSize: %u\n"
                    "Reserved1: %u\n"
                    "Reserved2: %u\n"
                    "Offset: %u\n\n\n",
                    bmpheader.sig, (bmpheader.sig >> 8),
                    bmpheader.filesize,
                    bmpheader.reserved1,
                    bmpheader.reserved2,
                    bmpheader.offset);
    
    
    
        }
    Edit: I suppose the post mentioned above was just saying that there was no need for the read buffer at all. Looks like #pragma pack(1) is the best way.
    Last edited by Syscal; 10-07-2013 at 08:11 PM.

  9. #9
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Because different types have different alignment restrictions. 16-bit types are typically required to be aligned on 16-bit boundaries, 32-bit types on 32-bit boundaries. Thus, there is a gap after sig, to move to a 32-bit alignment for filesize, then no gap after filesize, and none after reserved1 because reserved2 is 16-bit and can itself fill in the "gap" required to align offset on a 32-bit boundary. More info: Data structure alignment - Wikipedia, the free encyclopedia.

  10. #10
    C lover
    Join Date
    Oct 2007
    Location
    Virginia
    Posts
    266
    Ah hah! It makes sense to me now. Great read!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. send file size and then the file
    By polslinux in forum C Programming
    Replies: 9
    Last Post: 06-26-2012, 01:44 AM
  2. Replies: 2
    Last Post: 03-05-2012, 10:35 AM
  3. Replies: 16
    Last Post: 04-20-2009, 04:33 PM
  4. Replies: 3
    Last Post: 08-13-2006, 05:58 AM
  5. File Size and File Size on Disk
    By DavidP in forum A Brief History of Cprogramming.com
    Replies: 4
    Last Post: 12-15-2001, 08:03 PM