CDC Objekt mit CImage als bmp speichern



  • Hallo zusammen,

    also ich surfe jetzt schon seid heut morgen im Forum herum.

    Ich muss mein gezeichnetes CDC Objekt nun als bmp File ablegen.

    Ich bin schonmal so weit gekommen, dass ich weiß, dass ich des mit CImage machen muss.

    Aber irgendwie komm ich da grad net weiter.

    CImage test;
    test.Attach((HBITMAP)pDC);     //pDC ist mein CDC Objekt
    test.Save("C://test123.bmp");
    

    Das Attachen macht er schon nicht.

    Was mach ich denn falsch?



  • Hallo,

    du musst schon ein richtiges HBITMAP übergeben, so "zwingst" du ein CDC-Objekt ein HBITMAP zu sein, was zwar den Compiler zufrieden stellt, aber sicher keine Bitmap ist.

    MfG,

    Probe-Nutzer



  • hi,

    also ich hab das jetzt hier:

    CImage Image;
     HDC       hScrDC, hMemDC;
     HBITMAP    hBitmap, hOldBitmap;
     int       nX, nY, nX2, nY2;
     int       nWidth, nHeight;
     hScrDC = this->pDC->m_hDC;
        hMemDC = CreateCompatibleDC(hScrDC);
        nX = 0;
        nY = 0;
        nX2 = GetDeviceCaps(hScrDC, HORZRES);
        nY2 = GetDeviceCaps(hScrDC, VERTRES);
        nWidth = nX2 - nX;
        nHeight = nY2 - nY;
     hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);
        hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
     BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);
        hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);
        DeleteDC(hScrDC);
        DeleteDC(hMemDC); 
    
    Image.Attach(hBitmap);
    
    // save an image in BMP format, even though jpg file extension is used
    	Image.Save("c:\\image.jpg");
    

    er speichert schonmal ein bild, aber er nimmt irgendeinen bereich vom gesamten screen und wohl nicht den bereich von meinem pDC Objekt, wo ich schon drauf gezeichnet hab (Zeile 6: hScrDC = this->pDC->m_hDC;)



  • Hab das mal schnell ausprobiert und komme da mit nem 4 Zeiler hin.

    //Bitmap holen pDC muß ein Zeiger auf ein gültiges DC sein
    	HBITMAP bitmap = (HBITMAP)this->pDC->GetCurrentBitmap()->GetSafeHandle();
            //CImage erstellen
    	CImage Image;
            //Bitmap zuweisen
    	Image.Attach(bitmap);
            //Bitmap speichern
    	Image.Save("c:\\image.jpg");
    

    Gruß Matthias



  • hi

    ich will dir da jetzt nix, aber weiterhin das problem bei Attach 😞



  • Was für ein problem mit Attach? Hab das ganze auch nur mit dem DC des dialoges versucht solle aber auch mit jedem anderen ClientDC laufen, der eine eigene Bitmap hat. Wobei wenn Du irgendwo reinzeichnest mußt du doch auch die entsprechende Bitmap dazu haben.

    Gruß Matthias



  • Hi
    ich muss auch so etwas machen und hab die code von CTecS/Matthias eingebaut...
    doch ich bekomme den Fehler
    Debug Assertion Failed!
    in File: atlimage.h Line 1568
    Expression: nBytes == sizeof( BITMAP) 😕

    ich vermute die Bitmap ist einfach zu groß o.ä.
    ich würde gerne vor der speicherung das bild einfach schneiden (nicht verkleinern, sondern einfach abschneiden was ich nicht brauche) oder von anfang an eine begrenzung bei der erstellung der bitmap, doch ich hab dazu keine methoden gefunden... 😞

    kann mir jemand weiterhelfen?



  • Ich denke zwar nicht das dein Problem die größe deiner Bitmap is, aber wenn du das Bitmap beschneiden willst, geht das doch ganz einfach. Erstelle ein neues Bitap in der gewünschten Zielgröße und blitte den gewünschten ausschnitt aus der Quelle in das Ziel. Zum Schluß Ziel Speichern und fertig.

    Gruß Matthias



  • so... hab das nun ein bissel anders gemacht...
    und zwar hab ich mir gedacht ich zeichne das gleich in ne bitmap...
    so bin ich auch gleich das Attach-Problem los... es kommt kein fehler mehr.
    doch leider ist meine bitmap vollkommen schwarz... weiß jemand, wo das problem liegen könnte...
    wird da nichts reingezeichnet, oder speichert er den falschen bereich...

    hier die draw-funktion mit eingebauter bitmap speicherung:

    void CPOCView::OnDraw(CDC* pDC)
    {
    	GetClientRect(&crect);
    	CPOCDoc* pDoc=(CPOCDoc*)GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc) return;
    
    	int w=(int)((double)pDoc->PLAYGROUND_WIDTH*pDoc->zoomfac);
    	int h=(int)((double)pDoc->PLAYGROUND_HEIGHT*pDoc->zoomfac);
    
    	pDC->SetWindowOrg(0,h);
    	pDC->SetWindowExt(w,-h);
    
    	int i;
    
    	if (!(pDoc->clickmode==CLICK_COMP_ACTIVE || pDoc->clickmode==CLICK_NODE_ACTIVE) && pDoc->SHOWLEGEND)
    	{
    		DrawLegend(pDC,pDoc);
    	}
    
    	for (i=0;i<pDoc->numcomponents;i++)
    	{
    		DrawComponent(pDC,pDoc,i);
    	}
    	if (!(pDoc->clickmode==CLICK_COMP_ACTIVE && pDoc->toolmode==TOOL_MOVE))
    	{
    		for (i=0;i<pDoc->N;i++)
    		{
    			for (int j=0;j<i;j++)
    			{
    				DrawLink(pDC,pDoc,i,j);
    			}
    		}
    		for (i=0;i<pDoc->N;i++)
    		{
    			DrawNode(pDC,pDoc,i);
    		}
    	}
    
    	pDC->MoveTo(0,0);
    	pDC->LineTo(0,h);
    	pDC->LineTo(w,h);
    	pDC->LineTo(w,0);
    
    	if(pDoc->getCreateBMP() == true)
    	{
    		//to enter the if-area just one time fpr each file
    	    pDoc->setCreateBMP(false);
    
    		//create a DC for drawing directly in a bitmap
    	    CDC pDC2;
    	    pDC2.CreateCompatibleDC(pDC);
    	    pDC2.SetMapMode(MM_TEXT);
    	    pDC2.SetWindowOrg(0,h);
    	    pDC2.SetWindowExt(w,-h);
    
    	    CRect rcClip, rcClient;
        	    pDC->GetClipBox( &rcClip );
           	    GetClientRect(&rcClient);
    
    		//Select a compatible bitmap into the bitmap DC
        	    CBitmap bitmap;
        	    bitmap.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height());
        	    pDC2.SelectObject( &bitmap );
    
           		//Set clip region to be same as that in draw DC
        	    CRgn rgn;
        	    rgn.CreateRectRgnIndirect( &rcClip );
        	    pDC2.SelectClipRgn(&rgn);
        	    rgn.DeleteObject();
    
    		//now drawing into the bitmap
    	    CPOCView::OnDraw(&pDC2);
    
    		//CImage erstellen
    	    CImage image;
    		//Bitmap zuweisen
    	    image.Attach(bitmap);
    
    		//Bitmap speichern
    	    image.Save(L"C:\\test.bmp"); /*TODO: ersetzen durch pDoc->OnBMPCreation()*/
    
    	}
    }
    

    ab zeile 46 geht der abschnitt für die bitmap erstellung los
    doch wie gesagt, speichert er nur eine schwarze bitmap-datei ab



  • Also nur mal schnell drüber geschaut is mir aufgefallen:

    1. was brauchst du SetMapMode,SetWindowOrg,SetWindowExt in deinem memdc
    2. was soll die clipbox bewirken wenn du die
    3. zum erstellen einer Rectrgn die du dann
    4. nachdem du die in deinem memdc selectiert hast gleich wieder löschst
    5. übergibst du ondraw deine memdc, weiss net ob das geht weil ich hab immer aus dem screendc und den memdc mit bitblt geblittet

    so das ist meine 5 punkte plan zu deiner ondraw 😉

    viel erfolg



  • oh man... ein problem nach dem anderen 😞
    also danke erstmal für deine hilfe... hab das jetzt über bitblt gemacht, ohne onDraw(...) nochmal aufzurufen.
    und endlich hab ich tatsächlich ein halbwegs vernünftiges farbiges bild.

    doch das bild das ich nun bekomme ist horizontal gespiegelt... ich vermute es liegt daran, dass das ursprungs cdc (das pdc) von unten nach oben schreibt (hab ich nicht selber geschrieben, sondern so bekommen)

    gibt es eine möglichkeit, das ganze gleich gespiegelt zu blitten?
    oder muss man es danach spiegeln, und wenn das so ist, wie macht man das?

    mit dem code hab ich's geblittet (ab dem if):

    if(pDoc->getCreateBMP() == true)
    	{
    			//to enter the if-area just one time for each file
    		pDoc->setCreateBMP(false);
    
    			//create a DC for drawing directly in a bitmap
    		CDC memDC;
    		memDC.CreateCompatibleDC(pDC);
    
    		CRect rcClip, rcClient;
        	pDC->GetClipBox( &rcClip );
    
           	GetClientRect(&rcClient);
    
    			//Select a compatible bitmap into the bitmap DC
        	CBitmap bitmap;
        	bitmap.CreateCompatibleBitmap(pDC, w, h);
        	memDC.SelectObject( &bitmap );
    
    			//now drawing into the bitmap
    		memDC.BitBlt( rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(), pDC,rcClip.left, rcClip.top, SRCCOPY );
    
    			//CImage erstellen
    
    		CImage image;
    			//Bitmap zuweisen
    		image.Attach(bitmap);
    		image.DIBOR_TOPDOWN;
    			//Bitmap speichern
    		image.Save(L"C:\\test.jpg");
    
    	}
    

    gruß
    Kleriker



  • und warum stellst du den SetWindowOrg() und SetWindowExt() vor dem Blitten nicht wieder auf 0? sollte doch dann alles wieder normal sein und benötigen tust du das doch so und so nicht mehr



  • das hab ich schon probiert, das bringt nichts...
    entweder bekomm ich ein ganz schwarzes bild, oder trotzdem nur spiegelverkehrt...



  • keine andere idee? 😞



  • na dan dreh doch einfach das bild zu fuß oder schau mal bei codeproject.com vorbei, vielleicht findest du ne klasse die das gleich mit kann



  • also per hand umdrehen, kann man schon vergessen... jedenfalls nach der pixel für pixel methode... 👎

    ich hab aber das hier gefunden.
    da spiegelt einer das bild der funktion render von der klasse IPicture
    leider stürzt das prog bei mir während des render-befehls ab

    pIPic->Render(hDC, zeichenflaeche.left, zeichenflaeche.bottom, zeichenflaeche.Width(), -zeichenflaeche.Height(), 0, hmHoehe, hmWeite, -hmHoehe, NULL);
    

    schon mal jemand damit gearbeit und kann mir sagen, ob hier ein fehler drin steckt
    und wie man mit der dieser Klasse IPicture umgeht?



  • wieso kannst du das net Pixelweise swapen, du darfst nur net getpixel und setpixel nehmen das wird der unfug elend langsam, aber wenn du dir die rohdaten also das bitmap-array geben lässt dann geht das fix. aber wenn du willst nimm das, is aus net klasse von mir habs etwas umgeschrieben und natürlich net getestet 😃

    void FlipPicture(CBitmap &BM,BOOL Horizontal)
    {
    	BITMAP     bm;
    	BM.GetObject(sizeof(BITMAP), (LPSTR)&bm);
    
    	BYTE *bmpBufferSource = new BYTE[ bm.bmWidthBytes*bm.bmHeight ];//allocate memory for image 
                                                  //byte buffer
    	BYTE *bmpBufferDest = new BYTE[ bm.bmWidthBytes*bm.bmHeight ];//allocate memory for image 
                                                  //byte buffer
    
    	ULONG dwValue=BM.GetBitmapBits(bm.bmWidthBytes*bm.bmHeight,
                       bmpBufferSource);//Get the bitmap bits  
                                  //into a structure*/
    
    	if(Horizontal == TRUE)
    	{
    		for(LONG Count = 0;Count < bm.bmHeight;Count++)
    		{
    			BYTE *Source = &bmpBufferSource[bm.bmWidthBytes*(Count+1)];
    			BYTE *Dest = &bmpBufferDest[bm.bmWidthBytes*Count];
    			__asm
    			{
    			mov ECX,bm.bmWidthBytes;
    			mov	EDX,Source;
    			mov EBX,Dest;
    	next:
    			mov EAX,[EDX]
    			mov [EBX],EAX
    			lea	EDX,[EDX-4]
    			lea	EBX,[EBX+4]
    			sub ECX,4
    			jnz next
    			}
    		}
    	}
    	else
    	{
    		for(LONG Count = 0;Count < bm.bmHeight;Count++)
    		{
    			BYTE *Source = &bmpBufferSource[bm.bmWidthBytes*(bm.bmHeight-Count-1)];
    			BYTE *Dest = &bmpBufferDest[bm.bmWidthBytes*Count];
    			__asm
    			{
    			mov ECX,bm.bmWidthBytes;
    			mov	EDX,Source;
    			mov EBX,Dest;
    	next1:
    			mov EAX,[EDX]
    			mov [EBX],EAX
    			lea	EDX,[EDX+4]
    			lea	EBX,[EBX+4]
    			sub ECX,4
    			jnz next1
    			}
    		}
    
    	}
    	dwValue = BM.SetBitmapBits(bm.bmWidthBytes*bm.bmHeight,bmpBufferDest);
    
    	delete bmpBufferSource;
    	delete bmpBufferDest;
    }
    

    wenn das immer noch zu lansam is weiss ich auch net

    gruß



  • wow stark... funktionert ohne probleme 👍 👍 👍
    recht herzlichen, tief empfundenen, wirklich ernst gemeinten, Vielen Dank 😃


Log in to reply