Display 8bit image data in a window

Hi All,

I need to display some data in the View of an MFC application.

The data i have has come from a camera and is 8 bit data with each bit representing one grey scale pixel value.

I'm having problems display the data at the moment.  With the code i have the image is the correct size but the image within it seems to repeat itself four times.

My current solution involves trying to create a CBitmap object out of the data using CreateCompatibleBitmap and SetBitmapBits.

I have very little experience of palettes and CBitmaps so any help would be appreciated.

This is the code I currently have in OnDraw:  (pImage->GetData returns the raw data)

ImageData* pImage = pDoc->GetImage();

CDC dcMem;
dcMem.CreateCompatibleDC(pDC);

CBitmap bitmap;
bitmap.CreateCompatibleBitmap(pDC, pImage->GetWidth(), pImage->GetHeight());
bitmap.SetBitmapBits(pImage->GetNumberOfBytes(), pImage->GetData());
CBitmap* pOldBitmap = dcMem.SelectObject(&bitmap);
pDC->BitBlt(0, 0, pImage->GetWidth(), pImage->GetHeight(), &dcMem, 0, 0,SRCCOPY);
dcMem.SelectObject(pOldBitmap);

Maybe i need to do something with the palette?

Thanks
spforemanAsked:
Who is Participating?
 
mahesh1402Connect With a Mentor Commented:
It seems you have 8 bit 'Raw' data obtained from camera..I will suggest you to convert this 8-bit data to bitmap using code something like following :

// Allocate bitmap header structure
BITMAPINFO * BMI = (BITMAPINFO*)new unsigned char[sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) * 256)];

// Fill the greyscale palette
for (int GenPal = 0; GenPal < 256; GenPal++)
    *(int*)(&BMI->bmiColors[GenPal]) = GenPal * 0x10101;

// Fill in some information about the image we'll be creating
BMI->bmiHeader.biSize = sizeof(BMI->bmiHeader);
BMI->bmiHeader.biWidth = 128;   // here specify image width
BMI->bmiHeader.biHeight = 128; // here specify image height
BMI->bmiHeader.biPlanes = 1;
BMI->bmiHeader.biBitCount = 8;
BMI->bmiHeader.biCompression = BI_RGB;
BMI->bmiHeader.biXPelsPerMeter = 0;
BMI->bmiHeader.biYPelsPerMeter = 0;
BMI->bmiHeader.biClrUsed = 256;
BMI->bmiHeader.biClrImportant = 256;

// Get the DWord aligned scanline width
int ScanLine = (BMI->bmiHeader.biWidth + 3) & 0xFFFFFFFC;

// Fill in the image data size in the header
BMI->bmiHeader.biSizeImage = ScanLine * BMI->bmiHeader.biHeight;

// Create a New DC
HDC DrawDC = CreateCompatibleDC(NULL);

unsigned char * DataPtr; // <===== This is the pointer to the raw image data

// Create a new DIBSection
HBITMAP DrawBMP = CreateDIBSection(DrawDC, BMI, DIB_RGB_COLORS, (void**)&DataPtr, NULL, NULL);

// Select DIBSection into DC
HBITMAP OldBMP = (HBITMAP)SelectObject(DrawDC, DrawBMP);

if (OldBMP != NULL) { // Write image data (You would just copy your data in here)
    for (int DoY = 0; DoY < BMI->bmiHeader.biHeight; DoY++)
        for (int DoX = 0; DoX < BMI->bmiHeader.biWidth; DoX++)
            DataPtr[(DoY * ScanLine) + DoX] = DoX + DoY;

    // Draw the image to the screen (Assuming "hdc" holds the device context of your viewport)
    BitBlt(hdc, 0, 0, BMI->bmiHeader.biWidth,  BMI->bmiHeader.biHeight, DrawDC, 0, 0, SRCCOPY);

    // De-select DIBSection from the DC
    SelectObject(DrawDC, OldBMP);
 }
 
// Clean up GDI objects
DeleteObject(DrawBMP);
DeleteDC(DrawDC);

// Clean up header structure
delete BMI;

Hope this helps
-MAHESH
0
 
mahesh1402Commented:
you can also use SetDIBitsToDevice for this purpose

   LPBITMAPINFO bitinfo;
    unsigned char image[ImgHeight][ImgWidth];
    FILE *fp;

    fp = fopen("hands.raw", "rb");  // open raw file.. this is your 8 bit raw file received from camera
    if( fp == NULL ) return;

    bitinfo = (LPBITMAPINFO)new char[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
    bitinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bitinfo->bmiHeader.biWidth = ImgWidth;
    bitinfo->bmiHeader.biHeight = ImgHeight;
    bitinfo->bmiHeader.biPlanes = 1;
    bitinfo->bmiHeader.biBitCount = 8;                  
    bitinfo->bmiHeader.biCompression = BI_RGB;
    bitinfo->bmiHeader.biSizeImage = 0;
    bitinfo->bmiHeader.biXPelsPerMeter = 0;
    bitinfo->bmiHeader.biYPelsPerMeter = 0;
    bitinfo->bmiHeader.biClrUsed = 256;
    bitinfo->bmiHeader.biClrImportant = 256;

    // gray palette
    for(int i = 0; i < 256; i++)
    {
      bitinfo->bmiColors[i].rgbRed = char(i);
      bitinfo->bmiColors[i].rgbBlue = char(i);
      bitinfo->bmiColors[i].rgbGreen = char(i);
      bitinfo->bmiColors[i].rgbReserved = 0;
    }

    for( int i=0; i<ImgHeight; i++)
    {
        fread( image[i], 1, ImgWidth, fp );
    }

// Create DC goes here

    ::SetDIBitsToDevice( hDC,0,0,ImgWidth,ImgHeight,0,0, 0,ImgHeight,image,bitinfo, DIB_RGB_COLORS);

    fclose( fp );
    delete[] bitinfo;
}
NOTE : If the width of a scanline is not divisible by 4, you must change the code to pad each line.  refer prev src code for ScanLIne calculation

-MAHESH
0
 
mahesh1402Commented:
othewise if you dont want to go as above simply :

1) Get *.raw filesize [file_size]

2) Create an array unsigned char* lpBits = new unsigned char[file_size];

3) Read the data from the file to lpBits

4) Create CBitmap from this data:
    CBitmap bm;
    bm.CreateBitmap( width, height, 1, 8, lpBits ); // you should know width height of raw image, and bits-per-pixel=8

5) Initialize PictureHolder with this bitmap:
    CPictureHolder::CreateFromBitmap((HBITMAP)bm);

6) Display bitmap:
    CPictureHolder::Render(...);

7) Clean up:
    delete [] lpBits;

-MAHESH
0
 
spforemanAuthor Commented:
Thanks for the help MAHESH

All three solutions were spot on.

I had spent a day trying to do this and was so close.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.