CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 11 of 11
  1. #1
    sunnysky Guest

    Problem in Displaying Bit Values

    I am writing a program to display values from a data file as an image. But I can only get a blue screen. Here is a small program resembling my code. Could you see what I have missed? I only changed OnDraw function.

    Code:
    void CColorDisplayView::OnDraw(CDC* pDC)
    {
    	CColorDisplayDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc)
    		return;
    
    	CRect rect;
    	GetClientRect(rect);
    	int nWidth = rect.Width();
    	int nHeight = rect.Height();
    
    	// Allocate a bitmap header. Windows takes care of freeing this memory.
    	BITMAPINFO *    pbmiDIB = NULL;
    	pbmiDIB = (BITMAPINFO *) new BYTE[sizeof(BITMAPINFOHEADER) + 256*sizeof(WORD)];
    	if (pbmiDIB == NULL)
    	{
    		throw;
    	}
    
    	// Fill in the BITMAPINFOHEADER
    	pbmiDIB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    	pbmiDIB->bmiHeader.biWidth = nWidth;
    	pbmiDIB->bmiHeader.biHeight = nHeight;
    	pbmiDIB->bmiHeader.biPlanes = 1;
    	pbmiDIB->bmiHeader.biBitCount = 8;          // max 256 colors supported
    	pbmiDIB->bmiHeader.biCompression = BI_RGB;
    	pbmiDIB->bmiHeader.biSizeImage = 0;
    	pbmiDIB->bmiHeader.biXPelsPerMeter = 0;
    	pbmiDIB->bmiHeader.biYPelsPerMeter = 0;
    	pbmiDIB->bmiHeader.biClrUsed = 0;
    	pbmiDIB->bmiHeader.biClrImportant = 0;
    
    	CPalette cPalette;
    	BOOL success = cPalette.CreateHalftonePalette(pDC);
    
    	CPalette* pOldPal = pDC->SelectPalette(&cPalette, FALSE);
    	pDC->RealizePalette();
    
    	// Create our DIB. This call allocates the memory for our bitmap.
    	LPVOID pvBits = NULL;
    	HBITMAP hBitmap = CreateDIBSection(
    		pDC->GetSafeHdc(), 
    		pbmiDIB,
    		DIB_PAL_COLORS,
    		(void **)&pvBits,        // Here's where we put the image
    		NULL,
    		0);
    
    	LPBYTE pSensorValues = (LPBYTE) pvBits;
    	delete pbmiDIB;
    	pbmiDIB = NULL;
    
    	int k = 0;
    	for(int j = 0; j < nHeight; j++) {
    		for(int i = 0; i < nWidth; i++) {
    			*pSensorValues = k % 256;
    			pSensorValues++;
    		}
    		k++;
    	}
    
    	CDC memdc;
    	memdc.CreateCompatibleDC(pDC);
    	CBitmap* pOldBm = (CBitmap *) memdc.SelectObject(hBitmap);
    
    
    	BOOL bRet = pDC->BitBlt( 
    		rect.left, 
    		rect.top, 
    		nWidth, nHeight,
    		&memdc, 0, 0, SRCCOPY );
    }

  2. #2
    sunnysky Guest

    Re: Problem in Displaying Bit Values

    Another sample code using all purpose palette.

    Code:
    void CColorDisplayView::OnDraw(CDC* pDC)
    {
    	CColorDisplayDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc)
    		return;
    
    	CRect rect;
    	GetClientRect(rect);
    	int nWidth = rect.Width();
    	int nHeight = rect.Height();
    
    	// Allocate a bitmap header. Windows takes care of freeing this memory.
    	BITMAPINFO *    pbmiDIB = NULL;
    	pbmiDIB = (BITMAPINFO *) new BYTE[sizeof(BITMAPINFOHEADER) + 256*sizeof(WORD)];
    	if (pbmiDIB == NULL)
    	{
    		throw;
    	}
    
    	// Fill in the BITMAPINFOHEADER
    	pbmiDIB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    	pbmiDIB->bmiHeader.biWidth = nWidth;
    	pbmiDIB->bmiHeader.biHeight = nHeight;
    	pbmiDIB->bmiHeader.biPlanes = 1;
    	pbmiDIB->bmiHeader.biBitCount = 8;          // max 256 colors supported
    	pbmiDIB->bmiHeader.biCompression = BI_RGB;
    	pbmiDIB->bmiHeader.biSizeImage = 0;
    	pbmiDIB->bmiHeader.biXPelsPerMeter = 0;
    	pbmiDIB->bmiHeader.biYPelsPerMeter = 0;
    	pbmiDIB->bmiHeader.biClrUsed = 0;
    	pbmiDIB->bmiHeader.biClrImportant = 0;
    
    	int          i, incr, R, G, B ;
    	LOGPALETTE * plp ;
    
    	plp = (LOGPALETTE *)(malloc (sizeof (LOGPALETTE) + 246 * sizeof (PALETTEENTRY))) ;
    
    	plp->palVersion    = 0x0300 ;
    	plp->palNumEntries = 247 ;
    
    	// The following loop calculates 31 gray shades, but 3 of them
    	//        will match the standard 20 colors
    	for (i = 0, G = 0, incr = 8 ; G <= 0xFF ; i++, G += incr)
    	{
    		plp->palPalEntry[i].peRed   = (BYTE) G ;
    		plp->palPalEntry[i].peGreen = (BYTE) G ;
    		plp->palPalEntry[i].peBlue  = (BYTE) G ;
    		plp->palPalEntry[i].peFlags = 0 ;
    
    		incr = (incr == 9 ? 8 : 9) ;
    	}
    
    	// The following loop is responsible for 216 entries, but 8 of 
    	//        them will match the standard 20 colors, and another
    	//        4 of them will match the gray shades above.
    
    	for (R = 0 ; R <= 0xFF ; R += 0x33)
    	for (G = 0 ; G <= 0xFF ; G += 0x33)
    	for (B = 0 ; B <= 0xFF ; B += 0x33)
    	{
    		plp->palPalEntry[i].peRed   = (BYTE) R ;
    		plp->palPalEntry[i].peGreen = (BYTE) G ;
    		plp->palPalEntry[i].peBlue  = (BYTE) B ;
    		plp->palPalEntry[i].peFlags = 0 ;
    
    		i++ ;
    	}
    
    	CPalette cPalette;
    	cPalette.CreatePalette (plp) ;
    	free (plp) ;
    //	BOOL success = cPalette.CreateHalftonePalette(pDC);
    
    	CPalette* pOldPal = pDC->SelectPalette(&cPalette, FALSE);
    	pDC->RealizePalette();
    
    	// Create our DIB. This call allocates the memory for our bitmap.
    	LPVOID pvBits = NULL;
    	HBITMAP hBitmap = CreateDIBSection(
    		pDC->GetSafeHdc(), 
    		pbmiDIB,
    		DIB_PAL_COLORS,
    		(void **)&pvBits,        // Here's where we put the image
    		NULL,
    		0);
    
    	LPBYTE pSensorValues = (LPBYTE) pvBits;
    	delete pbmiDIB;
    	pbmiDIB = NULL;
    
    	int k = 0;
    	for(int j = 0; j < nHeight; j++) {
    		for(int i = 0; i < nWidth; i++) {
    			*pSensorValues = k % 256;
    			pSensorValues++;
    		}
    		k++;
    	}
    
    	CDC memdc;
    	memdc.CreateCompatibleDC(pDC);
    	CBitmap* pOldBm = (CBitmap *) memdc.SelectObject(hBitmap);
    
    
    	BOOL bRet = pDC->BitBlt( 
    		rect.left, 
    		rect.top, 
    		nWidth, nHeight,
    		&memdc, 0, 0, SRCCOPY );
    }

  3. #3
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Problem in Displaying Bit Values

    Quote Originally Posted by sunnysky View Post
    Code:
    	// Allocate a bitmap header. Windows takes care of freeing this memory.
    	BITMAPINFO *    pbmiDIB = NULL;
    	pbmiDIB = (BITMAPINFO *) new BYTE[sizeof(BITMAPINFOHEADER) + 256*sizeof(WORD)];
    	if (pbmiDIB == NULL)
    	{
    		throw;
    	}
    1) Windows does NOT take care of freeing memory you allocate with new.

    If you mean that when your exe terminates, the memory will no longer be allocated, well no you're right there because windows releases the heaps associated with your process.

    It's still "bad form" to not delete what you have newed.

    2) new will never return NULL.
    you will either get allocated memory, or the C++ runtime will throw an exception for you.

    3) throw;
    without parameter rethrows the pending exception
    outside of a catch block, it throws 'nothing' which is again "bad form" because it prevents you from properly catching it elsewhere.


    Quote Originally Posted by sunnysky View Post
    Code:
    	// Fill in the BITMAPINFOHEADER
    You are only partially filling the bitmapinfoheader. For a palette based image, you also need to specify the image palette members as well.
    you aren't even allocating the palette here, so your image isn't even entirely valid.
    you're also specifying that you have a 16bit palette where you probably want to specify an RGB palette.

  4. #4
    sunnysky Guest

    Re: Problem in Displaying Bit Values

    Hi OReubens,

    Thank you for these points.
    1) Windows does NOT take care of freeing memory you allocate with new.
    I have delete operation for pbmiDIB.
    Code:
    delete pbmiDIB;
    pbmiDIB = NULL;
    But I may need to use
    Code:
    delete[] (BYTE*)pbmiDIB;
    pbmiDIB = NULL;
    2) new will never return NULL.
    you will either get allocated memory, or the C++ runtime will throw an exception for you.
    Didn't know that. Thanks for pointing out.

    3) throw;
    without parameter rethrows the pending exception
    outside of a catch block, it throws 'nothing' which is again "bad form" because it prevents you from properly catching it elsewhere.
    I may just delete that throw.

    You are only partially filling the bitmapinfoheader. For a palette based image, you also need to specify the image palette members as well.
    you aren't even allocating the palette here, so your image isn't even entirely valid.
    you're also specifying that you have a 16bit palette where you probably want to specify an RGB palette.
    I am wondering whether I need to allocate sizeof(BITMAPINFOHEADER) + 256*sizeof(WORD) bytes space. I think maybe only sizeof(BITMAPINFOHEADER) + sizeof(WORD) is necessary. I am using a palette, so I don't need color map from BITMAPINFO, right?

    Doesn't cPalette.CreateHalftonePalette(pDC) or cPalette.CreatePalette (plp) specify an RGB palette?

  5. #5
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Problem in Displaying Bit Values

    Quote Originally Posted by sunnysky View Post
    I have delete operation for pbmiDIB.
    Code:
    delete pbmiDIB;
    pbmiDIB = NULL;
    if you allocate with new[]
    you should delete with delete[]

    also, you don't have to set a pointer to NULL after a delete, unless you'll be testing/reusing the pointer.


    Doesn't cPalette.CreateHalftonePalette(pDC) or cPalette.CreatePalette (plp) specify an RGB palette?
    No that tells Windows which palette to use for DISPLAYING the image in your applicationwindow. (it "sets the palette for the screen" if you want a simple analogy). Windows will then map the colors from your image to the colors of the display. It does this with one of several color matching and/or dithering schemes.

    Both functions are entirely pointless if your Windows is running on 16/24/32bit(or better) color modes. Note that running Windows (the OS) in 256 color modes has been obsolete for more than a decade. I honestly wouldn't pay any sort of attention to it and assume truecolor.

  6. #6
    sunnysky Guest

    Re: Problem in Displaying Bit Values

    I am working on an old project that uses 256 color modes. I have been writing some small projects to reproduce its functionality in order to understand how it works.

    So, what have I missed in using 256 color modes in this test program?

  7. #7
    sunnysky Guest

    Re: Problem in Displaying Bit Values

    I figured out. I missed the initialization of the color table implemented by the following code.
    Code:
    	
    WORD* color = (WORD*) pbmiDIB->bmiColors;
    
    for (int i=0; i<256; i++) {
        *(color++) = i;
        }
    Now the code is like this:
    Code:
    void CColorDisplayView::OnDraw(CDC* pDC)
    {
    	CColorDisplayDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc)
    		return;
    
    	CRect rect;
    	GetClientRect(rect);
    	int nWidth = rect.Width();
    	int nHeight = rect.Height();
    
    	int          i, incr, R, G, B ;
    	LOGPALETTE * plp ;
    
    	plp = (LOGPALETTE *)(malloc (sizeof (LOGPALETTE) + 246 * sizeof (PALETTEENTRY))) ;
    
    	plp->palVersion    = 0x0300 ;
    	plp->palNumEntries = 247 ;
    
    	// The following loop calculates 31 gray shades, but 3 of them
    	//        will match the standard 20 colors
    	for (i = 0, G = 0, incr = 8 ; G <= 0xFF ; i++, G += incr)
    	{
    		plp->palPalEntry[i].peRed   = (BYTE) G ;
    		plp->palPalEntry[i].peGreen = (BYTE) G ;
    		plp->palPalEntry[i].peBlue  = (BYTE) G ;
    		plp->palPalEntry[i].peFlags = 0 ;
    
    		incr = (incr == 9 ? 8 : 9) ;
    	}
    
    	// The following loop is responsible for 216 entries, but 8 of 
    	//        them will match the standard 20 colors, and another
    	//        4 of them will match the gray shades above.
    
    	for (R = 0 ; R <= 0xFF ; R += 0x33)
    	for (G = 0 ; G <= 0xFF ; G += 0x33)
    	for (B = 0 ; B <= 0xFF ; B += 0x33)
    	{
    		plp->palPalEntry[i].peRed   = (BYTE) R ;
    		plp->palPalEntry[i].peGreen = (BYTE) G ;
    		plp->palPalEntry[i].peBlue  = (BYTE) B ;
    		plp->palPalEntry[i].peFlags = 0 ;
    
    		i++ ;
    	}
    
    	CPalette cPalette;
    	BOOL success = cPalette.CreatePalette (plp) ;
    //	BOOL success = cPalette.CreateHalftonePalette(pDC);
    	free (plp) ;
    
    	CPalette* pOldPal = pDC->SelectPalette(&cPalette, FALSE);
    	pDC->RealizePalette();
    
    		// Allocate a bitmap header. Windows takes care of freeing this memory.
    	BITMAPINFO *    pbmiDIB = NULL;
    	pbmiDIB = (BITMAPINFO *) new BYTE[sizeof(BITMAPINFOHEADER) + 256*sizeof(WORD)];
    
    	// Fill in the BITMAPINFOHEADER
    	pbmiDIB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    	pbmiDIB->bmiHeader.biWidth = nWidth;
    	pbmiDIB->bmiHeader.biHeight = nHeight;
    	pbmiDIB->bmiHeader.biPlanes = 1;
    	pbmiDIB->bmiHeader.biBitCount = 8;          // max 256 colors supported
    	pbmiDIB->bmiHeader.biCompression = BI_RGB;
    	pbmiDIB->bmiHeader.biSizeImage = 0;
    	pbmiDIB->bmiHeader.biXPelsPerMeter = 0;
    	pbmiDIB->bmiHeader.biYPelsPerMeter = 0;
    	pbmiDIB->bmiHeader.biClrUsed = 0;
    	pbmiDIB->bmiHeader.biClrImportant = 0;
    			
        // Fill in our DIB color table. We are setting up an indexed logical palette.
    	// This means that we are indexing into the current realized palette, rather
    	// than specifying actual RGB values.
    	WORD* color = (WORD*) pbmiDIB->bmiColors;
    
    	for (int i=0; i<256; i++) 
    	{
    		*(color++) = i;
    	}
    
    	// Create our DIB. This call allocates the memory for our bitmap.
    	LPVOID pvBits = NULL;
    	HBITMAP hBitmap = CreateDIBSection(
    		pDC->GetSafeHdc(), 
    		pbmiDIB,
    		DIB_PAL_COLORS,
    		(void **)&pvBits,        // Here's where we put the image
    		NULL,
    		0);
    
    	LPBYTE pSensorValues = (LPBYTE) pvBits;
    	delete[] (BYTE*)pbmiDIB;
    	pbmiDIB = NULL;
    
    	int temp = 0;
    	int k = 0;
    	for(int j = 0; j < nHeight; j++) {
    		for(int i = 0; i < ((nWidth * 8 + 31) & ~31) / 8 ; i++) {
    			*pSensorValues = k % 256;
    			pSensorValues++;
    		}
    		k++;
    	}
    
    	CDC memdc;
    	memdc.CreateCompatibleDC(pDC);
    	CBitmap* pOldBm = (CBitmap *) memdc.SelectObject(hBitmap);
    
    	BOOL bRet = pDC->BitBlt( 
    		rect.left, 
    		rect.top, 
    		nWidth, nHeight,
    		&memdc, 0, 0, SRCCOPY );
    }
    I still don't fully understand the mechanism. But at least I got what OReubens means.

  8. #8
    sunnysky Guest

    Re: Problem in Displaying Bit Values

    I still don't understand why the color table of BITMAPINFO need to be specified. We already have the palette. Aren't the values pointed by pvBits immediately mapped to a color in the palette? What's the role of BITMAPINFO color table and how is it used?

  9. #9
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Problem in Displaying Bit Values

    no. you need to specify the palette the IMAGE is supposed to use. This is what you do by specifying the colors in the image's color table. (you only need to do this for 16 and 256 color bitmaps). For 16/24/32bit images, you can directly set each pixel to the precise color you would like it to be. This is what tells that color 1 is blue and color 2 is red and color 3 is torquoise (or whatever you set it to).

    ---

    windows in 16bit/32bit (or higher) color modes DOES NOT USE a palette for the screen, and simply uses the colors the image says it wants. whichever color your image wants, the OS can paint the pixel in the color you want (or in 16bit mode, in a color that's near enough to be usable).


    on a windows in 256color SCREEN mode, more than one application might want it's own version of 256 unique colors. But since the screen is limited to 256 colors, the OS can only provide one app with an ideal color palette and needs to provide all other apps with "more or less adequate" colors that fit within the 256 it has. this is what the craete/realize palette stuff does, it tells windows which colors should be DISPLAYED. and windows will TRY to match the color the image wants to the colors the screen is set to.
    If you realise a palette that does not have turquoise. THen pixels in color 3 will be drawn in "whatever color was closest to turquoise", this could be orange if no other colors are closer.



    256 color mode is obsolete thse days, so unles syou REALLY REALLY have to support an old version of windows on antiquated video hardware set to 256color mode. You can simply remove all the CreatePalette/CreateHalfTonePalette and RealizePalette (and all associated calls) and your app will run perfectly fine on a windows set to 16bit (or higher) screen mode. Your app will still run on windows set in 256 color screen mode, but the image will look awful.

  10. #10
    sunnysky Guest

    Re: Problem in Displaying Bit Values

    Thanks OReubens,

    Let's say our image only have 256 distinct colors (actually only 64 colors in our application). To use 16/24/32bit display, we just specify 256 colors in the BITMAPINFO color table, each of which is expressed in 16/24/32bit numbers, right?

  11. #11
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Problem in Displaying Bit Values

    if you use a 256 color image
    then each pixel is a single byte, each of which is an index into the colortable
    the color table is EITHER 256x 16bit combined RGB values, or 256xRGBQuads depending on the DIB_PAL_COLORS or DIB_RGB_COLORS

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured