Question and Answer Database FAQ485C.txt 256 Color Bitmaps in WIN 16 API Category :Windows API Platform :All Windows Product : BC++4.5x BC++5.x C++Builder1.0 C++Builder3.x TC++Win4.5 Question: Q: How do i read a 256 color bitmap from a file? Answer: the following function reads in and then displays a 256 color bitmap. (note — the bitmap is hard coded, and the function can only read in 256 color bitmaps. This could be easily changed. //-------------------------------------------------------------------------------------------- //start code BOOL LoadBitmapFromFile (HWND hwnd){ HFILE hfile; BITMAPFILEHEADER BMPFileHead; BITMAPINFOHEADER BMPFileInfo; BITMAPINFO *BMPInfo; int BMPInfoSize; void *image; OFSTRUCT FileBuf; HDC hdc; PLOGPALETTE PaletteLog; PALETTEENTRY pe[256]; HPALETTE hpal; if (HFILE_ERROR == (hfile = OpenFile ("winnt256.bmp", &FileBuf, OF_READ))){ MessageBox (hwnd, "Could not open file", "ERROR!", MB_OK | MB_ICONEXCLAMATION); return FALSE; } if (FILE_READ_ERROR == (_hread(hfile, &BMPFileHead, sizeof (BITMAPFILEHEADER)))){ MessageBox (hwnd, "Could not read Bitmap file header", "ERROR!", MB_OK | MB_ICONEXCLAMATION); _lclose (hfile); return FALSE; } if (FILE_READ_ERROR == (_hread(hfile, &BMPFileInfo, sizeof (BITMAPINFOHEADER)))){ MessageBox (hwnd, "Could not read Bitmap file info", "ERROR!", MB_OK | MB_ICONEXCLAMATION); _lclose (hfile); return FALSE; } BMPInfoSize = (sizeof (BITMAPINFO)) + (265 * sizeof (RGBQUAD)); BMPInfo = (BITMAPINFO*) malloc (BMPInfoSize); BMPInfo->bmiHeader = BMPFileInfo; if(FILE_READ_ERROR == (_hread (hfile, BMPInfo->bmiColors, 256 * sizeof (RGBQUAD)))){ MessageBox (hwnd, "Could not read Bitmap palette", "ERROR!", MB_OK | MB_ICONEXCLAMATION); free (BMPInfo); _lclose (hfile); return FALSE; } image = GlobalAllocPtr (GPTR, BMPFileInfo.biSizeImage + 1024); if(FILE_READ_ERROR == (_hread (hfile, image, BMPFileInfo.biSizeImage))){ MessageBox (hwnd, "Could not read Bitmap bits to buffer", "ERROR!", MB_OK | MB_ICONEXCLAMATION); free (BMPInfo); _lclose (hfile); return FALSE; } _lclose (hfile); PaletteLog = (PLOGPALETTE)malloc(sizeof (LOGPALETTE) * 256); PaletteLog->palNumEntries = 256; PaletteLog->palVersion = 0x300; for (int i = 0; i < 256; i++){ PaletteLog->palPalEntry[i].peRed = BMPInfo->bmiColors[i].rgbRed; PaletteLog->palPalEntry[i].peGreen = BMPInfo->bmiColors[i].rgbGreen; PaletteLog->palPalEntry[i].peBlue = BMPInfo->bmiColors[i].rgbBlue; } hpal = CreatePalette (PaletteLog); hdc = GetDC (hwnd); SelectPalette (hdc, hpal, FALSE); RealizePalette (hdc); SetDIBitsToDevice (hdc, 0, 0, BMPFileInfo.biWidth, BMPFileInfo.biHeight, 0, 0, 0, BMPFileInfo.biHeight, image, BMPInfo, DIB_RGB_COLORS); GlobalFreePtr (image); free (BMPInfo); delete (PaletteLog); DeleteObject (hpal); ReleaseDC (hwnd, hdc); return TRUE; } First thing that is done is the file is opened. if (HFILE_ERROR == (hfile = OpenFile ("winnt256.bmp", &FileBuf, OF_READ))){ MessageBox (hwnd, "Could not open file", "ERROR!", MB_OK | MB_ICONEXCLAMATION); return FALSE; } If the file was opened successfully, we then stripe off the BITMAPFILEHEADER by reading it in. The way a bitmap is saved is as follows: -------------------- | BITMAPFILEHEADER | -------------------- | BITMAPINFOHEADER | -------------------- | RGBQUAD | | (bitmap colors) | -------------------- | actual bitmap | | bits | | | | | | | -------------------- So we reading in the first BITMAPFILEHEADER size chunk of the file, and placing it in a BITMAPFILEHEADER struct. if (FILE_READ_ERROR == (_hread(hfile, &BMPFileHead, sizeof (BITMAPFILEHEADER)))){ MessageBox (hwnd, "Could not read Bitmap file header", "ERROR!", MB_OK | MB_ICONEXCLAMATION); _lclose (hfile); return FALSE; } -(note _hread will adjust the file pointer by the number of bytes actually read) After we get the BITMAPFILEHEADER we then do the same thing only reading in the BITMAPINFOHEADER. if (FILE_READ_ERROR == (_hread(hfile, &BMPFileInfo, sizeof (BITMAPINFOHEADER)))){ MessageBox (hwnd, "Could not read Bitmap file info", "ERROR!", MB_OK | MB_ICONEXCLAMATION); _lclose (hfile); return FALSE; } Once we got the BITMAPINFOHEADER the next thing we need to do is create a BITMAPINFO struct. The BITMAPINFO struct is the struct that contains the BITMAPINFOHEADER and the RGBQUAD of the bitmap. To create the struct we allocate space that is the size of a BITMAPINFO plus the size of a RGBQUAD * the number of colors the bitmap contains (in this case 256). BMPInfoSize = (sizeof (BITMAPINFO)) + (265 * sizeof (RGBQUAD)); BMPInfo = (BITMAPINFO*) malloc (BMPInfoSize); Then we set the BITMAPINFO's bmi.Header to the BITMAPINFOHEADER of this bitmap. BMPInfo->bmiHeader = BMPFileInfo; Then we read the RGBQUAD info from the file into the RGBQUAD info of the BITMAPINFO structure. if(FILE_READ_ERROR == (_hread (hfile, BMPInfo->bmiColors, 256 * sizeof (RGBQUAD)))){ MessageBox (hwnd, "Could not read Bitmap palette", "ERROR!", MB_OK | MB_ICONEXCLAMATION); free (BMPInfo); _lclose (hfile); return FALSE; } next we allocate space for the actual bits of the bitmap, and read the bits in from the file to the space we just allocated. The size of the actual bitmap is stored in the biSizeImage property of the BITMAPINFOHEADER. image = GlobalAllocPtr (GPTR, BMPFileInfo.biSizeImage); if(FILE_READ_ERROR == (_hread (hfile, image, BMPFileInfo.biSizeImage))){ MessageBox (hwnd, "Could not read Bitmap bits to buffer", "ERROR!", MB_OK | MB_ICONEXCLAMATION); free (BMPInfo); _lclose (hfile); return FALSE; } then close the file it is no longer needed. _lclose (hfile); Now we need to set up our palette. First we allocate space for the palette. We need space large enough for the LOGPALETTE * nomber of colors in the bitmap (256 in our case). Once we have space our LOGPALETTE we then set its properties. palNumEntries = number of colors in our bitmap (256), palVersion most always = 0x300, and the palPalEntry[1] has to be filled with the colors of our bitmap. Since we read the colors into the BITMAPINFO.biColors space we simple transfor that out to palPalEntry[i] with a for loop. PaletteLog = (PLOGPALETTE)malloc(sizeof (LOGPALETTE) * 256); PaletteLog->palNumEntries = 256; PaletteLog->palVersion = 0x300; for (int i = 0; i < 256; i++){ PaletteLog->palPalEntry[i].peRed = BMPInfo->bmiColors[i].rgbRed; PaletteLog->palPalEntry[i].peGreen = BMPInfo->bmiColors[i].rgbGreen; PaletteLog->palPalEntry[i].peBlue = BMPInfo->bmiColors[i].rgbBlue; } Once we have the LOGPALETTE we call create palette witch returns a handle to our palette. hpal = CreatePalette (PaletteLog); Next we need to get the DC that we are going to place the bitmap in. hdc = GetDC (hwnd); Then we need to Select our palette into our dc and realize the palette with the system SelectPalette (hdc, hpal, FALSE); RealizePalette (hdc); Next we set the bits form our DIB to the hdc using the win API call SetDIBitsToDevice SetDIBitsToDevice (hdc, 0, 0, BMPFileInfo.biWidth, BMPFileInfo.biHeight, 0, 0, 0, BMPFileInfo.biHeight, image, BMPInfo, DIB_RGB_COLORS); Then we have to clean up our handles and pointers GlobalFreePtr (image); free (BMPInfo); delete (PaletteLog); DeleteObject (hpal); ReleaseDC (hwnd, hdc); If this works we return true and there will be a picture on the screen. return TRUE; } 7/2/98 10:32:32 AM
Last Modified: 01-SEP-99