views:

1331

answers:

3

I have a camera that returns raw images that can easily be converted to a bitmap that can be saved to a file by the following C# method (that I did not write). From various sources, I have determined that the pictures have 8 bits per pixel, and may or may not be grayscale.

private void rawImgToBmp(byte[] imgData, String fname) {
        Bitmap bmp = new Bitmap(getWidth(), getHeight(), 
            System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
        for (int i = 0; i < 256; i++)
            { bmp.Palette.Entries[i] = Color.FromArgb(255, i, i, i); }
        //Copy the data from the byte array into the bitmap
        BitmapData bmpData = 
            bmp.LockBits( new Rectangle(0, 0, bmp.Width, bmp.Height),
                          ImageLockMode.WriteOnly, bmp.PixelFormat);
        Marshal.Copy(imgData, 0, bmpData.Scan0, getWidth() * getHeight());
        bmp.UnlockBits(bmpData); //Unlock the pixels
        bmp.Save(FileName);
    }

My question is: how would I go about writing the equivalent method in C++, using built in functions of Windows CE 4.2?

erisu: thanks for the palette code, I think it's right. I've resorted to filling in the rest of the structs manually, according to the Wikipedia page.

A: 

Typically I use CreateBitmap or CreateCompatibleBitmap to generate bitmaps in windows. I am unfamiliar with WinCE but the functions seem to be present. Your data looks to be in 8 bit per pixel with a 256 color palette so you will also most likely need CreatePalette, SelectPalette, and RealizePalette functions.

Something like (warning: untested code):

HBITMAP hBmp=CreateBitmap(width, height, 1, 8, imgData);

LOGPALETTE logpal=(LOGPALETTE)new BYTE[sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY)];
logpal.palVersion=0x300;
logpal.palNumEntries=256;
int i=0;
do {  //no idea your palette's format, however it looks to be greyscale?
    logpal->mypal[i].peRed=i;
    logpal->mypal[i].peGreen=i;
    logpal->mypal[i].peBlue=i;
    logpal->mypal[i].peFlags=NULL;
while(++i<256);
HPALETTE hPal=CreatePalette(logpal);

//If your trying to display it to a window's DC called mywindowsDC
HDC hBmpDC = CreateCompatibleDC(mywindowsDC);
SelectObject(hBmpDC, hBmp);
SelectPalette(hBmpDC, hPal, TRUE);
BitBlt(mywindowsDC, 0, 0, width, height, hBmpDC, 0, 0, SRCCOPY);
RealizePalette(mywindowsDC);
//clean up
DeleteDC(hBmpDC);
delete [](BYTE *)logpal;
DeleteObject(hPal);
DeleteObject(hBmp);
erisu
I got your code to run, but nothing was drawn to screen. Which one of those objects/handles you create contains the bytes I would need to create a .bmp file?
drhorrible
Sorry, code was untested, error is probably in the palette portion. Do you want to draw into a window or output it to a file? if you just want to output to a file without displaying it, there are a few simple functions out there for writing raw data to .bmp.
erisu
I want to write it to a file. I've seen lots of potential functions, but I'm not sure which of your objects holds the raw data I want. Do you want me to post your code with my modifications so it compiles?
drhorrible
A: 

I am going to put the working code in this answer, whenever I arrive at it. For now, this is the best I have. I think it would work, but the code framed in //'s is currently causing problems. It creates an image buffer of 2,073,600 bytes (the size of raw_img.bin), but then the fread returns 711,148, and then feof(f) evaluates to true.

Sorry to paste so much code, but any help would be appreciated.

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <tchar.h>

#define NPAL_ENT 256

INT WINAPI WinMain( HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPTSTR lpCmdLine,
                    INT nShowCmd )
{
    int width = 1920, height = 1080;

printf("Reading raw img\n");
    FILE* f = fopen("\\FlashDisk\\raw_img.bin","r");
    if(NULL == f){printf("BAD");exit(1);}

printf("Obtaining size of raw img\n");
    fseek (f , 0L , SEEK_END);
    DWORD fsize = (DWORD)ftell (f);
    fseek (f , 0L , SEEK_SET);

printf("Creating imgData buffer of size %d\n",fsize);
    char *imgData = (char*) malloc (sizeof(char)*fsize);
    if(NULL == imgData) {printf("NOT imgData");exit(2);}

////////////////////////////////////////////////////////////////////////
printf("Copying contents of file into buffer\n");
    DWORD result = fread(imgData,1,fsize,f);
    if (result != fsize) {
        printf ("Reading error. Expected: %d, Got: %d\n",fsize, result ); 
        if(ferror(f)){printf("An error: %d\n", ferror(f)); }
        if(feof(f)) {printf("EOF\n");}
        delete[] imgData;
        fclose(f);
        exit (3);
    }
////////////////////////////////////////////////////////////////////////


    /* A bitmap has the following components:
     *  1. BMP file header
     *  2. Bitmap Information (DIB) header
     *  3. Color Palette
     *  4. Raw Data
     */
printf("Creating a bitmap handle\n");
    HBITMAP hBmp=CreateBitmap(width, height, 1, 8, imgData);

printf("1. Creating the file header\n");
    BITMAPFILEHEADER bmfh;
    memset( &bmfh, 0x00, sizeof( bmfh ) );
    bmfh.bfType = 0x4D42; // Magic #
    bmfh.bfSize = sizeof( bmfh ) + sizeof( BITMAPINFOHEADER ) 
        + NPAL_ENT*sizeof(PALETTEENTRY) + fsize; // Total file size
    bmfh.bfOffBits = sizeof( bmfh ) + sizeof( BITMAPINFOHEADER ) 
        + NPAL_ENT*sizeof(PALETTEENTRY);

printf("2. Creating bitmap info\n");
    BITMAPINFOHEADER bmih;
    bmih.biWidth = width;
    bmih.biHeight = height;
    bmih.biSize = sizeof(bmih);
    bmih.biPlanes = 1;
    bmih.biBitCount = 8;
    bmih.biCompression = BI_RGB;

printf("3. Creating a logpalette\n");
    int palSize = NPAL_ENT*sizeof(PALETTEENTRY);
    LOGPALETTE *logpal=(LOGPALETTE*)new BYTE[sizeof(LOGPALETTE)+palSize];
    if(!logpal) {delete [] imgData; printf("!logpal\n"); fclose(f); exit(4);}
    logpal->palVersion=0x300;
    logpal->palNumEntries=NPAL_ENT;
    int i=0;
    do {  //no idea your palette's format, however it looks to be greyscale?
        logpal->palPalEntry[i].peRed=i;
        logpal->palPalEntry[i].peGreen=i;
        logpal->palPalEntry[i].peBlue=i;
        logpal->palPalEntry[i].peFlags=NULL;
    }while(++i<NPAL_ENT);
    HPALETTE hPal=CreatePalette(logpal);
    if(!hPal){delete[] imgData; delete[] logpal; printf("!hpal\n"); exit(5);}


printf("4. Bitmap data has already been read\n");

// Complete bitmap is now in memory, time to save it

printf("Determining a unique filename\n");
    TCHAR tcFileName[80];
    wsprintf( tcFileName, (TCHAR*) TEXT( "\\USBDisk\\test.bmp" ) );
    printf("Filename determined\n");

    // open the file for writing
    HANDLE hFile = CreateFile( tcFileName, GENERIC_WRITE, 0, NULL, 
                               CREATE_ALWAYS, 0, NULL );
    if(!hFile) { delete[] imgData; delete[] logpal; fclose(f); exit(6); }
    printf("File opened for writing\n");

    // write the bitmap file header to file
    DWORD bytesWrit;
    WriteFile( hFile, &bmfh, sizeof( bmfh ), &bytesWrit, NULL );
    printf("bmp file header written\n");

    // write bmp info header to file
    WriteFile( hFile, &bmih, sizeof( bmih ), &bytesWrit, NULL );
    printf("bmp info header written\n");

    // write palette to file
    WriteFile( hFile, &logpal->palPalEntry, palSize, &bytesWrit, NULL );

    // write bmp bytes to file
    DWORD totWrit = 0;
    while( totWrit < fsize ) {
        WriteFile( hFile, imgData+totWrit, fsize-totWrit, &bytesWrit, NULL);
        totWrit += bytesWrit;
    }
    printf("bmp bytes written\n");

    // close the file
    CloseHandle( hFile );
    printf("File closed\n");

    delete [] imgData;
    delete [] logpal;
    fclose(f);
    fclose(hFile);

    return 0;

}
drhorrible
I wonder if the problem is the second parameter to fopen? You only specify "r", but the file is obviously binary. Try "rb"
1800 INFORMATION
A: 

I would not read in the image data using FILE* operations: you can make it work, but it's verbose and prone to problems like fread() thinking a Ctrl-Z means End-of-File, plus you have to remember to close the file when you're finished. Instead I'd use the MFC CFile class. This will look something like

 BYTE* pbyImageData = NULL;
CFile fileImage;
if(fileImage.Open(_T("\\rawimage.dat"), CFile::modeRead, NULL))
{
     pbyImageData = new BYTE[fileImage.GetLength()];
     fileImage.Read(pbyImageData, fileImage.GetLength());
}

Bitmaps are easily handled in Windows CE using the CDIBSectionCE class. This is available from CodeGuru ('A DIBSection wrapper for Win32 and WinCE'). Using CDIBSectionCE, you would do something like this...

// The BITMAPINFO struct is almost completely unusable because it has
// space for a less-than-generous 1-colour palette, so I always end up
// creating a home-grown version with room for 256 colours:
struct BITMAPINFO256
{
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD          bmiColors[256];
} stcBmpInfo;

// ...Fill in the BITMAPINFO structure -- bitmap size etc.
stcBmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
stcBmpInfo.bmiHeader.biWidth = .... 
/// etc ... keep the code you have for filling in bitmap info at present

// Now load up the image into the DIB Section
CDIBSectionCE bmp;
bmp.SetBitmap((BITMAPINFO*)&stcBmpInfo, pbyImageData);

// Now write the bitmap out as a file
bmp.Save(_T("\\mybitmap.bmp");

Note that CDIBSectionCE handles all the file header stuff. All you need to do is read in the image data, shovel it into a DIB Section, and then ask it to save itself out as a bitmap file.

AAT