1

I have inherited an old-school MFC Windows CE program, and am having to make some modifications to it. As part of this I have to create a monochrome image with text on it, and both display it on a screen as well as send each row of the image to a printer one at a time.

I originally used a bitmap, and had success using DrawText() and getting a test string (Hello World) to display on the screen (this code is in Figure 1). However, I hit a wall at the stage where I am looking to extract the wrap data from the bitmap. What I am trying to get is an array with 1s or 0s representing black or white. I had first thought I would use GetBitmapBits() but unfortunately the code I am working with is so old that function is not supported yet. I thought I could get around this issue by using GetBitmap() and then accessing the bmBits parameter. However this appears to always be null which was confirmed when I found the following link: Why does GetObject return an BITMAP with null bmBits?.

My next attempt was to follow the advice in the link and use CreateDIBSection() instead of CreateCompatibleBitmap(). This seems like the right path, and I should have access to the data I want, but unfortunately I cannot get the DIB to display (code is in Figure 2). I suspect I am doing something wrong in creating the header of the DIB, but I cannot figure out what my mistake is.

If anyone has suggestions for a way to access the data in the bitmap, or can see what I am doing wrong with the DIB, I would greatly appreciate the help!

*** FIGURE 1: Code to create and display a bitmap

void CRunPage::OnPaint() 
{
    CPaintDC dc(this);          // property page device context for painting
    CBitmap mBmp;               // CBitmap object for displaying built-in bitmaps
    CDC mDCMem;                 // CDC object to handle built-in bitmap
    int iWidth, iHeight;        // dimension to draw on the screen

    int icurLabel,              // current label index of open print file
        iLabelNum;              // number of labels in open print file
    LPBITMAPINFOHEADER pBMIH;   // bitmap header object for current label
    LPBYTE pImage;              // bitmap data for current label
    CSize size;                 // size of label
    int PreviewLeft,PreviewTop,PreviewWidth,PreviewHeight;
    CRect Rect;
    BITMAP bm;
    LPVOID bmBits=NULL;

    // Calculate the preview area
    PreviewLeft=5;
    PreviewTop=5;
    GetDlgItem(IDC_RUN_NEXT)->GetWindowRect(&Rect);
    ScreenToClient(&Rect);
    PreviewWidth=Rect.left-PreviewLeft*2;
    GetDlgItem(IDC_RUN_WRAPTEXT)->GetWindowRect(&Rect);
    ScreenToClient(&Rect);
    PreviewHeight=Rect.top-PreviewTop*2;

    CRect textRect;
    CString testText(_T("Hello World"));

    CBitmap * pOldBitmap;
    CBrush whiteBrush, *pOldBrush;
    CPen blackPen, *pOldPen;


    mDCMem.CreateCompatibleDC(&dc);

    mBmp.CreateCompatibleBitmap(&dc, PreviewWidth+PreviewLeft*2, PreviewHeight+PreviewTop*2);
    //mBmp.CreateCompatibleBitmap(&dc, PreviewWidth, PreviewHeight);
    pOldBitmap = mDCMem.SelectObject(&mBmp);

    blackPen.CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
    whiteBrush.CreateSolidBrush(RGB(255,255,255));

    textRect.SetRect(0,0,PreviewWidth, PreviewHeight);

    // this means behind the text will be a white box w/ a black boarder
    pOldBrush = mDCMem.SelectObject(&whiteBrush);
    pOldPen = mDCMem.SelectObject(&blackPen);

    //these commands draw on the memory-only context (mDCMem)
    mDCMem.Rectangle(&textRect);
    mDCMem.DrawText((LPCTSTR)testText, 11, &textRect, DT_CENTER|DT_VCENTER);

    mDCMem.SelectObject(pOldBrush);
    mDCMem.SelectObject(pOldPen);

    dc.StretchBlt(PreviewLeft,PreviewTop, PreviewWidth, PreviewHeight, & mDCMem, 0, 0, PreviewWidth, PreviewHeight, SRCCOPY);

    mDCMem.SelectObject(pOldBitmap);

}

*** FIGURE 2: Trying to use a DIB instead of a bitmap

