Wie ein .bmp in WinCE erstellen
-
22-07-2019 - |
Frage
Ich habe eine Kamera, die Rohbilder zurückgibt, die leicht in eine Bitmap umgewandelt werden können, die in einer Datei durch den folgenden C # Methode gespeichert werden kann (dass ich nicht schreiben). Aus verschiedenen Quellen, habe ich festgestellt, dass die Bilder 8 Bit pro Pixel haben, und können oder nicht Graustufen sein können.
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);
}
Meine Frage ist: Wie würde ich die entsprechende Methode in C ++ zu schreiben gehe über, in Funktionen von Windows CE gebaut mit 4.2
?erisu: danke für die Palette Code, ich denke, es ist richtig. Ich habe Zuflucht manuell in dem Rest der Strukturen zu füllen, nach der Wikipedia Seite.
Lösung 2
Dies ist der Code, der für mich arbeitet. Es basiert auf erisu Antwort und Wikipedia Beschreibung des BMP-Format . Für alle andere mit dieser Antwort, empfehle ich, dass Sie das BMP-Format so vollständig wie möglich zu verstehen, so können Sie die Header-Felder entsprechend anpassen.
Die komplizierte Schleife am Ende ist meine Abhilfe für ein Problem mit meiner Hardware / O, wo es alle Daten nicht schreiben mag ich fwrite geliefert. Es sollte jedoch in jeder Umgebung arbeiten.
#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;
}
Andere Tipps
Normalerweise verwende ich Create oder CreateCompatibleBitmap Bitmaps in Fenstern zu erzeugen. Ich bin nicht vertraut mit WinCE aber die Funktionen scheinen vorhanden zu sein. Ihre Daten sehen mit einer 256-Farbpalette in 8 Bit pro Pixel sein, so dass Sie auch am ehesten benötigen Create, Select und RealizePalette Funktionen.
So etwas wie (Achtung: nicht getesteten 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);
Ich würde nicht in den Bilddaten lesen mit FILE*
Operationen: Sie können es funktioniert, aber es ist ausführlich und anfällig für Probleme wie fread()
ein Ctrl-Z Denken bedeutet, End-of-Datei, und Sie haben sich daran zu erinnern das schließen Datei, wenn Sie fertig sind. Stattdessen würde ich die MFC CFile
Klasse. Dies wird in etwa so aussehen
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 sind in Windows CE mit der CDIBSectionCE
Klasse leicht zu handhaben. Dies ist von MS-Office ( 'A DIBSection Wrapper für Win32 und WinCE ‚). Mit CDIBSectionCE, würden Sie so etwas wie tun ...
// 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");
Beachten Sie, dass CDIBSectionCE
nimmt alle Datei-Header-Material. Alles, was Sie tun müssen, ist in den Bilddaten zu lesen, schaufeln sie in einen DIB-Abschnitt, und stellen sie dann selbst als Bitmap-Datei speichern aus.