Solved

Creating a CBitmap

Posted on 2002-07-04
16
3,401 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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Adapt this command to show who installed 29 106
string initialization in java 11 110
format the code in java 6 86
java ^ examples 8 62
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
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.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, just open a new email message. In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

910 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

22 Experts available now in Live!

Get 1:1 Help Now