Advertisement

Displaying an image using windows GDI.

Started by August 19, 2000 08:40 PM
7 comments, last by Aqutiv 24 years, 4 months ago
since this is a general programming forum, I thought this would be best to post it here, as for this particular task I''m not using any API. I can''t seem to be able to draw an image... This problem has buggered me for a long time. assuming I have an array of bytes representing pixels named ''image'' (sized 256x256), and an empty dialog, this is what I have:
    
LRESULT CALLBACK DlgImage( HWND hDlg, UINT msg, WPARAM wParam,
        LPARAM lParam ) {
    HDC hDC = GetDC(hDlg);
    HDC MemDC = CreateCompatibleDC(hDC);
    HBITMAP Tile;
    BITMAPINFOHEADER ImgInfHead;
    BITMAPINFO ImageInf;
    RGBQUAD Palette[256];
    int wid = 256, hit = 256;
    int i;
 
  switch( msg )
  {
   case WM_INITDIALOG:
   
          ImgInfHead.biSize = wid*hit;
          ImgInfHead.biWidth = wid;
          ImgInfHead.biHeight = hit;
          ImgInfHead.biPlanes = 1;
          ImgInfHead.biBitCount = 8; // 8Bit per pixel

          ImgInfHead.biCompression = BI_RGB; //Uncompressed

          ImgInfHead.biSizeImage = 0;
          ImgInfHead.biClrUsed = 0;
          ImgInfHead.biClrImportant = 0;
          ImageInf.bmiHeader = ImgInfHead;
 
         //Create a gray scale pallate

         for (i = 0; i < 256; i++) {
         Palette<i>.rgbBlue = i;
         Palette[i].rgbGreen = i;
         Palette[i].rgbRed = i
         Palette[i].rgbReserved = 0;
         }
 
         ImageInf.bmiColors = Pallate;
 
         Tile = CreateCompatibleBitmap(MemDC, wid, hit);
     SetDIBits( MemDC, Tile,
                0, hit, image,
                &ImageInf, DIB_RGB_COLORS);
 
         SelectObject(MemDC, Tile);
 
        if(!BitBlt(hDC, 0, 0, 256, 256, MemDC, 0, 0, SRCCOPY))    
MessageBox(hDlg, "BitBlt error", "error", MB_OK);
 
        DeleteObject(Tile);
        break;
  case WM_CLOSE:
  ReleaseDC(hDlg, hDC);
  EndDialog( hDlg, TRUE );
  return TRUE;
    }
    return FALSE;
}
    
Which won''t even compile cause Palette contains 256 elemends and ImageInf.bmiColors contains only 1 element... And I thought that 8bit bitmaps supposed to have 256 colors?? other then that, even when I reduced Palette to 1, It didn''t display anything (other then the dialog itself) nor BitBlt did return a zero value... I''d really appreciate any help, Thanks in advance, -Aqutiv AquDev - It is what it is.
AquDev - It is what it is.
An 8 bit graphic is capable of displaying up to 256 color values (because the pixel value is a 1 byte index into a palette), so you need your palette.You can make you BITMAPINFO variable a pointer, and allocate the space for a BITMAPINFOHEADER and your palette (sizeof(RGBQUAD)*palette entries).When you refer to info_variable->bmiColors[whatever_index_number] you''re telling the computer to look whatever number of bytes after the initial ''address'' of the BITMAPINFO structure, which would look into garbage if you don''t own that section of memory.
Sorry for such a broad answer, I''m a little tired right now.



----------
meh
----------meh
Advertisement
Check how you spell Palette .

ImageInf.bmiColors = Palatte;

is what you wrote. see the problem now?

=======================================
A man with no head is still a man.
A head with no man is plain freaky.
ZipSter: hehe, no.. that''s not the problem.
It was just a spelling mistake in the first place, so when I corrected it I forgot to update that bit. :D

Bulbasaur: Thanks alot... but hmm, my C/C++ knowledge isn''t in its best. How do I allocate the space for a pointer? Just changing the BITMAPINFO into a pointer and writing past the array will crash my application. :\
AquDev - It is what it is.
don''t bother, I figured it out, and now I can actually display the bitmap!

