Thread: saving bmp image files

  1. #1
    Registered User
    Join Date
    Nov 2008
    Posts
    9

    saving bmp image files

    Hello!

    I need your help for a problem. I have to save an image file - it is a bmp 24-bit file.
    I wrote some code but when I try to execute I get the message
    "12 [main] bmpengine 2532 _gygtls:handle_exceptions: Error while dumping state (probably corrupted stack) Segmentation fault (core dumped)"

    Notes:
    1) "bmpengine" is my executable
    2) the structures are:
    Code:
    typedef struct image
    {
        BITMAP_FILE_HEADER file_info;
        BITMAP_INFO_HEADER bitmap_info;
        byte *data;
    } IMAGE;
    
    and
    
    // BMP File header
    typedef struct bitmap_file_header {
        byte bfType[2];    
        dword bfSize;
        word bfReserved1;    
        word bfReserved2;
        dword bfOffBits;
    } BITMAP_FILE_HEADER;
    
    // BMP Image header
    typedef struct bitmap_info_header {
        dword biSize;
        dword biWidth;
        dword biHeight;
        word biPlanes;                   
        word biBitCount;
        dword biCompression;       
        dword biSizeImage;
        dword biXPelsPerMeter;     
        dword biYPelsPerMeter;
        dword biClrUsed;               
        dword biClrImportant;
    } BITMAP_INFO_HEADER;
    my "save" code is:
    Code:
    int save_image(IMAGE *image, char name[])
    {
    	FILE *fp;
    	int i, rowsize;
    	byte temp;
    	unsigned int row, col, colour;
    
    	fp=fopen(name, "wb");
    	if(fp==NULL)
    	{
    		printf("cannot open the file %s\n", name);
    		return EXIT_FAILURE;
    	}
    
    	/* I dont know if i really need those - it does not work with or without them
    
            image->file_info.bfReserved1=0;
    	image->file_info.bfReserved2=0;
    	image->file_info.bfOffBits=54;
    	image->bitmap_info.biBitCount=24;
    	image->bitmap_info.biCompression=0;
    
    	image->bitmap_info.biXPelsPerMeter=0;
    	image->bitmap_info.biYPelsPerMeter=0;
    	image->bitmap_info.biClrUsed=3;
    	image->bitmap_info.biClrImportant=0;
          */
    
    	rowsize=4*((3*image->bitmap_info.biWidth+3)/4);
    	image->bitmap_info.biSizeImage=image->bitmap_info.biHeight*rowsize;
    	image->file_info.bfSize=54+image->bitmap_info.biSizeImage;
    
    	// Reserving memory for image's data
    	image->data=(byte*) malloc(sizeof(byte)*image->bitmap_info.biSizeImage);
    	if (image->data==NULL)
    	{
    		printf("Insufficient memory to load new image.\n");
    	    free(image);   return EXIT_FAILURE;
    	 }
    
    	if(image != NULL)
    	{
    	fwrite(&image->file_info, sizeof(BITMAP_FILE_HEADER),1,fp);
    	fwrite(&image->bitmap_info, sizeof(BITMAP_INFO_HEADER),1,fp);
    
    	for(row=image->bitmap_info.biHeight-1; row>=0; row--) {//for each row
    		for(col=0;col<image->bitmap_info.biWidth;col++) //for each column
    			for(colour=BLUE; colour>=RED; colour--)  //for each color
    				fwrite(&image->data[row*rowsize+3*col+colour],sizeof(byte),1,fp); 				
    				
    	    for(i=rowsize-(3*image->bitmap_info.biWidth);i>=0;i--) //padding
    	        fwrite(&temp,sizeof(temp),1,fp);
    	    } //end_for
    	}  //end_if
    
    	fclose(fp);
    	return EXIT_SUCCESS;
    }
    where i am doing wrong??? please help!
    any help would be appreciated!
    thanks...

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    None of this will solve your complaint, but may avoid other probelms. I can't actually find anything in your code that is directly wrong - but it may be elsewhere that the problem lies.

    Code:
    	if(image != NULL)
    Should that not be tested MUCH further up, as you are using image->... plenty of times before that line.

    Code:
    free(image);   return EXIT_FAILURE;
    don't put two statements on the same line.

    Code:
    image->bitmap_info.biHeight
    Where is this set?

    Code:
    	image->data=(byte*) malloc(sizeof(byte)*image->bitmap_info.biSizeImage);
    ...
    				fwrite(&image->data[row*rowsize+3*col+colour],sizeof(byte),1,fp);
    You are writing out "garbage" (whatever malloc returned).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    Nov 2008
    Posts
    9
    Quote Originally Posted by matsp View Post

    Code:
    	image->data=(byte*) malloc(sizeof(byte)*image->bitmap_info.biSizeImage);
    ...
    				fwrite(&image->data[row*rowsize+3*col+colour],sizeof(byte),1,fp);
    You are writing out "garbage" (whatever malloc returned).
    thank you for your reply!
    but, can you explain to me why am I writing garbage?
    what should I write???? any ideas???

    thanks again...

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You are saving the memory you just allocated. It doesn't contain anything meaningful until it has been filled with something, right?

    Normally, you'd want to write your bitmap image content - I'm not sure where that happens to be, or what it is, but that's usually more meaningful to write out than a freshly allocated piece of memory - which contains whatever it happens to contain - fresh memory is usually zero, if it's been allocated and then freed, it's whatever happened to be in that memory last time it was used.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Nov 2008
    Posts
    9
    Please, I dont get it...
    I changed my code to this
    Code:
    int save_image(IMAGE *image, char name[])
    {
    	FILE *fp;
    	int i, rowsize;
    	byte temp;
    	unsigned int row, col, colour;
    
    	fp=fopen(name, "wb");
    	if(fp==NULL)
    	{
    		printf("cannot open the file %s\n", name);
    		return EXIT_FAILURE;
    	}
    
    	image->file_info.bfReserved1=0;
    	image->file_info.bfReserved2=0;
    	image->file_info.bfOffBits=54;
    	image->bitmap_info.biBitCount=24;
    	image->bitmap_info.biCompression=0;
    	image->bitmap_info.biXPelsPerMeter=0;
    	image->bitmap_info.biYPelsPerMeter=0;
    	image->bitmap_info.biClrUsed=3;
    	image->bitmap_info.biClrImportant=0;
    	image->bitmap_info.biHeight=image->bitmap_info.biHeight;
    	image->bitmap_info.biWidth=image->bitmap_info.biWidth;
    
    	rowsize=4*((3*image->bitmap_info.biWidth+3)/4);
    	image->bitmap_info.biSizeImage=image->bitmap_info.biHeight*rowsize;
    	image->file_info.bfSize=54+image->bitmap_info.biSizeImage;
    
    	if(image!=NULL)
    	{
    	fwrite(&image->file_info, sizeof(BITMAP_FILE_HEADER),1,fp);
    	fwrite(&image->bitmap_info, sizeof(BITMAP_INFO_HEADER),1,fp);
    
    	for( row=0; row<image->bitmap_info.biHeight; row++) {//for each row
    		for(col=0;col<image->bitmap_info.biWidth;col++) //for each column
    			for(colour=RED; colour<=BLUE; colour++)  //for each color
    				fwrite(&image->data[row*col+3*rowsize+colour],sizeof(byte),1,fp);
    
    	    for(i=0;i<rowsize-(3*image->bitmap_info.biWidth);i++) //padding
    	        fwrite(&temp,sizeof(temp),1,fp);
    	    }
    	}
    
    	fclose(fp);
    	return EXIT_SUCCESS;
    }
    now, i dont get any mistakes during execution
    I get an image with the same size as the original, but destroyed.... it has not any dimensions, not even the 24bit color...........
    (that's what Windos Vista are displaying in "properties" tab of the image)


    ONCE MORE - lets take it from the begining... what I want to do:

    Suppose, we have an image called "image1.bmp"
    we open it
    we do stuff with it (eg rotate, mirror etc) or do nothing...
    the image is still loaded to the memory
    then, we want to save it - just that! same filename, still 24 bit

    what do we have to do???
    my code is supposed to save the image
    so, what's wrong???

    Please Please
    help
    Im so confused...

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Is the size of the bitmap header and info structures the right one. Since these headers contain information in a packed format (no gaps), it is likely that the compiler adds padding to align the data structures.

    Other than that, I can't see anything directly wrong.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Your structures must be byte aligned:

    Code:
    #pragma pack (1)
    
    typedef struct image
    {
        BITMAP_FILE_HEADER file_info;
        BITMAP_INFO_HEADER bitmap_info;
        byte *data;
    } IMAGE;
    
    and
    
    // BMP File header
    typedef struct bitmap_file_header {
        byte bfType[2];    
        dword bfSize;
        word bfReserved1;    
        word bfReserved2;
        dword bfOffBits;
    } BITMAP_FILE_HEADER;
    
    // BMP Image header
    typedef struct bitmap_info_header {
        dword biSize;
        dword biWidth;
        dword biHeight;
        word biPlanes;                   
        word biBitCount;
        dword biCompression;       
        dword biSizeImage;
        dword biXPelsPerMeter;     
        dword biYPelsPerMeter;
        dword biClrUsed;               
        dword biClrImportant;
    } BITMAP_INFO_HEADER;
    Also, you're improperly handling the bitmap pallette and note the statements that are not needed:

    Code:
    #ifdef STATEMENTSNOTNEEDED
        image->file_info.bfReserved1=0;
        image->file_info.bfReserved2=0;
        image->file_info.bfOffBits=54;
        image->bitmap_info.biBitCount=24;
        image->bitmap_info.biCompression=0;
        image->bitmap_info.biXPelsPerMeter=0;
        image->bitmap_info.biYPelsPerMeter=0;
        image->bitmap_info.biClrUsed=3;
        image->bitmap_info.biClrImportant=0;
        image->bitmap_info.biHeight=image->bitmap_info.biHeight;
        image->bitmap_info.biWidth=image->bitmap_info.biWidth;
    
        rowsize=4*((3*image->bitmap_info.biWidth+3)/4);
        image->bitmap_info.biSizeImage=image->bitmap_info.biHeight*rowsize;
        image->file_info.bfSize=54+image->bitmap_info.biSizeImage;
     #endif
            fwrite(&image->file_info, sizeof(BITMAP_FILE_HEADER),1,fp);
        fwrite(&image->bitmap_info, sizeof(BITMAP_INFO_HEADER),1,fp);
        int itotalPalettbytes = (int) image->file_info.bfOffBits - sizeof(BITMAP_FILE_HEADER) - (int)sizeof(BITMAP_INFO_HEADER);
        fwrite((void *)(&image->bitmap_palette),4, itotalPalettbytes / 4, fp);
    I added the bitmap pallette to the IMAGE structure to make the code work.

  8. #8
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define byte unsigned char
    #define dword unsigned int 
    #define word unsigned short int 
    
    #pragma pack (1)
    
    //4 Bytes per each pallete color
    typedef struct {
        unsigned char rgbBlue,    
                     rgbGreen,    
                       rgbRed,    
                  rgbReserved;    
    }BITMAP_PALETTE;
    
    // BMP File header
    typedef struct bitmap_file_header {
        byte bfType[2];    
        dword bfSize;
        word bfReserved1;    
        word bfReserved2;
        dword bfOffBits;
    } BITMAP_FILE_HEADER;
    
    // BMP Image header
    typedef struct bitmap_info_header {
        dword biSize;
        dword biWidth;
        dword biHeight;
        word biPlanes;                   
        word biBitCount;
        dword biCompression;       
        dword biSizeImage;
        dword biXPelsPerMeter;     
        dword biYPelsPerMeter;
        dword biClrUsed;               
        dword biClrImportant;
    } BITMAP_INFO_HEADER;
    
    typedef struct image
    {
        BITMAP_FILE_HEADER file_info;
        BITMAP_INFO_HEADER bitmap_info;
        BITMAP_PALETTE *bitmap_palette;
        byte *data;
    } IMAGE;
    
    int save_image(IMAGE *image, char name[])
    {
        FILE *fp;
        int i, rowsize;
        byte temp;
        unsigned int row, col, colour;
        int nx, ny;
    
        if(image == NULL)
            return EXIT_FAILURE;
        fp=fopen(name, "wb");
        if(fp==NULL)
        {
            printf("cannot open the file %s\n", name);
            return EXIT_FAILURE;
        }
        fwrite(&image->file_info, sizeof(BITMAP_FILE_HEADER),1,fp);
        fwrite(&image->bitmap_info, sizeof(BITMAP_INFO_HEADER),1,fp);
        int itotalPalettbytes = (int) image->file_info.bfOffBits - sizeof(BITMAP_FILE_HEADER) - (int)sizeof(BITMAP_INFO_HEADER);
        fwrite((void *)(&image->bitmap_palette),4, itotalPalettbytes / 4, fp);
        if (((image->bitmap_info.biWidth * 3) % 4) == 0) {
            nx = image->bitmap_info.biWidth * 3;
        } 
        else {
            nx = image->bitmap_info.biWidth * 3 + 4 -((image->bitmap_info.biWidth * 3) % 4);
        }
        ny = image->bitmap_info.biHeight;
        fwrite((void *)image->data, sizeof(byte),nx * ny ,  fp);
        fclose(fp);
        return EXIT_SUCCESS;
    }
    
    int main(int argc, char **argv)
    {
        int iNx = 9, iNy;
        FILE *fp;
        int iTotalPaletteBytes;
        unsigned short int iType;     //holds the first two bytes of the file
        IMAGE *ImageInput = (IMAGE *) malloc(sizeof(IMAGE));
        if ((fp = fopen(argv[1], "rb")) == NULL)
        {
            printf("%s doesn't exist.\n",argv[1]);
        } 
        else 
        {
            fread((void *)&iType, 2, 1, fp);
            //The BM is a short integer... 19778
            if (iType == 19778)
            {
                fseek(fp,0,SEEK_SET);
                //dump the first 14 bytes
                fread((void *)&(ImageInput->file_info), sizeof(BITMAP_FILE_HEADER), 1, fp);
                //dump the next 40 bytes
                fread((void *)&(ImageInput->bitmap_info), sizeof(BITMAP_INFO_HEADER), 1, fp);
                iTotalPaletteBytes = (int)ImageInput->file_info.bfOffBits - sizeof(BITMAP_FILE_HEADER) - (int)sizeof(BITMAP_INFO_HEADER);
                //Dimention the array
                ImageInput->bitmap_palette = (BITMAP_PALETTE *) malloc(iTotalPaletteBytes); 
                //dump the next 4*n bytes 
                fread((void *)(ImageInput->bitmap_palette),4, iTotalPaletteBytes / 4, fp);    //works same way
                if (ImageInput->bitmap_info.biBitCount == 24) {
                    //Go to the beginning of the pixel data in the file
                    fseek(fp, ImageInput->file_info.bfOffBits, SEEK_SET);
    
                    //Calculate the width of the bitmap taking into account padding bytes
                    if (((ImageInput->bitmap_info.biWidth * 3) % 4) == 0) {
                        iNx = ImageInput->bitmap_info.biWidth * 3;
                    } 
                    else {
                        iNx = ImageInput->bitmap_info.biWidth * 3 + 4 -((ImageInput->bitmap_info.biWidth * 3) % 4);
                    }
                    iNy = ImageInput->bitmap_info.biHeight;
                    ImageInput->data = (unsigned char *) malloc(iNx * iNy * 3);    
                    memset(ImageInput->data,0, sizeof ImageInput->data);
                    //Retrive the data array from the file
                    fread((void *)ImageInput->data, iNx * iNy * 3, 1, fp);
                    save_image(ImageInput, "Test.bmp");
                }
            }
        }
        return 0;
    }

  9. #9
    Registered User
    Join Date
    Nov 2008
    Posts
    9
    BobS0327,
    thanks a lot for your reply!!!

    Can I ask one more thing?
    it is given that the image is 24 bit.
    do we really need the palette information, and why?

    thanks again...

  10. #10
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by aniramg69 View Post
    BobS0327,
    thanks a lot for your reply!!!

    Can I ask one more thing?
    it is given that the image is 24 bit.
    do we really need the palette information, and why?

    thanks again...
    The RGBQUAD structure is still part of the BMP (DIB) file format even though it is, for the most part, not used for 16, 24 and 32 bit image formats.

    But keep in mind that the color table can be used for the high color and true color image formats.

    An excerpt from this resource states:
    A high color or true color DIB image does not need a color table, because each pixel has full RGB components. But it could have nonzero biClrUsed and biClrImportant fields, and a color table. A color table for high color or true color images can be used to generate a palette for displaying the image on a palette-based device.
    Chapter 13 gives examples of how the color table can be used with a high/true color image.

    So, to code defensively, you should at the very minimum, verify that the biClrUsed field is set to Zero. Otherwise, if you make the assumption that there is no color table data and there actually is color table data, your displayed graphic image will be little more than garbage because you're reading the color table data as graphical image data.

  11. #11
    Registered User
    Join Date
    Nov 2008
    Posts
    9
    Thank you BobS0327.
    You were very kind and helpfull!

    Happy New Year for all!!!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 1
    Last Post: 05-27-2009, 12:46 PM
  2. I can't make bmp image files show up in an SDL window
    By Lucas89 in forum Game Programming
    Replies: 5
    Last Post: 05-25-2009, 01:04 PM
  3. Prob with padding in BMP image files
    By tin in forum Game Programming
    Replies: 2
    Last Post: 01-09-2006, 08:23 AM
  4. reading BMP files and pixels' colours
    By Xavier in forum C++ Programming
    Replies: 3
    Last Post: 12-16-2005, 05:19 AM
  5. Saving trees in files
    By Magos in forum C++ Programming
    Replies: 19
    Last Post: 08-29-2004, 04:08 PM