-
July 29th, 2014, 10:00 AM
#1
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 );
}
-
July 29th, 2014, 10:17 AM
#2
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 );
}
-
July 30th, 2014, 05:39 AM
#3
Re: Problem in Displaying Bit Values
Originally Posted by sunnysky
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.
Originally Posted by sunnysky
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.
-
July 30th, 2014, 02:12 PM
#4
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?
-
July 31st, 2014, 06:58 AM
#5
Re: Problem in Displaying Bit Values
Originally Posted by sunnysky
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.
-
July 31st, 2014, 08:30 AM
#6
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?
-
July 31st, 2014, 01:10 PM
#7
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.
-
July 31st, 2014, 01:29 PM
#8
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?
-
August 1st, 2014, 07:30 AM
#9
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.
-
August 1st, 2014, 09:38 AM
#10
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?
-
August 1st, 2014, 04:08 PM
#11
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|