Thread: Reading a bitmap image

  1. #1
    Registered User
    Join Date
    Feb 2004
    Posts
    4

    Reading a bitmap image

    Hello,

    I need to load a bitmap image and read its color values and save in an array. If color is white, then I want to store 0 and if color is other than white then I want to store 1. I have searched on the internet and found many code examples but none works for me.

    Any ideas ??

    Thanks.

  2. #2
    Been here, done that.
    Join Date
    May 2003
    Posts
    1,164
    Sure, understand the bitmap format and write your code accordingly. Check the http://www.wotsit.org website for formats of many files structures. This way you don't have to rely one someone else's code, you'll have the understanding to "go it alone"
    Definition: Politics -- Latin, from
    poly meaning many and
    tics meaning blood sucking parasites
    -- Tom Smothers

  3. #3
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    Read the bitmap header, then read the data which is an array of RGB values (assuming 24bit bitmaps). DON'T read it all in one step since:
    a) Structure sizes are usually multiples of 4, which 54 isn't.
    b) The way variables are stored may or may not match (little big endian).
    Code:
    const int BmpHeaderSize = 54;
    struct BmpHeader
    {
    	char ID[2];
    	long FileSize;
    	long RESERVED;
    	long BitmapDataOffset;
    	long BitmapHeaderSize;
    	long Width;
    	long Height;
    	short NrOfPlanes;
    	short BitsPerPixel;
    	long Compression;
    	long BitmapDataSize;
    	long HorizontalResolution;
    	long VerticalResolution;
    	long Colors;
    	long ImportantColors;
    };
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  4. #4
    Registered User scrapedbr's Avatar
    Join Date
    May 2003
    Posts
    19

    here is all the stuff

    see the code bove..
    cscience.org
    gobolinux.org
    Gobolinux user: 00101100

  5. #5
    Registered User scrapedbr's Avatar
    Join Date
    May 2003
    Posts
    19

    here is all the stuff

    i just write this code for a reserch work...
    this code work (i hope) =) !
    Code:
    typedef struct
    	{
    		unsigned char RGB[3];
    	}RGB;
    
    typedef struct
    	{
    		unsigned int size;
    		int width,height;
    		unsigned short int planes;
    		unsigned short int bpp;
    		unsigned int compression;
    		unsigned int imagesize;
    		int xresolution,yresolution;
    		unsigned int colours;
    		unsigned int impcolours;
    	}INFOHEADER;
    
    // ********** Create Matrix **********
    RGB** createMatrix(){
    	RGB** Matrix;
    	int i;
    	Matrix = (RGB **) malloc (sizeof (RGB*) * height);
    	if (Matrix == NULL){
    		perror("***** No memory available *****");
    		exit(0);
    	}
    	for (i=0;i<height;i++){
    		Matrix[i] = (RGB *) malloc (sizeof(RGB) * width);
    		if (Matrix[i] == NULL){
    		perror("***** No memory available *****");
    			exit(0);
    		}
    	}
    	return(Matrix);
    }
    
    // ********** Verify if the file is BMP *********
    void isBMP(FILE* arq, HEADER head, INFOHEADER info){
    	char type[3];
    	unsigned short int bpp;
    	fseek(arq,0,0);
    	fread(type,1,2,arq);
    	type[2] = '\0';
    
    	fseek(arq,28,0);
    	fread(&bpp,1,2,arq);
    
    	if (strcmp(type,"BM") || (bpp != 24)){
    		printf("\nThe file is not BMP format or is not 24 bits\n");
    	        exit(0);
    	}
    }
    
    // ********** Read BMP info from file **********
    INFOHEADER readInfo(FILE* arq){
    	INFOHEADER info;
    
    	// Image Width in pixels
    	fseek(arq,18,0);
    	fread(&info.width,1,4,arq);
    
    	// Image Height in pixels
    	fseek(arq,22,0);
    	fread(&info.height,1,4,arq);
    
    	// Color depth, BPP (bits per pixel)
    	fseek(arq,28,0);
    	fread(&info.bpp,1,2,arq);
    
    	// Compression type
    	// 0 = Normmally
    	// 1 = 8 bits per pixel
    	// 2 = 4 bits per pixel
    	fseek(arq,30,0);
    	fread(&info.compression,1,4,arq);
    
    	// Image size in bytes
    	fseek(arq,34,0);
    	fread(&info.imagesize,1,4,arq);
    
    	// Number of color used (NCL)
    	// value = 0 for full color set
    	fseek(arq,46,0);
    	fread(&info.colours,1,4,arq);
    
    	// Number of important color (NIC)
    	// value = 0 means all collors important
    	fseek(arq,50,0);
    	fread(&info.impcolours,1,4,arq);
    
    	return(info);
    }
    
    RGB** loadImage(FILE* arq, RGB** Matrix){
    	int i,j;
    	RGB tmp;
    	long pos = 51;
    
    	fseek(arq,0,0);
    
    	for (i=0; i<height; i++){
    		for (j=0; j<width; j++){
    			pos+= 3;
    			fseek(arq,pos,0);
    			fread(&tmp,(sizeof(RGB)),1,arq);
    			Matrix[i][j] = tmp;
    		}
    	}
    	return(Matrix);
    }
    
    
    /* Global */
    int height, widht;
    
    
    /* in your main program you just call */
    FILE* arq; /* the bitmap file 24 bits */
    RGB** Matrix_aux, Matrix;
    INFOHEADER info;
    info = readInfo(FILE* arq);
    height = info.height;
    width = info.width;
    
    Matrix_aux = createMatrix();
    Matrix = loadImage(arq,Matrix_aux);
    Sorry...
    Nonsense is our Motif.
    cscience.org
    gobolinux.org
    Gobolinux user: 00101100

  6. #6
    Registered User
    Join Date
    Feb 2004
    Posts
    4
    Thanks scrapedbr. This program gives 1 error. Please have a look. Also tell me how to load the bmp and how will I get the color values.

  7. #7
    Registered User scrapedbr's Avatar
    Join Date
    May 2003
    Posts
    19
    i think i got it...

    Code:
    typedef struct
    	{
    		char		type[2]; 	// file type
    		unsigned int	size; 		// file size in bytes
    		unsigned short int reserved1,reserved2;
    		unsigned int	offset; 	// offset to image data
    	}HEADER;
    to load the image just call this function:
    RGB** loadImage(FILE* arq, RGB** Matrix);

    in main;
    Code:
    	HEADER head;
    	isBMP(arq,head,info);

    you acces the color value by this form:
    int red, green, blue;

    temp = Matrix[i][j].RGB;
    red = (int)Matrix[i][j].RGB[0].
    green = (int)Matrix[i][j].RGB[1].
    blue = (int)Matrix[i][j].RGB[2].
    Last edited by scrapedbr; 03-01-2004 at 02:24 PM.
    cscience.org
    gobolinux.org
    Gobolinux user: 00101100

  8. #8
    Registered User scrapedbr's Avatar
    Join Date
    May 2003
    Posts
    19
    i write again the code. is in attach.

    gcc -o example example.c

    open a bitmap 24 bits file to a matrix, and save again to out.bmp the same file.
    cscience.org
    gobolinux.org
    Gobolinux user: 00101100

  9. #9
    Registered User
    Join Date
    Feb 2004
    Posts
    4
    Thanks scrapedbr for you co-operation. I have taken a very small 24-bit image but getting error message "No Memory available....Not enough Memory". Would you please tell me how to resolve this ??

  10. #10
    Registered User scrapedbr's Avatar
    Join Date
    May 2003
    Posts
    19
    hmmm, just reboot your machine. Or create a swap partition.
    cscience.org
    gobolinux.org
    Gobolinux user: 00101100

  11. #11
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    That seems awful complex for a simple BMP loader.

    I've written several of my own. Unless you are coding for a third party library there is no need to do checks for whether or not this is a BMP or not. If you are the only one using it in your game, then you'd better know if it's a BMP or not or you've got issues.

    Here is the structure of a BMP:

    BitmapFileHeader
    ----------------------
    BitmapInfo
    ----------------------
    1024 byte Palette in format RGB0 (if applicable)
    ----------------------
    ImageData

    The following is a DOS 8-bit BMP loader - it does not check for 16,24 bit but could be made to do so quite easily. To convert to Windows simply change the data types, exit(0), and the disk i/o functions to the equivalent Windows ones. I also have a Windows BMP loader but it was taken from Andre Lamothe's book Tricks of the Windows Game Programming Gurus and it does not differ all that much from this one.


    BMP.h
    Code:
    #ifndef _BMP_
    #define _BMP_
    
    //Bitmap.cpp
    //Implements simple .bmp loading
    #include <fcntl.h>
    #include <io.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <conio.h>
    #include <dos.h>
    #include <process.h>
    
    
    typedef unsigned char BYTE;
    typedef unsigned int  WORD;
    typedef unsigned long DWORD;
    
    struct BMPHeader
    {
      WORD 	Type;
      DWORD 	Size;
      DWORD	Reserved;
      DWORD	Offset;
      DWORD  HeaderSize;
      DWORD  Width;
      DWORD	Height;
      WORD	Planes;
      WORD    BitsPerPixel;
      DWORD	Compression;
      DWORD	SizeImage;
      DWORD	XPixelsPerMeter;
      DWORD	YPixelsPerMeter;
      DWORD  ColorsUsed;
      DWORD	ColorsImportant;
    };
    
    class BMPImage
    {
      BMPHeader ImageHeader;
      BYTE *ImageData;
      BYTE *Palette;
      public:
        BMPImage(const char *bmpfile);
        BYTE GetImageData(WORD offset) 
          {return ImageData[offset];};
        BYTE GetPaletteData(WORD offset) {return Palette[offset];};
        DWORD GetHeight(void) {return ImageHeader.Height;};
        DWORD GetWidth(void) {return ImageHeader.Width;};
        DWORD GetImageSize(void) 
          {return (ImageHeader.Width*ImageHeader.Height);};
    };
    #endif


    BMP.cpp
    Code:
    BMPImage::BMPImage(const char *bmpfile)
    {
      int handle=open(bmpfile,O_RDONLY|O_BINARY);
      if (handle==-1)
      {
        printf("%s file not found\n",bmpfile);
        exit(0);
      }
    
      read (handle,&ImageHeader,sizeof(BMPHeader));
      BYTE *tempPalette=new BYTE[1024];
      Palette=new BYTE[768];
      ImageData=new 
         BYTE[ImageHeader.Width*ImageHeader.Height];
      read (handle,tempPalette,1024);
      int pal=0;
    
      //Transfer the bmp palette into the class palette
      //Discard the fourth value
      //Reverse the order in prep for VGA palette switch
      for (int i=0;i<1020;i+=4)
      {
        Palette[pal]=tempPalette[i+2]>>2;
        Palette[pal+1]=tempPalette[i+1]>>2;
        Palette[pal+2]=tempPalette[i]>>2;
        pal+=3;
      }
      read 
      (handle,ImageData,ImageHeader.Width*ImageHeader.Height);
    }

  12. #12
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    This is a fairly robust validation routine. One improvement might be to verify the bit offset by calculating together the height, width, and boundary padding (if any).

    Code:
    /*
      Validate, then read data into the supplied buffers.
      If successful, a pointer to the actual bits is returned. 
      Otherwise, the function returns NULL.  
    */
    void * GetBitmapInfo(
     BITMAPFILEHEADER * bfhBuf, 
     BITMAPINFOHEADER * bihBuf, 
     const void * base, 
     unsigned length)
    {
     void * bits = 0;
     
     char * ptr = (char*)base;
     
         if(length > sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))
        {
         BITMAPFILEHEADER * bfh = (BITMAPFILEHEADER *)ptr;
     
         BITMAPINFOHEADER * bih = (BITMAPINFOHEADER *)(ptr + sizeof(BITMAPFILEHEADER)); 
      
             if(((char*)&(bfh->bfType))[0] == 'B' 
                &&
               ((char*)&(bfh->bfType))[1] == 'M'
                &&
               bfh->bfReserved1 == 0
                &&
               bfh->bfReserved2 == 0 
                &&
               bfh->bfSize == length
                &&
               bih->biSize == 40
                &&
                 (bih->biBitCount == 1 
                   ||
                  bih->biBitCount == 4 
                   ||
                  bih->biBitCount == 8 
                   ||
                  bih->biBitCount == 24)
                &&
             /* this doesn't really validate anything, 
                but it does prevent access violations */   
               bfh->bfOffBits < length) 
            {
             bfhBuf->bfType = bfh->bfType;
             bfhBuf->bfSize = bfh->bfSize;
             bfhBuf->bfReserved1 = bfh->bfReserved1;
             bfhBuf->bfReserved2 = bfh->bfReserved2;
             bfhBuf->bfOffBits = bfh->bfOffBits;
             bihBuf->biSize = bih->biSize;
             bihBuf->biWidth = bih->biWidth;
             bihBuf->biHeight = bih->biHeight;
             bihBuf->biPlanes = bih->biPlanes;
             bihBuf->biBitCount = bih->biBitCount;
             bihBuf->biCompression = bih->biCompression;
             bihBuf->biSizeImage = bih->biSizeImage;
             bihBuf->biXPelsPerMeter = bih->biXPelsPerMeter;
             bihBuf->biYPelsPerMeter = bih->biYPelsPerMeter;
             bihBuf->biClrUsed = bih->biClrUsed;
             bihBuf->biClrImportant = bih->biClrImportant;
             bits = &ptr[bfh->bfOffBits];    
            }
        }   
    
     return bits;
    }
    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;
    }

  13. #13
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    My bmp loader does not account for the padding to the nearest 4 byte boundary. To avoid this problem I simply make my bitmaps dimensions evenly divisible by 4. As well it does not check for 8,16 or 24 bit bmps. But this could be added very easily.

    My theory behind not accounting for the padding is this. If the bitmap is evenly divisible by 4, then it is also a power of 2. With that, accessing the image data breaks down to simple bit shifts which are super fast. Although you wont see a major decrease in performance if you don't use dimensions evenly divisible by 4, you will save yourself a lot of headache if you simply follow this rule when creating your bitmaps.

    Eventually all of my bitmaps are compiled into RLE chunks of data anyways. The file is preceded with a header that indicates the bitsperpixel for the images, the total number of images in the file, and some basic author information. Then each image is represented as a chunk. Each chunk is preceded by a header indicating the chunk size, and the dimensions of the chunk or dimensions of the image. Palette data, if applicable, is appended to the last 768 bytes of the file in the order RGB. With this format - I've called it CMP or a compiled bmp - I can store all of my bitmaps in one file and they are not easily accessible by other people so the data is safe.

    When I load the data, only one palette is loaded since all images will use the same palette (when applicable) and each image is then loaded into an array with this scheme Array[imagenumber][imagedata]. The imagedata is accessed by spritepixely*width+spritepixelx. It is much easier to work with the bitmaps when the raw data is in an array w/o all of the other overhead. Then during the initialization stage the palette is set and the fun begins.

  14. #14
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    That's an interesting approach! Is there any way to add these directories to the executable (in some resource form)?
    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;
    }

  15. #15
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well you could do it by simply retrieving the size of the EXE, setting the file pointer to one BYTE past that and writing in the binary data from there. Your loader would then have to retrieve the size of the EXE and start loading from there.

    Here are my structs:

    Code:
    typedef struct CMPHeader
    {
       DWORD NumImages;
       WORD BitsPerPixel;
       WORD Compressed;
       BYTE DateOfFile[8];
       BYTE Author[20];
    };
    
    typedef struct NCHeader
    {
      DWORD bmpwidth;
      DWORD bmpheight;
      DWORD chunksize;
      DWORD id;
    };
    I have a program that will take a text file as input and will output a .CMP file with all the relevant info in it. The text file simply lists the bmps that will be compiled into the cmp.

    The CMPHeader is at the start of the file and each NCHeader precedes a chunk of raw bitmap data. My current format allows for different size bitmaps to be compiled in the same file, however, this might cause problems later, but the chunksize field will tell you how much data to read for the next chunk. After that another chunk will appear - there will be CMPHeader.NumImages chunks in the file.


    Here is the structure of my cmp file:

    ---------------------------
    CMPHeader
    ---------------------------
    NCHeader -> new chunk header
    ---------------------------
    Raw bitmap data -> RLE compressed if CMPHeader->compressed is 1
    ---------------------------
    NCHeader
    ---------------------------
    Raw bitmap data
    ---------------------------
    ...
    ...
    ...
    ...
    ----------------------------
    Palette data in order RGB - 768 bytes - 4th element is stripped from palette data in the bmp files. Palette is taken from first image in the compilation process since all images share the same palette.
    ------------------EOF




    Future revisions will allow a PAL file to be specified as the palette data but will still be placed in the last 768 bytes of the file.

    I thought it was easier to place the palette at the end of the file rather than after the CMPHeader. This way the palette is always guaranteed to start at lengthoffile-768.

    It's just something I cooked up so that I don't have a million bmps sitting out there on the drive just waiting for someone to alter.
    Last edited by VirtualAce; 03-02-2004 at 08:45 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 1
    Last Post: 05-27-2009, 12:46 PM
  2. HotSpot image controls (web)
    By novacain in forum C# Programming
    Replies: 0
    Last Post: 06-25-2008, 04:27 AM
  3. reading gif image pixel Information-help
    By kapil1089thekin in forum C Programming
    Replies: 2
    Last Post: 05-17-2008, 01:13 AM
  4. how to convert a bitmap image to a jpg image file using C++?
    By nomer in forum Windows Programming
    Replies: 4
    Last Post: 06-04-2006, 07:40 PM
  5. Replies: 6
    Last Post: 03-03-2005, 03:52 AM