but, hmm.. it seems that I have another problem..
no matter what I do, or where I read the image from, its pettern''s always the same, a few dark pixels followed by endless white pixels. (it''s displayed bottom-up, though, so the dark pixels at the bottom-left)

this is my image declaration:
int wid = 256;
int hit = 256;
BYTE *image = new BYTE[wid*hit];

here''s how I read a single image from a binary file that stores a collection of tiles which are uncompressed 256 color bitmaps: file.read(image, sizeof(image));

file is an ifsteam, rethar simple,
but no matter where I read it from, it is always the same...
It can''t be the way I display the image, cause if I specify the pixels (for example, I make half of them 0, which is black in my case) it works fine.


AquDev - It is what it is.
sizeof(image) == 4.

You probably want:

    file.read(image, wid * hit * sizeof(BYTE));    


Advertisement
Your code section doesn''t run CreatePalette(), SelectPalette(), or RealizePalette(), which you will need unless the bitmap is not 8 bit.

LOGPALETTE *pal;HPALETTE oldpal,newpal; //HPALETTE is just another pointer in windows...pal = malloc(sizeof(DWORD)+(sizeof(PALETTEENTRY)*num_entries)); /* check documentation, palette is 2 shorts, and an array of PALETTEENTRYspal->palVersion = //check for version in documentation, like 300h, I thinkpal->palNumEntries = num_entries;for(i=0;i    pal->palPalEntry.peRed = Palette.rgbRed;<br>    pal->palPalEntry.peGreen = Palette.rgbGreen;<br>    pal->palPalEntry.peBlue = Palette.rgbBlue;<br>    pal->palPalEntry.peFlags = 0;<br>/*can''t memcpy from Palette because RGBQUAD is sored BGR+ 1 byte and<br>  LOGPALETTE is RGB + 1 byte */<br>}<br>newpal = CreatePalette(pal);<br>free(pal); //don''t need this anymore<br>oldpal = SelectPalette(MemDC,newpal,FALSE); /* save oldpal,<br>  its the default palette for this device context which you<br>  replace with SelectPalette when you''re done drawing */<br>RealizePalette(MemDC); //call RealizePalette when switching in your new palette<br>… draw<br>… call DeleteObject on newpal when your done with it before<br>… deleting the device context<br> </pre> <br><br>Or something like that <img src="smile.gif" width=15 height=15 align=middle> You should get the old gdi object when selecting a new one in (like with SelectPalette or SelectObject), and replace the old one when your done with the device context.This is to prevent memory leaks, the program that put the old object there (windows or your program; tho under windows it is possible for a third program to alter your graphics) has to free that memory when its done with it.<br>&nbsp;Also, about your bitmap being upside down; if the height is positive, the data is interperated as the top left corner is the 0th position in the data, if the height is negative its upside down.I''m not sure why some images are upside down, but this is how you tell which way the data is stored in the file.<br><br>Good luck <IMG SRC="http://www.gamedev.net/community/forums/icons/icon10.gif"><br><br><br>  </i>   <br><br>———-<br>meh
----------meh
Bulbasaur: oh.... so That's why my images always appear black & white! Thanks, man.

