Hep_Cat
asked on
Creating a CBitmap
I have a 2D array of grayscale values (0-255). I would like to use them to create a CBitmap to display in a dialog.
How do I use the CBitmap initialization functions to create a grayscale picture with one byte per pixel? I am confused in particular by the num bytes and color plane stuff.
How do I get a HBITMAP to set on the CStatic on a dialog box
How do I use the CBitmap initialization functions to create a grayscale picture with one byte per pixel? I am confused in particular by the num bytes and color plane stuff.
How do I get a HBITMAP to set on the CStatic on a dialog box
Hi!
easest way is to use CDIB class I mentoned in the previous your Q.
easest way is to use CDIB class I mentoned in the previous your Q.
ASKER
What does the nPlanes parameter mean (I want grayscale). Here is some of my sample source code that isn't working:
void CDisplayDlg::DisplayPictur e()
{
CBitmap cBitmap;
int nWidth = 20;
int nHeight = 20;
int nPlanes = 1;
int nBitcount = 8;
BYTE lpBits[400];
BYTE color = 0;
for (int y = 0; y < 400; y++)
{
lpBits[y] = color;
}
cBitmap.CreateBitmap(nWidt h, nHeight, nPlanes, nBitcount, lpBits);
HBITMAP hBitmap = HBITMAP(cBitmap);
m_cStaticPicture.SetBitmap (hBitmap);
}
m_cStaticPicture is the CStatic control. Does it matter what size I make the CStatic box on the Dialog window?
void CDisplayDlg::DisplayPictur
{
CBitmap cBitmap;
int nWidth = 20;
int nHeight = 20;
int nPlanes = 1;
int nBitcount = 8;
BYTE lpBits[400];
BYTE color = 0;
for (int y = 0; y < 400; y++)
{
lpBits[y] = color;
}
cBitmap.CreateBitmap(nWidt
HBITMAP hBitmap = HBITMAP(cBitmap);
m_cStaticPicture.SetBitmap
}
m_cStaticPicture is the CStatic control. Does it matter what size I make the CStatic box on the Dialog window?
Hi!
1. nPlanes mean color planes of the your bitmap - in 99% cases it equal to 1
2. Of course static control will clip your bitmap according own size.
1. nPlanes mean color planes of the your bitmap - in 99% cases it equal to 1
2. Of course static control will clip your bitmap according own size.
Actually CStatic will not clip. It just grows to be large enough to show the picture, clipped by size of parent window. Kinda funny that way.
The code you gave will create an image that displays apparently random colors... the 8-bits-per-pixel colors will use the system palette.
If the incoming data is bytes of 0-255, where 0 is black, 128 is gray, and 255 is white, then I suggest creating a 24-bit image.
cBitmap.CreateBitmap(nWidt h, nHeight, 1, 24, lpBits);
Make lpBits point to a 1200-byte array (400 pixels x 3 bytes per pixel) and fill that data as follows:
for (int j= 0; j < 400; j++) {
lpBits[(j*3)+0]= inputDataBytes[j];
lpBits[(j*3)+1]= inputDataBytes[j];
lpBits[(j*3)+2]= inputDataBytes[j];
}
-- Dan
If the incoming data is bytes of 0-255, where 0 is black, 128 is gray, and 255 is white, then I suggest creating a 24-bit image.
cBitmap.CreateBitmap(nWidt
Make lpBits point to a 1200-byte array (400 pixels x 3 bytes per pixel) and fill that data as follows:
for (int j= 0; j < 400; j++) {
lpBits[(j*3)+0]= inputDataBytes[j];
lpBits[(j*3)+1]= inputDataBytes[j];
lpBits[(j*3)+2]= inputDataBytes[j];
}
-- Dan
Hep_Cat,
using 24 as your nBitCount is probably the easiest way to go. Especially with your bitmap being 20x20 pixels you don't really need to worry about bytes your wasting. But there is one pitfall with bitmaps: rows in bitfields must be DWORD-aligned, i.e. each row must start at a multiple of 4. So the width of your array isn't always neccessarily (BitCount / 8) * width. Use this formula to get the actual needed width:
RowWidth = ( ( ( nBitCount >> 3 ) * nWidth ) + 3 ) & ~3;
In your case it doesn't make a difference, but if you look at nWidth = 19:
RowWidth = ( ( ( 24 >> 3 ) * 19 ) + 3 ) & ~3
= ( ( 3 * 19 ) + 3 ) & ~3
= 60 & ~3 = 60
So there are 3 bytes at the end of each row that have to be appended to make the next row start at a DWORD-boundary.
using 24 as your nBitCount is probably the easiest way to go. Especially with your bitmap being 20x20 pixels you don't really need to worry about bytes your wasting. But there is one pitfall with bitmaps: rows in bitfields must be DWORD-aligned, i.e. each row must start at a multiple of 4. So the width of your array isn't always neccessarily (BitCount / 8) * width. Use this formula to get the actual needed width:
RowWidth = ( ( ( nBitCount >> 3 ) * nWidth ) + 3 ) & ~3;
In your case it doesn't make a difference, but if you look at nWidth = 19:
RowWidth = ( ( ( 24 >> 3 ) * 19 ) + 3 ) & ~3
= ( ( 3 * 19 ) + 3 ) & ~3
= 60 & ~3 = 60
So there are 3 bytes at the end of each row that have to be appended to make the next row start at a DWORD-boundary.
ASKER
Ok, this all makes sense, but something is going wrong. Here's all that I have got:
The project is a SIMPLE Dlg app. I just dropped a picture control on the dialog, set its type to Bitmap, and changed its ID to IDC_PICTURE. Then I created a control variable "m_cStaticPicture". Next is all the relevant code.
// Constants in DisplayDlg.h
const int nSize = 20;
const int nPlanes = 1;
const int nBitcount = 24;
const int nPixels = nSize * nSize; // Total pixel count
const int nBytes = nPixels * 3; // 3 Bytes/pixel
// These are members of the DisplayDlg class
CBitmap cBmp;
HBITMAP hBmp;
BYTE lpBits[nBytes];
// This is the code from the CDisplayDlg::OnInitDialog( )
// function that I was hoping would set the bits.
//
BYTE color = 0;
for (int y = 0; y < nPixels; y++)
{
lpBits[(y*3)+0] = color;
lpBits[(y*3)+1] = color;
lpBits[(y*3)+2] = color;
}
cBmp.CreateBitmap(nSize, nSize, nPlanes, nBitcout, lpBits);
hBmp = HBITMAP(cBmp);
m_cStaticPicture.SetBitmap (hBmp);
////////////////////////// ///////
Now, when I run this I am getting a bitmap that has some Windows graphics in it (like the X, box, and underscore in the top right corner of most apps. Also the ? square from minesweeper). If I make the CBitmap and the HBITMAP local variables instead of class members, then I get an all-white picture with some random black spots in it no matter what color I use. I am just trying to set it to a single color for now.
I am doing something incorrectly with the memory?
I could email my workspace to anybody willing to take a look at this.
The project is a SIMPLE Dlg app. I just dropped a picture control on the dialog, set its type to Bitmap, and changed its ID to IDC_PICTURE. Then I created a control variable "m_cStaticPicture". Next is all the relevant code.
// Constants in DisplayDlg.h
const int nSize = 20;
const int nPlanes = 1;
const int nBitcount = 24;
const int nPixels = nSize * nSize; // Total pixel count
const int nBytes = nPixels * 3; // 3 Bytes/pixel
// These are members of the DisplayDlg class
CBitmap cBmp;
HBITMAP hBmp;
BYTE lpBits[nBytes];
// This is the code from the CDisplayDlg::OnInitDialog(
// function that I was hoping would set the bits.
//
BYTE color = 0;
for (int y = 0; y < nPixels; y++)
{
lpBits[(y*3)+0] = color;
lpBits[(y*3)+1] = color;
lpBits[(y*3)+2] = color;
}
cBmp.CreateBitmap(nSize, nSize, nPlanes, nBitcout, lpBits);
hBmp = HBITMAP(cBmp);
m_cStaticPicture.SetBitmap
//////////////////////////
Now, when I run this I am getting a bitmap that has some Windows graphics in it (like the X, box, and underscore in the top right corner of most apps. Also the ? square from minesweeper). If I make the CBitmap and the HBITMAP local variables instead of class members, then I get an all-white picture with some random black spots in it no matter what color I use. I am just trying to set it to a single color for now.
I am doing something incorrectly with the memory?
I could email my workspace to anybody willing to take a look at this.
I changed this line to fix a typo:
cBmp.CreateBitmap(nSize, nSize, nPlanes, nBitcount, lpBits);
and I placed all of tha code in an OnButton1 handler. (draw a button in the dlg editor and then double-click it).
It works perfectly. If I leave color=0, it is a small black square. If I set color=128, it is gray and color=255 is white.
-- Dan
cBmp.CreateBitmap(nSize, nSize, nPlanes, nBitcount, lpBits);
and I placed all of tha code in an OnButton1 handler. (draw a button in the dlg editor and then double-click it).
It works perfectly. If I leave color=0, it is a small black square. If I set color=128, it is gray and color=255 is white.
-- Dan
ASKER
Dan
I do the same, and I get nothing. If you'll mail me your workspace (bergstro@eng.utah.edu) I'll give it a try and accept it as an answer if it works.
Hep_Cat
I do the same, and I get nothing. If you'll mail me your workspace (bergstro@eng.utah.edu) I'll give it a try and accept it as an answer if it works.
Hep_Cat
OK, I sent it, but it is the simplest possible dlg-based app with changes only to the OnButton2 handler. It should have worked for you.
The only confounding thing might be your video settings. My screen is set at TrueColor(24 bit)
-- Dan
The only confounding thing might be your video settings. My screen is set at TrueColor(24 bit)
-- Dan
ASKER
I am accepting this as an answer because it definitely should be working. The code executes fine, but I am not getting any colored boxes displayed. If anyone knows the problem, I'd love to hear it. My screen is set to True Color (32 bit) under the settings tab of the display properties.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
My Windows doesn't have a 24 bit option. I tried using the DIB stuff and I finally got it to work just fine. I've posted the code that I used below (again, it just sets everything to a gray value).
void CDisplayDlg::OnButton1()
{
const int nSize = 20;
const int nBytes = nSize * nSize;
BYTE * bits;
CClientDC dc(this);
BITMAPINFO * BitInfo = new BITMAPINFO;
BitInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BitInfo->bmiHeader.biWidth = nSize;
BitInfo->bmiHeader.biHeigh t = -nSize;
BitInfo->bmiHeader.biPlane s = 1;
BitInfo->bmiHeader.biBitCo unt = 8;
BitInfo->bmiHeader.biCompr ession = 0;
CDC memDC;
memDC.CreateCompatibleDC(& dc);
HBITMAP hbmp=CreateDIBSection(memD C.m_hDC, BitInfo, DIB_RGB_COLORS,
(void **)&bits, NULL, 0);
HBITMAP oldBmp=(HBITMAP)SelectObje ct(memDC.m _hDC, hbmp);
BYTE color = 128;
for (int j=0; j<nBytes; j++)
{
bits[j] = color;
}
int nColors = 256;
RGBQUAD * pRGB = new RGBQUAD[nColors];
for (int i=0; i<256; i++)
{
pRGB[i].rgbRed = i;
pRGB[i].rgbGreen = i;
pRGB[i].rgbBlue = i;
pRGB[i].rgbReserved = 0;
}
::SetDIBColorTable(memDC.m _hDC, 0, nColors, pRGB);
dc.BitBlt(50, 50, nSize, nSize, &memDC, 0, 0, SRCCOPY);
DeleteObject(hbmp);
delete BitInfo;
delete pRGB;
}
void CDisplayDlg::OnButton1()
{
const int nSize = 20;
const int nBytes = nSize * nSize;
BYTE * bits;
CClientDC dc(this);
BITMAPINFO * BitInfo = new BITMAPINFO;
BitInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BitInfo->bmiHeader.biWidth
BitInfo->bmiHeader.biHeigh
BitInfo->bmiHeader.biPlane
BitInfo->bmiHeader.biBitCo
BitInfo->bmiHeader.biCompr
CDC memDC;
memDC.CreateCompatibleDC(&
HBITMAP hbmp=CreateDIBSection(memD
(void **)&bits, NULL, 0);
HBITMAP oldBmp=(HBITMAP)SelectObje
BYTE color = 128;
for (int j=0; j<nBytes; j++)
{
bits[j] = color;
}
int nColors = 256;
RGBQUAD * pRGB = new RGBQUAD[nColors];
for (int i=0; i<256; i++)
{
pRGB[i].rgbRed = i;
pRGB[i].rgbGreen = i;
pRGB[i].rgbBlue = i;
pRGB[i].rgbReserved = 0;
}
::SetDIBColorTable(memDC.m
dc.BitBlt(50, 50, nSize, nSize, &memDC, 0, 0, SRCCOPY);
DeleteObject(hbmp);
delete BitInfo;
delete pRGB;
}
I'm glad we got this working for you.
>>I am accepting this as an answer...
Perhaps you clicked the wrong button? The question is still open and no points have been awarded.
-- Dan
>>I am accepting this as an answer...
Perhaps you clicked the wrong button? The question is still open and no points have been awarded.
-- Dan
ASKER
I tried Dan's solution on a 24-bit video machine and it worked great. DIB's are messier, but eliminated some of the headache.
Hep_Cat
Hep_Cat
Use the bitcount to8. becoz you are dealing with 0 - 255 colors
User the function CBitmap::CreateBitmap
GOOD LUCK