Bitmap in Bitmap malen



  • Guten Morgen,

    ich bin Neuling in OOP und arbeite mich seit einigen Wochen in die GUI-Programmierung ein. Ich würde mich freuen, wenn jemand mir bei dem folgenden Problem auf die Sprünge helfen könnte:

    Ich möchte in ein Bitmap, das in einem MDI-Fenster angezeigt wird, weitere kleine Bitmaps und/oder Text einfügen, und zwar so, dass diese "Intarsien" am Schluss zu dem Bitmap gehören und mit ihm abgespeichert werden. Das Einfügen möchte ich per Mausklick vornehmen. Ich habe bis jetzt mit TextOut experimentiert, aber das wird nicht in die Bitmap übernommen.
    Ich speichere die Mauskoordinaten in einer Membervariablen der View-Klasse, also könnte OnDraw den Punkt auslesen. Aber wie krieg ich die Bitmaps verschmolzen?

    Vielen Dank für jede Hilfe,
    Wind 😕



  • Ich bin jetzt alles andere als ein Experte...
    Was Du machen musst ist dich mit DCs auseinandersetzen... Du kannst ein Bitmap in einen DC laden auf diesem DC rumzeichnen und Ihn dann wieder zurueck in ein Bitmap kopieren...
    Da sollte auch gehen wenn Du nachtraeglich Bitmaps auf ein Bitmap "klebst"...
    Finde die Materie der Device Contexte leider auch raltiv haarig weswegen ich mich mal mit weiterem Geschwaller zurueckhalte...
    Helge.



  • guf-cryptkeeper schrieb:

    ...und Ihn dann wieder zurueck in ein Bitmap kopieren...

    Vielen Dank, Helge. Ich bin jetzt soweit, dass die Bitmap eingefügt wird und auch beim OnPainten nicht verloren geht.
    Irgendwie müsste ich jetzt aber diese Kombination zum neuen DC machen, so dass sie erhalten bleibt, wenn ich weitere Bitmaps hinzufüge.

    Wie kopiere ich also den DC zurück in die Bitmap?

    Wind



  • Hi nochmal. Wie gesagt ich moechte mich nicht mit fremden Federn schmuecken aber ein nettes Forumsmitglied von hier hat mir auf Basis dieser Funktion geholfen :-)...

    //
    //Function recommended by Rapha... Copy Device Context to Bitmap File
    //
    // Diese Funktion wird nicht mehr benötigt, da sie in Serialize kopiert wurde
    
    int CDispBmpDoc::dc2bitmap(HDC hdc, int width, int height, CString filename)
    {
    	HDC hdc2;
        HBITMAP aBmp;
        BITMAPINFO bi;
        HGDIOBJ OldObj;
        void *dibvalues;
        HANDLE fileHandle;
    
        BITMAPFILEHEADER bmfh;
        BITMAPINFOHEADER bmih;
            DWORD bytes_write;
        DWORD bytes_written;
    
        hdc2=CreateCompatibleDC(hdc);
    
        ZeroMemory(&bmih,sizeof(BITMAPINFOHEADER));
        bmih.biSize=sizeof(BITMAPINFOHEADER);
          bmih.biHeight=height;
            bmih.biWidth=width;
            bmih.biPlanes=1;
            bmih.biBitCount=24;
        bmih.biCompression=BI_RGB;
        bmih.biSizeImage = ((((bmih.biWidth * bmih.biBitCount) + 31) & ~31) >> 3) * bmih.biHeight;
            bmih.biXPelsPerMeter = 0;
            bmih.biYPelsPerMeter = 0;
            bmih.biClrImportant = 0;
        //bmih.biSizeImage=(3*bmih.biHeight*bmih.biWidth);
            //bmih.biSizeImage = 0;
    
        bi.bmiHeader=bmih;
    
        aBmp=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,(void**)&dibvalues,NULL,NULL);
    
        if (aBmp==NULL)
        {
            OutputDebugString("CreateDIBSection failed!\n");
            return 0;
        }
    
        OldObj=SelectObject(hdc2,aBmp);
        BitBlt(hdc2,0,0,width,height,hdc,0,0,SRCCOPY);
    
        ZeroMemory(&bmfh,sizeof(BITMAPFILEHEADER));
        bmfh.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
        bmfh.bfSize=(3*bmih.biHeight*bmih.biWidth)+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
            bmfh.bfType=0x4d42;
            bmfh.bfReserved1 = 0;
            bmfh.bfReserved2 = 0;
    
        fileHandle=CreateFile(filename,GENERIC_READ | GENERIC_WRITE,(DWORD)0,NULL,
                                                        CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,(HANDLE) NULL);
        if (fileHandle==INVALID_HANDLE_VALUE)
        {
            OutputDebugString("CreateFile failed!\n");
            return 0;
        }
    
            // Write the BITMAPFILEHEADER
            bytes_write=sizeof(BITMAPFILEHEADER);
        if (!WriteFile(fileHandle,(void*)&bmfh,bytes_write,&bytes_written,NULL))
        {
            OutputDebugString("WriteFile failed!\n");
            return 0;
        }
    
            //Write the BITMAPINFOHEADER
        bytes_write=sizeof(BITMAPINFOHEADER);
        if (!WriteFile(fileHandle,(void*)&bmih,bytes_write,&bytes_written,NULL))
        {
            OutputDebugString("WriteFile failed!\n");
            return 0;
        }
    
            //Write the Color Index Array???
            bytes_write=bmih.biSizeImage;//3*bmih.biHeight*bmih.biWidth;
        if (!WriteFile(fileHandle,(void*)dibvalues,bytes_write,&bytes_written,NULL))
        {
            OutputDebugString("WriteFile failed!\n");
            return 0;
        }
    
        CloseHandle(fileHandle);
    
        DeleteObject(SelectObject(hdc2,OldObj));
        DeleteDC(hdc2);
    
        return 1;
    }
    

    Bei mir ist diese Funktion in die Serialize Funktion "eingebaut"...

    void CDispBmpDoc::Serialize(CArchive& ar)
    {
    	if (ar.IsStoring())
    	{
    		// Bitmap speichern
    		/* Dazu hab ich einfach den Code von dc2bitmap kopiert und leicht modifiziert (anstatt WriteFile: ar.Write etc)*/
    
    		HDC hdc2;
    		HBITMAP aBmp;
    		BITMAPINFO bi;
    		HGDIOBJ OldObj;
    		void *dibvalues;
    
    		BITMAPFILEHEADER bmfh;
    		BITMAPINFOHEADER bmih;
    		DWORD bytes_write;
    
    		hdc2=CreateCompatibleDC((HDC)m_ImageDC);
    
    		ZeroMemory(&bmih,sizeof(BITMAPINFOHEADER));
    		bmih.biSize=sizeof(BITMAPINFOHEADER);
    		bmih.biHeight=m_Height;
    		bmih.biWidth=m_Width;
    		bmih.biPlanes=1;
    		bmih.biBitCount=24;
    		bmih.biCompression=BI_RGB;
    		bmih.biSizeImage = ((((bmih.biWidth * bmih.biBitCount) + 31) & ~31) >> 3) * bmih.biHeight;
    		bmih.biXPelsPerMeter = 0;
    		bmih.biYPelsPerMeter = 0;
    		bmih.biClrImportant = 0;
    		//bmih.biSizeImage=(3*bmih.biHeight*bmih.biWidth);
    			//bmih.biSizeImage = 0;
    
       		bi.bmiHeader=bmih;
    
    		aBmp=CreateDIBSection((HDC)m_ImageDC,&bi,DIB_RGB_COLORS,(void**)&dibvalues,NULL,NULL);
    
    		if (aBmp==NULL)
    		{
    			OutputDebugString("CreateDIBSection failed!\n");
    			return;
    		}
    
    		OldObj=SelectObject(hdc2,aBmp);
    		BitBlt(hdc2,0,0,m_Width,m_Height,(HDC) m_ImageDC,0,0,SRCCOPY);
    
    		ZeroMemory(&bmfh,sizeof(BITMAPFILEHEADER));
    		bmfh.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
    		bmfh.bfSize=(3*bmih.biHeight*bmih.biWidth)+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
    		bmfh.bfType=0x4d42;
    		bmfh.bfReserved1 = 0;
    		bmfh.bfReserved2 = 0;
    
    		// Write the BITMAPFILEHEADER
    		bytes_write=sizeof(BITMAPFILEHEADER);
    		ar.Write((void*)&bmfh, bytes_write);
    
    		//Write the BITMAPINFOHEADER
    		bytes_write=sizeof(BITMAPINFOHEADER);
    		ar.Write((void*)&bmih,bytes_write);
    
    		//Write the Color Index Array???
    		bytes_write=bmih.biSizeImage;//3*bmih.biHeight*bmih.biWidth;
    		ar.Write((void*)dibvalues,bytes_write);
    		DeleteObject(SelectObject(hdc2,OldObj));
    		DeleteDC(hdc2);
    	}	
    	else
    	{
    		// Ein Bitmap wird geladen
    		/* Dinge die erledigt werden müssen:
    		1. Bitmap in m_hBitmap laden
    		2. Größe des Bitmaps bestimmen und in den Variablen speichern
    		3. Das BildDC mit dem Bitmap verbinden
    		*/
    		if (ImageExists()) // sicherheitshalber
    			DeleteImage();
    
    		// 1. Bitmap laden
    		m_hImage = (HBITMAP) ::LoadImage(0,ar.m_strFileName, IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
    
    		// 2. Größe des Bitmaps bestimmen
    		BITMAP bm;
    		::GetObject(m_hImage, sizeof(bm), &bm);
    		m_Height = bm.bmHeight;
    		m_Width = bm.bmWidth;
    
    		// 3. Das DC (mit dem Bitmap) soll für die Ausgabe (dh. zum "Bildschirm") kompatibel sein
    		//    Ein Weg ist, ein DC auf den Desktop zu erhalten
    		CClientDC DesktopDC(NULL); // ein kleiner "Trick" um and das DC des Desktops (d.h. des "ganzen Bildschirms") zu kommen
    		m_ImageDC.CreateCompatibleDC(&DesktopDC);
    		m_ImageDC.SelectObject(m_hImage);
    
    		/* Zu Demstrationszwecken:
    		Über m_IMageDC kann man jetzt Operationen auf das Bild ausführen, z.B.
    		 - Pixel mit Get/SetPixel lesen/setzen
    		 - Malen (LinTo, FillRect, FillSolidRect, etc)
    		 - ...
    		 Um den Text rechts unten im Bild zu löschen einfach diesen Abschnitt löschen
    		 */
    		RECT rect;
    		rect.left = m_Width - 210;
    		rect.right = m_Width;
    		rect.top = m_Height - 40;
    		rect.bottom = m_Height;
    		m_ImageDC.FillSolidRect(&rect, RGB(255,255,0));
    		m_ImageDC.Draw3dRect(&rect, RGB(200,200,200), RGB(0,0,0));
    		COLORREF OldTextColor = m_ImageDC.SetTextColor(RGB(0,0,0));
    		COLORREF OldBgColor = m_ImageDC.SetBkColor(RGB(255,255,0));
    		m_ImageDC.TextOut(rect.left+5, rect.top+5, "Funktionstest (um zu löschen");
    		m_ImageDC.TextOut(rect.left+5, rect.top+23, "siehe CDispBmpDoc::Serialize)");
    		m_ImageDC.SetTextColor(OldTextColor);
    		m_ImageDC.SetBkColor(OldBgColor);
    		/* Ende des Abschnitts */
    	}
    }
    

    Ich hoffe auf Basis dieser Code Schnipsel kommst Du weiter...
    Ich konnte zumindest die Bitmap mit Rechtecken/Strichen was auch immer versehen und speichern. Viel Glueck und Erfolg,
    Helge.



  • Cool 🙂
    Vielen Dank, Helge.

    Lieben Gruß, auch an den edlen Spender.
    Wind


Anmelden zum Antworten