2009-01-14 78 views
1

我有一個攝像頭,可以通過以下C#方法(我沒有寫入)返回原始圖像,該圖像可以很容易地轉換爲可以保存到文件的位圖。從各種來源,我已確定圖片每像素8位,可能或不可能是灰度。如何在WinCE中創建一個.bmp文件

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); 
    } 

我的問題是:如何使用C++編寫等效方法,使用Windows CE 4.2的內置函數?

erisu:感謝調色板代碼,我認爲它是正確的。根據Wikipedia頁面,我已經手動填充了其餘的結構。

回答

1

這是對我工作的代碼。它基於erisu的回答和Wikipedia's description of the BMP format。對於使用此答案的其他人,我建議您儘可能全面瞭解BMP格式,以便相應地調整標題字段。

最後的複雜循環是我的硬件/操作系統問題的解決方法,它不會寫入我提供給fwrite的所有數據。但它應該可以在任何環境下工作。

#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 w = 1920, h = 1080; // My values, yours may vary 

//////////////////////// File Operations /////////////////////////////// 

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

    // Obtaining size of raw img 
    fseek (f , 0L , SEEK_END); 
    DWORD fsize = (DWORD)ftell (f); 
    fseek (f , 0L , SEEK_SET); 

    char *imgData = (char*) malloc (sizeof(char)*fsize); 
    if(NULL == imgData) {printf("NOT imgData");exit(2);} 

    // Copy contents of file into buffer 
    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); 
    } 
    fclose(f); 

//////////////////////// BMP Operations /////////////////////////////// 

    /* A bitmap has the following components: 
    * 1. BMP file header 
    * 2. Bitmap Information (DIB) header 
    * 3. Color Palette 
    * 4. Raw Data 
    */ 
    BITMAPFILEHEADER bmfh; 
    ZeroMemory(&bmfh, sizeof(bmfh)); 
    bmfh.bfType = 0x4D42; // MagiC# 
    bmfh.bfSize = sizeof(bmfh) + sizeof(BITMAPINFOHEADER) 
     + NPAL_ENT*sizeof(PALETTEENTRY) + w*h; // Or total file size if w/h not known 
    bmfh.bfOffBits = sizeof(bmfh) + sizeof(BITMAPINFOHEADER) 
     + NPAL_ENT*sizeof(PALETTEENTRY); 

    BITMAPINFOHEADER bmih; 
    ZeroMemory(&bmih, sizeof(bmih)); 
    bmih.biWidth = w; 
    bmih.biHeight = h; 
    bmih.biSize = sizeof(bmih); 
    bmih.biPlanes = 1; 
    bmih.biBitCount = 8; 
    bmih.biCompression = BI_RGB; 
    bmih.biSizeImage = w * h; 

    int palSize = NPAL_ENT*sizeof(PALETTEENTRY); 
    LOGPALETTE *logpal=(LOGPALETTE*)new BYTE[sizeof(LOGPALETTE)+palSize]; 
    if(!logpal) {delete [] imgData; printf("!logpal\n"); exit(4);} 
    logpal->palVersion=0x300; 
    logpal->palNumEntries=NPAL_ENT; 
    int i=0; 
    do { // Exact palette format varies. This is what worked for me 
     logpal->palPalEntry[i].peRed=i; 
     logpal->palPalEntry[i].peGreen=i; 
     logpal->palPalEntry[i].peBlue=i; 
     logpal->palPalEntry[i].peFlags=NULL; 
    } while(++i<NPAL_ENT); 

    // Complete bitmap is now in memory, time to save it 
    TCHAR bmpfname[80]; 
    wsprintf(bmpfname, (TCHAR*) TEXT("\\USBDisk\\out.bmp")); 

    // open the file for writing 
    FILE *bmpFile = _wfopen(bmpfname,L"wb"); 
    if(!bmpFile) { delete[] imgData; delete[] logpal; exit(6); } 

    // write the bitmap to file, in whatever chunks WinCE allows 
    size_t totWrit = 0, offset = 0, writeAmt = 0; 
    while(totWrit < bmfh.bfSize){ 
     if(totWrit < sizeof(bmfh)){ // File header 
      offset = totWrit; 
      totWrit += fwrite(((char*)&bmfh)+offset, 1, sizeof(bmfh)-offset, bmpFile); 
     } 
     else if(totWrit<sizeof(bmfh)+sizeof(bmih)){ // Image header 
      offset = totWrit - sizeof(bmfh); 
      totWrit += fwrite(((char*)&bmih)+offset, 1, sizeof(bmih)-offset, bmpFile); 
     } 
     else if(totWrit<sizeof(bmfh)+sizeof(bmih)+palSize) { // Pallette 
      offset = totWrit - sizeof(bmfh) - sizeof(bmih); 
      totWrit += fwrite(((char*)&logpal->palPalEntry)+offset, 1, palSize-offset, bmpFile); 
     } 
     else { // Image data 
      offset = totWrit - sizeof(bmfh) - sizeof(bmih) - palSize; 
      if(bmfh.bfSize-totWrit >= IO_SIZE) { 
       writeAmt = IO_SIZE; 
      } 
      else { 
       writeAmt = bmfh.bfSize-totWrit; 
      } 
      totWrit += fwrite(&imageBuffer[offset], 1, writeAmt, bmpFile); 
     } 

     // Close and open after each iteration to please WinCE 
     fflush(bmpFile); 
     fclose(bmpFile); 
     Sleep(4000); 
     bmpFile = _wfopen(bmpfname,L"ab"); 
     if(!bmpFile) {flog->lprintf("Couldn't reopen bmpfile"); delete [] logpal; return 0;} 
    } 
    fclose(bmpFile); 

    if(totWrit != bmfh.bfSize) { 
     printf("BMP Size mismatch: %d/%d.",totWrit,bmfh.bfSize); 
     delete [] imgData; 
     delete [] logpal; 
     exit(-1); 
    } 
    // Cleanup 
    delete [] imgData; 
    delete [] logpal; 

    return 0; 

} 
1

通常,我使用CreateBitmap或CreateCompatibleBitmap在Windows中生成位圖。我不熟悉WinCE,但功能似乎存在。你的數據看起來是每像素8位,256色調色板,所以你也很可能需要CreatePalette,SelectPalette和RealizePalette功能。

喜歡的東西(警告:未經測試的代碼):

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); 
+0

我得到了你的代碼運行,但沒有畫到屏幕上。你創建的那些對象/句柄中的哪一個包含我需要創建一個.bmp文件的字節? – 2009-01-14 07:12:03

+0

對不起,代碼未經測試,錯誤可能在調色板部分。 你想繪製一個窗口或輸出到一個文件?如果你只是想輸出到一個文件而不顯示它,那麼有一些簡單的函數可以將原始數據寫入.bmp。 – erisu 2009-01-14 18:11:00

-2

我不會使用FILE*操作圖像數據讀取:你可以把它的工作,但它的繁瑣,容易出現問題,如fread()思考一個按Ctrl-Z是指檔案結尾,再加上你必須請記住在完成後關閉文件。相反,我會使用MFC CFile類。這看起來像

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

位圖很容易在Windows CE中使用CDIBSectionCE類處理。這可從CodeGuru('A DIBSection wrapper for Win32 and WinCE')獲得。使用CDIBSectionCE,你會做這樣的事情...

// 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"); 

注意CDIBSectionCE處理所有的文件頭的東西。您只需讀取圖像數據,將其鏟入DIB部分,然後讓它將自己保存爲位圖文件。