Win32 - Direkt im Speicher zeichnen und Bitmap anzeigen



  • Mit folgendem Code kann ich mit der sehr langsamen SetPixel() API meine Grafik direkt
    auf einem Fenster zeichnen.

    hdc = BeginPaint(hWnd, &ps);
    		hBrush = CreateSolidBrush(g_Color);
    		hPen = CreatePen(PS_NULL, 1, RGB(0, 0, 0));
    		holdPen = (HPEN)SelectObject(hdc, hPen);
    		holdBrush = (HBRUSH)SelectObject(hdc, hBrush);	
    
    		int color;
    
    		for (int y = 0; y < 255; y++)
    		{
    			for (int x = 0; x < 255; x++)
    			{
    				color = x & y; 
    				SetPixel(hdc, x + 460, y + 180, RGB(color, color, color));
    			}
    		}
    
    		SelectObject(hdc, holdBrush);
    		SelectObject(hdc, holdPen);
    		DeleteObject(hPen);
    		DeleteObject(hBrush);
    		EndPaint(hWnd, &ps);
    

    Frage:
    Wie muss der Code aussehen, um zur Laufzeit eine Bitmap zu erstellen, direkt
    im Speicher auf diese Bitmap (oder einem 1D-Array) zu zeichnen und diese Bitmap
    dann auf einem Fenster darzustellen?



  • Ich bin inwzsichen einen kleinen Schritt weiter und habe folgenden Code, der im Speicher eine Bitmap in gewünschter Größe und BitTiefe erstellt.

    static HBITMAP CreateBitmapFromPixels(HDC hDC, UINT uWidth, UINT uHeight, UINT uBitsPerPixel, LPVOID pBits)
    {
    	if (uBitsPerPixel < 8) // NOT IMPLEMENTED YET
    		return NULL;
    
    	if (uBitsPerPixel == 8)
    		return Create8bppBitmap(hDC, uWidth, uHeight, pBits);
    
    	HBITMAP hBitmap = 0;
    	if (!uWidth || !uHeight || !uBitsPerPixel)
    		return hBitmap;
    	LONG lBmpSize = uWidth * uHeight * (uBitsPerPixel / 8);
    	BITMAPINFO bmpInfo = { 0 };
    	bmpInfo.bmiHeader.biBitCount = uBitsPerPixel;
    	bmpInfo.bmiHeader.biHeight = uHeight;
    	bmpInfo.bmiHeader.biWidth = uWidth;
    	bmpInfo.bmiHeader.biPlanes = 1;
    	bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    	// Pointer to access the pixels of bitmap
    	UINT * pPixels = 0;
    	hBitmap = CreateDIBSection(hDC, (BITMAPINFO *)&
    		bmpInfo, DIB_RGB_COLORS, (void **)&
    		pPixels, NULL, 0);
    
    	if (!hBitmap)
    		return hBitmap; // return if invalid bitmaps
    
    	//SetBitmapBits( hBitmap, lBmpSize, pBits);
    	// Directly Write
    
            memcpy(pPixels, pBits, lBmpSize);   
    
    	return hBitmap;
    }
    
    case WM_PAINT:
    
    		PAINTSTRUCT 	ps;
    		HDC 			hdc;
    		BITMAP 			bitmap;
    		HDC 			hdcMem;
    		HGDIOBJ 		oldBitmap;
    
    		hdc = BeginPaint(hWnd, &ps);
    
    		hdcMem = CreateCompatibleDC(hdc);
    		oldBitmap = SelectObject(hdcMem, hTest);
    
    		GetObject(hTest, sizeof(bitmap), &bitmap);
    		BitBlt(hdc, 100, 100, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);
    
    		SelectObject(hdcMem, oldBitmap);
    		DeleteDC(hdcMem);
    
    		EndPaint(hWnd, &ps);
    		break;
    

    Wenn ich folgende Zeile deaktiviere, erhalte ich schonmal eine schwarze (leere) Bitmap.

    memcpy(pPixels, pBits, lBmpSize);
    

    Ich habe schon versucht ein 1D-Byte-Array zu erstellen (BitmapBreite * BitmapWeite * 4 Bytes für RGBA) und habe versucht, hier mein DrawingCode aus dem ersten Posting direkt als Byte-Werte in das 1D-Array zu schreiben und als pBits zu übergeben. Jedoch scheine ich hier noch irgendetwas falsch zu machen.

    Kann mir evtl. jemand freundlicherweise weiter helfen, wie ich ich diese pBits erstelle und an CreateBitmapFromPixels() übergebe? Vielen DanK!



  • Den Zeiger auf die Bits hast du doch bereits (pPixel), also entweder speicherst du ihn irgendwo oder du gehst den längeren Weg über GetObject (füllt in dem Fall eine DIBSECTION-Struktur, die wiederum eine Bitmap-Struktur enthält. Diese wiederum enthält den Zeiger auf die Pixeldaten).

    Diesen Zeiger kannst du nun nehmen und die Daten schreiben, du musst aber darauf achten, dass die Zeilen DWORD-aligned sind, die Größe einer Zeile im Speicher entspricht nicht zwangsläufig der tatsächlichen Größe der Bitmap.

    stride = 4*((width*bitCount+31) / 32);
    


  • Wo und wie wird denn

    CreateBitmapFromPixels(HDC hDC, UINT uWidth, UINT uHeight, UINT uBitsPerPixel, LPVOID pBits)
    

    aufgerufen ?

    CreateDIBSection(  ... NULL.0)
    

    If hSection is NULL, the system allocates memory for the DIB.

    Wo soll der Speicher denn wieder freigegeben werden ?

    Wenn die Groesse bekannt ist kann man den Speicher besser einmal selbst
    allokieren, als das jedes Mal automatisch wieder zu veranlassen.

    Wenn das mit memcopy funktionieren soll muss die Bitmap ohnehin zum aktuellen
    Device-Context passen, also auch alles bekannt sein.
    (Hoehe, Breite, Bittiefe, ...)

    Was passiert wenn der Anwender die Grafikeinstellungen ändert ?

    Der Zusammenhang zwischen HBITMAP und Bitmap Struktur ist klar?

    Funktionierennder Code siehe:
    https://msdn.microsoft.com/en-us/library/windows/desktop/dd183402%28v=vs.85%29.aspx


Anmelden zum Antworten