Solved

Creating a CBitmap

Posted on 2002-07-04
16
3,381 Views
Last Modified: 2013-11-20
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
0
Comment
Question by:Hep_Cat
  • 6
  • 6
  • 2
  • +2
16 Comments
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 7131150
First you want to know the width and height of the bitmap, and make the 2d array to continous 1 dimensional array,

Use the bitcount to8. becoz you are dealing with 0 - 255 colors

User the function CBitmap::CreateBitmap

GOOD LUCK
0
 
LVL 12

Expert Comment

by:migel
ID: 7131193
Hi!
easest way is to use CDIB class I mentoned in the previous your Q.
0
 

Author Comment

by:Hep_Cat
ID: 7132635
What does the nPlanes parameter mean (I want grayscale).  Here is some of my sample source code that isn't working:

void CDisplayDlg::DisplayPicture()
{
     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(nWidth, 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?
0
 
LVL 12

Expert Comment

by:migel
ID: 7133604
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.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 7134681
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.


0
 
LVL 49

Expert Comment

by:DanRollins
ID: 7134730
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(nWidth, 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
0
 
LVL 8

Expert Comment

by:fl0yd
ID: 7139219
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.
0
 

Author Comment

by:Hep_Cat
ID: 7141264
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.
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 49

Expert Comment

by:DanRollins
ID: 7141781
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
0
 

Author Comment

by:Hep_Cat
ID: 7141831
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
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 7141986
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
0
 

Author Comment

by:Hep_Cat
ID: 7143884
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.
0
 
LVL 49

Accepted Solution

by:
DanRollins earned 300 total points
ID: 7144107
First, you can try changing your video settings to 24 bits.  If you must use TrueColor(32 bit) then you should modify the program as follows:

const int nBytes = nPixels * 4;    // 4 Bytes/pixel
...
for (int y = 0; y < nPixels; y++)
{
    lpBits[(y*4)+0] = color;
    lpBits[(y*4)+1] = color;
    lpBits[(y*4)+2] = color;
    lpBits[(y*4)+3] = 0; // I think
}

To avoid having problems with various video settings, you should consider using CreateDIBitmap rather than CreateBitmap (DI is Device Independant).  It is more complicated to set up the API call, but as I recall, the data layout is about the same.  But try the above first.

-- Dan
0
 

Author Comment

by:Hep_Cat
ID: 7144409
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.biHeight               = -nSize;
     BitInfo->bmiHeader.biPlanes               = 1;
     BitInfo->bmiHeader.biBitCount          = 8;
     BitInfo->bmiHeader.biCompression     = 0;

     CDC memDC;
     memDC.CreateCompatibleDC(&dc);

     HBITMAP hbmp=CreateDIBSection(memDC.m_hDC, BitInfo, DIB_RGB_COLORS,
                                       (void **)&bits, NULL, 0);
     HBITMAP oldBmp=(HBITMAP)SelectObject(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;
}
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 7144462
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
0
 

Author Comment

by:Hep_Cat
ID: 7146844
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
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now