Yup, I fixed the problem with the image pattern.. It seems that
BYTE *image = new BYTE[wid*hit];
is wrong.... and it should have been:
BYTE image[wid*hit];
which works fine. (assuming they're constants)

baskuenen:
That is hardly true... because if it was then all the chunks that follow the images wouldn't be readed correctly.
wid * hit == wid * hit * sizeof(BYTE) == sizeof(image);
which is kinda obvious, seeing as image is made of wid*hit BYTE's... and that you don't need to multiple by the size of BYTE because it's 1, and multiplying by 1 has no meaning.
practice your math knowledge. j/k




Edited by - Aqutiv on August 21, 2000 6:58:42 AM
AquDev - It is what it is.
Sorry to bother you, but... that didn't help.
I'm still getting this as if it was 2 colors instead of
256 shades of gray.
I'm completely positive the the image is 256 colors, I even tried a bit more 'colorful' pallete but it still is b&w...
here's what I have:

            LRESULT CALLBACK DlgImage( HWND hDlg, UINT msg, WPARAM wParam, 						  LPARAM lParam ) {	HDC hDC;    HDC MemDC;	PAINTSTRUCT ps;	HBITMAP Tile;	BITMAPINFOHEADER ImgInfHead;	LPBITMAPINFO ImageInf;  	LOGPALETTE *pal;	short int num_entries = 256;	HPALETTE oldpal,newpal; //HPALETTE is just another pointer in windows    	int i;   	 switch( msg )	 {		case WM_INITDIALOG:	        break;		case WM_PAINT:			hDC = BeginPaint(hDlg, &ps);			MemDC = CreateCompatibleDC(hDC);            ImageInf = (LPBITMAPINFO)new BYTE[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256];            ImgInfHead.biSize = sizeof(BITMAPINFOHEADER);            ImgInfHead.biWidth = wid;            ImgInfHead.biHeight = -hit;			ImgInfHead.biPlanes = 1;			ImgInfHead.biBitCount = 8; // 8Bit per pixel			ImgInfHead.biCompression = BI_RGB; //Uncompressed			ImgInfHead.biSizeImage = 0;			ImgInfHead.biClrUsed = 256;			ImgInfHead.biClrImportant = 128;			ImageInf->bmiHeader = ImgInfHead;			for (i = 0; i < 256; i++) {				ImageInf->bmiColors<i>.rgbBlue  = i;                ImageInf->bmiColors<i>.rgbGreen  = i;                ImageInf->bmiColors<i>.rgbRed  = i;                ImageInf->bmiColors[i].rgbReserved = 0;			}						Tile = CreateCompatibleBitmap(MemDC, wid, hit);  			pal = (LOGPALETTE *) new BYTE[sizeof(DWORD)+sizeof(PALETTEENTRY)*num_entries]; // check documentation, palette is 2 shorts, and an array of PALETTEENTRYs			pal->palVersion = //check for version in documentation, like 300h, I think			pal->palNumEntries = num_entries;			for(i=0;i < num_entries; i++) {				pal->palPalEntry[i].peRed =  ImageInf->bmiColors[i].rgbRed;   				pal->palPalEntry[i].peGreen = ImageInf->bmiColors[i].rgbGreen;  				pal->palPalEntry[i].peBlue = ImageInf->bmiColors[i].rgbBlue;    				pal->palPalEntry[i].peFlags = 0;				/*can't memcpy from Palette because RGBQUAD is sored BGR+ 1 byte and  				LOGPALETTE is RGB + 1 byte */			}			newpal = CreatePalette(pal);			free(pal); //don't need this anymore			oldpal = SelectPalette(MemDC,newpal,FALSE); 			/* save oldpal,  			     its the default palette for this device context which you  r			replace with SelectPalette when you're done drawing */			RealizePalette(MemDC); //call RealizePalette when switching in your new palette						SetDIBits( MemDC, Tile,                                     0, hit, image,  						   ImageInf, DIB_RGB_COLORS);        	SelectObject(MemDC, Tile);    	            if(!BitBlt(hDC, 0, 0, wid, hit, MemDC, 0, 0, SRCCOPY))				MessageBox(hDlg, "BitBlt Error", "error", MB_OK);			SelectPalette(MemDC, oldpal, FALSE);            EndPaint(hDlg, &ps);            delete ImageInf;			DeleteObject(newpal);			DeleteObject(Tile);			DeleteObject(MemDC);	        break;		case WM_CLOSE:			EndDialog( hDlg, TRUE );			return TRUE;    }    return FALSE;}            


Sorry for the long post. :o

Edited by - Aqutiv on August 21, 2000 7:42:20 AM

Edited by - Aqutiv on August 21, 2000 7:46:34 AM
AquDev - It is what it is.

This topic is closed to new replies.

Advertisement