【问题标题】:How to create a .bmp in WinCE如何在 WinCE 中创建 .bmp
【发布时间】:2009-01-14 01:36:30
【问题描述】:

我有一个相机,它返回原始图像,可以很容易地转换为位图,可以通过以下 C# 方法(我没有写)保存到文件中。从各种来源,我已经确定图片每个像素有 8 位,并且可能是也可能不是灰度。

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

我的问题是:如何使用 Windows CE 4.2 的内置函数在 C++ 中编写等效方法?

erisu:感谢调色板代码,我认为它是正确的。根据Wikipedia 页面,我已求助于手动填写其余结构。

【问题讨论】:

    标签: c++ image-processing windows-ce bmp


    【解决方案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);
    

    【讨论】:

    • 我让您的代码运行,但屏幕上没有任何内容。您创建的对象/句柄中的哪一个包含创建 .bmp 文件所需的字节?
    • 抱歉,代码未经测试,错误可能在调色板部分。你想画到一个窗口还是输出到一个文件?如果您只想输出到文件而不显示它,有一些简单的函数可以将原始数据写入 .bmp。
    • 我想把它写到一个文件中。我见过很多潜在的功能,但我不确定你的哪些对象包含我想要的原始数据。你想让我发布你的代码和我的修改以便编译吗?
    【解决方案2】:

    这是适合我的代码。它基于 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;
    
    }
    

    【讨论】:

    • 不知道是不是fopen的第二个参数有问题?您只指定“r”,但该文件显然是二进制文件。试试“rb”
    【解决方案3】:

    我不会使用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 部分,然后要求其将自身保存为位图文件。

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 2020-01-21
      • 2016-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多