void CRunPage::OnPaint() 
{

    CPaintDC dc(this);          // property page device context for painting

    CBitmap mBmp;               // CBitmap object for displaying built-in bitmaps
    CDC mDCMem;                 // CDC object to handle built-in bitmap
    int iWidth, iHeight;        // dimension to draw on the screen

    int icurLabel,              // current label index of open print file
        iLabelNum;              // number of labels in open print file
    LPBITMAPINFOHEADER pBMIH;   // bitmap header object for current label
    LPBYTE pImage;              // bitmap data for current label
    CSize size;                 // size of label
    int PreviewLeft,PreviewTop,PreviewWidth,PreviewHeight;
    CRect Rect;
    BITMAP bm;

    // Calculate the preview area
    PreviewLeft=5;
    PreviewTop=5;
    GetDlgItem(IDC_RUN_NEXT)->GetWindowRect(&Rect);
    ScreenToClient(&Rect);
    PreviewWidth=Rect.left-PreviewLeft*2;
    GetDlgItem(IDC_RUN_WRAPTEXT)->GetWindowRect(&Rect);
    ScreenToClient(&Rect);
    PreviewHeight=Rect.top-PreviewTop*2;

    CRect textRect;
    CString testText(_T("Hello World"));

    CBitmap * pOldBitmap;
    CBrush whiteBrush, *pOldBrush;
    CPen blackPen, *pOldPen;

    LPBYTE pFWandImageMem=NULL, pImageMem=NULL, pTemp=NULL;
    int i=0,j=0, buffSize=0, numBytesPerRow=0, bitmapWidthPix,bitmapHeightPix;

    char *numBytesPerRowString;
    char temp;
    void ** ppvBits;
    BITMAPINFOHEADER bmif;
    BITMAPINFO bmi;
    HBITMAP myDIB, myOldDIB;

    mDCMem.CreateCompatibleDC(&dc);

    //this rect is the area in which I can draw (its x,y location is set by BitBlt or StretchBlt
    //mBmp.CreateCompatibleBitmap(&dc, PreviewWidth+PreviewLeft*2, PreviewHeight+PreviewTop*2);

    bmif.biSize = sizeof(BITMAPINFOHEADER);
    bmif.biWidth = PreviewWidth+PreviewLeft*2;
    bmif.biHeight = -(PreviewHeight+PreviewTop*2);//- means top down (I think? I tried both ways and neither worked)
    bmif.biPlanes = 1;
    bmif.biBitCount = 1;
    bmif.biCompression = BI_RGB; // no compression
    bmif.biSizeImage = 0; // Size (bytes) if image - this can be set to 0 for uncompressed images
    bmif.biXPelsPerMeter = 0;
    bmif.biYPelsPerMeter = 0;
    bmif.biClrUsed =0;
    bmif.biClrImportant = 0;

    bmi.bmiColors[0].rgbBlue=0;
    bmi.bmiColors[0].rgbGreen=0;
    bmi.bmiColors[0].rgbRed=0;
    bmi.bmiColors[0].rgbReserved=0;
    bmi.bmiColors[1].rgbBlue=255;
    bmi.bmiColors[1].rgbGreen=255;
    bmi.bmiColors[1].rgbRed=255;
    bmi.bmiColors[1].rgbReserved=0;

    bmi.bmiHeader=bmif;

    myDIB = CreateDIBSection(dc.GetSafeHdc(), &bmi, DIB_RGB_COLORS, ppvBits, NULL, 0);

    myOldDIB = (HBITMAP)mDCMem.SelectObject(myDIB);//SelectObject(mDCMem, myDIB);
blackPen.CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
whiteBrush.CreateSolidBrush(RGB(255,255,255));

textRect.SetRect(0,0,PreviewWidth, PreviewHeight);

// this means behind the text will be a white box w/ a black boarder
pOldBrush = mDCMem.SelectObject(&whiteBrush);
pOldPen = mDCMem.SelectObject(&blackPen);

//these commands draw on the memory-only context (mDCMem)
mDCMem.Rectangle(&textRect);
mDCMem.DrawText((LPCTSTR)testText, 11, &textRect, DT_CENTER|DT_VCENTER);

mDCMem.SelectObject(pOldBrush);
mDCMem.SelectObject(pOldPen);

dc.StretchBlt(PreviewLeft,PreviewTop, PreviewWidth, PreviewHeight, & mDCMem, 0, 0, PreviewWidth, PreviewHeight, SRCCOPY);

mDCMem.SelectObject(myOldDIB);

}

Community
  • 1
  • 1
Cacadam
  • 111
  • 1
  • 1
  • 4

1 Answers1

0

So I made two minor changes to the DIB code, and it is displaying the image correctly now.

First, I changed the way I passed in my pointer to the CreateDIBSection():

void ** ppvBits;

to

LPBYTE pBits;

And then I had to change how I passed that into CreateDIBSection. I also explicitly casted the return of CreateDIBSection() to an HBITMAP:

myDIB = CreateDIBSection(dc.GetSafeHdc(), &bmi, DIB_RGB_COLORS, (void**)&pBits, NULL, 0);

to

myDIB = (HBITMAP) CreateDIBSection(dc.GetSafeHdc(), &bmi, DIB_RGB_COLORS, ppvBits, NULL, 0);

I have not had a chance to see if I can access the image data, but I am past the initial issues now. Thanks to anyone who looked at this, and if people know how to do the first (device dependent bitmap) method I would be interested to know.

Cacadam
  • 111
  • 1
  • 1
  • 4