Thread: Loading a bmp file

  1. #1
    myNegReal
    Join Date
    Jun 2005
    Posts
    100

    Loading a bmp file

    I'm having trouble with this one, as easy as the format is, I'm doing something wrong. I have a function here to load a bmp file, taking the filename:
    Code:
    LIMAGE BMPLoader::loadBMP(const char* filename) {
        struct {
            unsigned short int type;
            unsigned int filesize;
            unsigned short int reserved;
            unsigned short int reserved2;
            unsigned int offset;
        } header;
        struct {
            unsigned int headersize;
            unsigned long int width, height;
            unsigned short int planes;
            unsigned short int bitsppx;
            unsigned int compression, imagesize;
            unsigned long int hres, vhres;
            unsigned int numcolors, importantcols;
        } infoheader;
        unsigned char temp;
        char* palette = 0;
        char* imaged = 0;
        LIMAGE image = {0, 0, 0, 0};
        if (filename == 0) return image;
        FILE* file = 0;
        file = fopen(filename, "rb");
        if (file == 0) return image;
        fread(&header, sizeof(header), 1, file);
        if (header.type != BMP_HEAD) {
            fclose(file);
            return image;
        }
        fread(&infoheader, sizeof(infoheader), 1, file);
        if (infoheader.compression != 0) return image; // don't deal with compressed BMPs
        image.bpp = infoheader.bitsppx;
        image.width = infoheader.width;
        image.height = infoheader.height;
        if (infoheader.bitsppx < 16) {
            palette = new char[infoheader.numcolors*4];
            fread(palette, 1, infoheader.numcolors*4, file);
        } else {
            imaged = new char[(image.width*image.height)*(image.bpp/8)];
            fseek(file, header.offset, SEEK_SET);
            fread(imaged, 1, infoheader.imagesize, file);
        }
        /*for (int i=0;i<infoheader.imagesize;i+=3) {
            temp = imaged[i];
            imaged[i] = imaged[i+2];
            imaged[i+2] = temp;
        }*/
        fclose(file);
        image.image = imaged;
        delete [] imaged;
        return image;
    }
    LIMAGE is a struct defined in another header which contains 3 ints (bpp, height, width) and a char*, the actual image data. The commented out for loop causes a problem with memory therefore is commented out for now lol.. if you find something wrong with my function or structs or whatever tell me that'd be great, but my problem is, everything I read in (height, width, bpp, etc) gets assigned the value of these characters: ( then what looks like a b but the vertical line extends further downward and a ". Then I output the values to a file. as a decimal it came to 0 and as a string it came to ˜ý". Any idea why it's not reading values correctly? Thanks in advance

    Note: the function isn't complete, it doesn't read in images with a bpp of less than 16. The image i used to test was 24 and because it doesn't read the value right it thinks it's less than 16.
    Last edited by Ganoosh; 10-03-2005 at 03:33 PM.
    Using Dev-C++ on Windows

  2. #2
    Registered User
    Join Date
    Jun 2003
    Posts
    361
    I found that, when reading the Bitmap File Header and Bitmap Info Header (preceding the pixel data), that I could not read it all in as one header:
    Code:
    fread(&header, sizeof(header), 1, file);
    Even though that is what everyone suggested, and it makes sense that it should work properly, I found I had to resort to reading every value in line by line:
    Code:
    void CompleteHeader(CUSTOMBITMAPHEADER *BitmapHeader, FILE *BinaryIFile)
    {
    	fread(&(BitmapHeader->Type), sizeof(BitmapHeader->Type), 1, BinaryIFile);
    	fread(&(BitmapHeader->Size), sizeof(BitmapHeader->Size), 1, BinaryIFile);
    	fread(&(BitmapHeader->Reserved1), sizeof(BitmapHeader->Reserved1), 1, BinaryIFile);
    	fread(&(BitmapHeader->Reserved2), sizeof(BitmapHeader->Reserved2), 1, BinaryIFile);
    	fread(&(BitmapHeader->OffBits), sizeof(BitmapHeader->OffBits), 1, BinaryIFile);
    	fread(&(BitmapHeader->RemainingSize), sizeof(BitmapHeader->Size), 1, BinaryIFile);
    	fread(&(BitmapHeader->Width), sizeof(BitmapHeader->Width), 1, BinaryIFile);
    	fread(&(BitmapHeader->Height), sizeof(BitmapHeader->Height), 1, BinaryIFile);
    	fread(&(BitmapHeader->Planes), sizeof(BitmapHeader->Planes), 1, BinaryIFile);
    	fread(&(BitmapHeader->BitCount), sizeof(BitmapHeader->BitCount), 1, BinaryIFile);
    	fread(&(BitmapHeader->Compression), sizeof(BitmapHeader->Compression), 1, BinaryIFile);
    	fread(&(BitmapHeader->SizeImage), sizeof(BitmapHeader->SizeImage), 1, BinaryIFile);
    	fread(&(BitmapHeader->XPelsPerMeter), sizeof(BitmapHeader->XPelsPerMeter), 1, BinaryIFile);
    	fread(&(BitmapHeader->YPelsPerMeter),	sizeof(BitmapHeader->YPelsPerMeter), 1, BinaryIFile);
    	fread(&(BitmapHeader->ClrUsed), sizeof(BitmapHeader->ClrUsed), 1, BinaryIFile);
    	fread(&(BitmapHeader->ClrImportant), sizeof(BitmapHeader->ClrImportant), 1, BinaryIFile);
    }
    Also, to avoid any dependancies on Windows.h (it seemed un-necessary to me), I just defined my own structure:
    Code:
    struct CUSTOMBITMAPHEADER
    {
    	unsigned short	Type;
    	unsigned long	Size;
    	unsigned short	Reserved1;
    	unsigned short	Reserved2;
    	unsigned long	OffBits;
    	unsigned long	RemainingSize;
    	unsigned long	Width;
    	unsigned long	Height;
    	unsigned short	Planes;
    	unsigned short	BitCount;
    	unsigned long	Compression;
    	unsigned long	SizeImage;
    	unsigned long	XPelsPerMeter;
    	unsigned long	YPelsPerMeter;
    	unsigned long	ClrUsed;
    	unsigned long	ClrImportant;
    };
    A detailed description of the fields can be found on www.brackeen.com, in the VGA Tutorials (Bitmaps and Palettes) Section.
    Pentium 4 - 2.0GHz, 512MB RAM
    NVIDIA GeForce4 MX 440
    WinXP
    Visual Studio .Net 2003
    DX9 October 2004 Update (R.I.P. VC++ 6.0 Compatability)

  3. #3
    myNegReal
    Join Date
    Jun 2005
    Posts
    100
    Yeah I'm avoiding windows dependencies because i wanna make a whole image loader to support multiple filetypes that I'm also gonna use on linux. Anyway, I'll try that and see what happens, thanks.
    Using Dev-C++ on Windows

  4. #4
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Your problem is the structure packing alignment. You need to consult your compiler documentation and determine how you can change the alignment to a 1 byte boundary.
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > Even though that is what everyone suggested, and it makes sense that it should work properly
    Indeed, your approach solves the alignment problem but it would still fall down on a machine with a different endian-ess. To fix that, you'd have to read the file one byte at a time and assemble each short/long by hand.

    Since the OP is using dev-c++, then the struct packing can be achieved with
    Code:
        struct __attribute__ ((__packed__)) {
            unsigned short int type;
            unsigned int filesize;
            unsigned short int reserved;
            unsigned short int reserved2;
            unsigned int offset;
        } header;
    You might want to check sizeof(header)==14 before trying to read the file, just to make sure that the struct is packed properly.
    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.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. File Writing Problem
    By polskash in forum C Programming
    Replies: 3
    Last Post: 02-13-2009, 10:47 AM
  2. C++ std routines
    By siavoshkc in forum C++ Programming
    Replies: 33
    Last Post: 07-28-2006, 12:13 AM
  3. Possible circular definition with singleton objects
    By techrolla in forum C++ Programming
    Replies: 3
    Last Post: 12-26-2004, 10:46 AM
  4. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 10:12 PM
  5. simulate Grep command in Unix using C
    By laxmi in forum C Programming
    Replies: 6
    Last Post: 05-10-2002, 04:10 PM