Как создать .bmp в WinCE - PullRequest
       29

Как создать .bmp в WinCE

1 голос
/ 14 января 2009

У меня есть камера, которая возвращает необработанные изображения, которые можно легко преобразовать в растровое изображение, которое можно сохранить в файл с помощью следующего метода 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);
    }

У меня вопрос: как мне написать эквивалентный метод на C ++, используя встроенные функции Windows CE 4.2?

erisu: спасибо за код палитры, я думаю, что это правильно. Я прибег к заполнению остальных структур вручную, согласно странице Wikipedia .

Ответы [ 3 ]

1 голос
/ 15 января 2009

Это код, который работает для меня. Он основан на ответе erisu и описании Википедии о формате BMP . Для всех, кто использует этот ответ, я рекомендую вам максимально полно понять формат 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 голос
/ 14 января 2009

Обычно я использую CreateBitmap или CreateCompatibleBitmap для генерации растровых изображений в окнах. Я не знаком с 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 голосов
/ 22 сентября 2009

Я бы не считывал данные изображения, используя 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 ( 'Оболочка DIBSection для Win32 и 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 и затем попросить сохранить себя в виде растрового файла.

...