RGB Datenstrom auf Dialog zeichnen - wie am besten?



  • hallo,

    ich möchte aus einem Byte strom (RGB-Farbmodell) das bild auf einen dialog zeichnen.

    Nun bin ich mir aber nicht so richtig sicher, ob ich den richtigen ansatz verfolge. Mein gedanke war alles selbst zu machen ... also irgendwie über diese dc geschichte pixel für pixel zu zeichnen.

    Da ich aber eine ganze serie von bildern nacheinander ausgeben will, müsste es natürlich auch ein bisschen performance-optimiert von statten gehen.

    Nun meine frage: wär mein ansatz denn sehr resourcenfressend, so dass es sich gar nicht lohnt die idee weiterzuverfolgen, wenn ja, welche anderen möglichkeiten habe ich aus einem reinen RGB-Datenstrom ein bild zu erzeugen (natürlich könnte ich die breite und höhe des bildes einer potentiellen funktion mitliefern).
    Wenn der ansatz gut sein sollte, würde ich mich über ein link zu dem thema freuen ... also sprich: wie zeichne ich auf einen dialog.

    Mit der Forumssuche komm ich im moment leider gar nicht zurecht. Bekomme nie ordentliche ergebnisse ... und vorallem ganz wenige ... habt ihr ähnliche erfahrung diesbezüglich?

    danke schonmal,
    mfg, TFTS



  • ich hab es jetzt mit SetPixelV(...) versucht ... es ist eindeutig zu langsam. man kann zugucken wie das bild gezeichnet wird. Also brauche ich eine alternative. Irgendwas wo ich den reinen RGBDatenstrom reinschieben kann.

    Kann mir da jemand weiterhelfen?

    danke schonmal

    mfg, TFTS



  • Versuch mal einen virtuellen DC mit SetPixelV(...) zu füllen und dann per dc.BitBlt(...,vDC,...) darzustellen.

    Viel Erfolg!

    connan



  • hallo connan,
    danke für deine antwort

    wo finde ich informationen zu diesem virtuellen dc? hab eben mal gegoogled ... da find ich nix gescheites zu

    mfg, TFTS



  • Sammel die Pixel in einem Feld, die übergibst du dann einem CBitmap in der create-Methode, was du in den CDC blitten kannst. KLappt aber nur wenn das Format des Bildes stimmt.



  • Sorry, war etwas ungenau also ich erzeuge meine 'virtuellen DC's' auf folgende weise (meist so wie hier als Member schon im Konstruktor):

    CMyViewClass::CMyViewClass() //z.B: public CView
    {
        m_pDC=new CDC;
        m_pBitmap= new CBitmap;
    
        m_pDC->CreateCompatibleDC(NULL);
        m_pBitmap->CreateBitmap( nBreite, nHöhe,1 ,32 ,NULL );
        m_pDC->SelectObject(m_pBitmap);
    }
    
    virtual void CMyViewClass::OnDraw(CDC* pDC)
    {
          pDC->BitBlt(..., m_pDC, ..., SRCCOPY);
    }
    
    void CMyViewClass::Draw()
    {
         while(...)
         {
             m_pDC->SetPixelV(...);
         }
    
         this->Invalidate(FALSE); //FALSE da du ja selbst neu zeichnest
    }
    

    Ich hoffe es ist jetzt verständlicher. Viel schneller geht es mit GDI glaube ich nicht mehr.

    Achso, zur suche: Versuche mal Deinen Suchbegriff in Sternchen zu packen also z.B. *float*



  • das sieht schonmal gut aus ... lässt sich das auch irgendwie in eine dialog basierende anwendung portieren, oder ist eine dialog basierende anwendung für solche zwecke völlig ungeeignet.
    bzw. ich kann ja auch eine View klasse erstellen ... aber wie muss ich mir dass dann vorstellen ... poppt sich dann einzusätzliches fenster auf, wenn ich das bild darstellen lasse oder bekomm ich das auch irgendwie auf meinen Dialog?

    dann fehlt mir auch noch ein bisschen der durchblick bei der abfolge der funktionen... ich vermute mal die ondraw funktion wird automatisch aufgerufen wenn ein document(?) gezeichnet wird. aber wann werden wie die anderen funktionen gestartet?

    und dann noch eine frage zur geschwindigkeit:
    wird es nur dadurch schneller, wenn ich vorher (also bevor ich die bildsequenz ablaufen lassen, alle pixel bereits als bitmap zusammengefasst hab? oder ist es auch schneller, wenn ich das dann erst machen während ich die bilder darstelle. Logisch würde mir erscheinen, dass ich das vorher machen müsste. Das wär aber dann ja wieder recht speicherintensiv, da ja die ganzen bilddaten im speicher gehalten werden, richtig?

    das mit den sternchen (*) hab ich beim suchen auch probiert. aber sobald man nach mehreren begriffen (mit AND verknüpft) sucht wirds echt dünn bei den ergebnissen.

    mfg, TFTS



  • TFTomSun schrieb:

    das sieht schonmal gut aus ... lässt sich das auch irgendwie in eine dialog basierende anwendung portieren, oder ist eine dialog basierende anwendung für solche zwecke völlig ungeeignet.
    bzw. ich kann ja auch eine View klasse erstellen ... aber wie muss ich mir dass dann vorstellen ... poppt sich dann einzusätzliches fenster auf, wenn ich das bild darstellen lasse oder bekomm ich das auch irgendwie auf meinen Dialog?

    Na klar lässt sich das auch für einen Dialog implementieren, genauer müsste es für die meisten von CWnd abgeleiteten Klassen funktionieren. Für den Dialog kannst Du entweder immer BitBlt aufrufen wenn Du willst das was gezeichnet wird o. du Überschreibst die OnPaint und machst es da, hat den Vorteil das man jetzt nur noch Invalidate(FALSE) aufrufen muss um die DC's zu 'swapen'.
    Ansonsten, wenn Du auf den DC eines Dialogs zugreifst wir rigoros (?) über den Dialog gezeichnet je nachdem wo Du die Basisversion von OnPaint aufrufst werden die Steuerelemente überzeichnet o. nicht (ein Fenster geht nicht auf).

    TFTomSun schrieb:

    dann fehlt mir auch noch ein bisschen der durchblick bei der abfolge der funktionen... ich vermute mal die ondraw funktion wird automatisch aufgerufen wenn ein document(?) gezeichnet wird. aber wann werden wie die anderen funktionen gestartet?

    OnDraw wird über Invalidate aufgerufen. Draw() ist nur ein Beispiel wie Deine Zeichnungsfunktion aussehen könnte.

    TFTomSun schrieb:

    und dann noch eine frage zur geschwindigkeit:
    wird es nur dadurch schneller, wenn ich vorher (also bevor ich die bildsequenz ablaufen lassen, alle pixel bereits als bitmap zusammengefasst hab? oder ist es auch schneller, wenn ich das dann erst machen während ich die bilder darstelle. Logisch würde mir erscheinen, dass ich das vorher machen müsste. Das wär aber dann ja wieder recht speicherintensiv, da ja die ganzen bilddaten im speicher gehalten werden, richtig?

    Erstmal richtig, aber schneller wird es dadurch, dass eben nicht jeder Punkt einzeln auf den Bilschirm gezeichnet werden muss, sonder erst mal im virtuellen DC im Speicher abgelegt wird und dann als Ganzes übertragen wird. Das selbe lässt sich sicher auch mit einem Array erreichen aber eh man da SetPixel o.ä. implementiert hat...

    mfg connan



  • hallo,

    so richtig klappt es noch nicht. ich weiss nicht wie ich die virtuelle funktion erstelle. kann ich die überhaupt direkt in meiner Dialogklasse erstellen?

    was ich bis jetzt gemacht habe.
    ich habe die membervariablen in meiner dialog klasse erstellt:

    CBitmap* m_pBitmap;
    	CDC* m_pDC;
    

    ich habe in der OnInitDialog die initialisierung der pointer vorgenommen:

    nBreite=1600;
    	nHoehe=1200;
    	m_pDC=new CDC; 
        m_pBitmap= new CBitmap;   
        m_pDC->CreateCompatibleDC(NULL); 
        m_pBitmap->CreateBitmap( nBreite, nHoehe,1 ,32 ,NULL ); 
        m_pDC->SelectObject(m_pBitmap);
    

    ich habe eine funktion die über eine Button funktion aufgerufen wird erstellt:

    void CJpglibDlg::BytestreamToDialog()
    {
    	UpdateData(true);
    	int x,y;
    	int breite;
    	int hoehe;
    	int byte_nr;
    	int i;
    	byte_nr=0;
    	CDC *dd;					//by TFTS created: farbige Legenden Quadrate löschen
    
    	breite = int(m_width);
    	hoehe = int(m_height);
    	dd = GetDC();
    
    		byte_nr=0;
    		for(y=1;y<=hoehe;y++)
    		{
    			for(x=1;x<=breite;x++)
    			{
    
    				m_pDC->SetPixelV( x,y, RGB(RGBbuffer[byte_nr],RGBbuffer[byte_nr+1],RGBbuffer[byte_nr+2]));
    				byte_nr=byte_nr+3;
    			}
    		}
    
    	//dd->BitBlt(10,10,x,y, m_pDC,x,y, SRCCOPY); 
    
    }
    

    ... ich denke mal es wird noch so einiges nicht stimmen ... aber trotzdem schonmal danke für deine geduld



  • Erstmal ??? 🙂
    Das sieht doch schon ganz gut aus!
    Die auskommentierte Zeile dd->BitBlt(...) müsste eigentlich schon ihren Dienst leisten. Zumindest in dem Moment, in dem der Button gedrückt wird sollte etwas zu sehen sein!?
    Edit:mit dem x,y stimmt was noch nicht, das zweite Pärchen muss 0,0 sein und das erste wenn schon x+10,y+10 :).
    Die virtuelle Funktion ( in Deinem Fall OnPaint() ) sollte schon existieren, da das Anwendungsgerüst noch etwas zusätzlichen Code für die Darstellung als Icon erzeugt. Falls Du alles manuell erstellt hast, must Du OnPaint() selbst überschreiben (virtuell). Aber ist halt nur eine eleganter Variante, der Aufruf von BitBlt müsste eigentlich reichen.
    Ach und, was genau geht eigentlich nicht? 😉



  • hallo,

    danke für deine antwort. die OnPaint() wird doch aber aufgerufen sobald irgendetwas an dem fenster verschoben wird, oder wenn es minimiert wird. ich möchte jedoch das zeichnen meiner bitmaps per button auslösen ... also im prinzip so wie es ist.

    Das Problem ist ... er malt nix. kein bild ... nichts. kann das daran liegen, dass er das bitmap nicht zeichnet wenn das fenster nicht groß genug dafür ist?

    Außerdem denke ich, dass es so wie es jetzt ist, auch noch nicht schneller ist als wenn ich jedes pixel einzeln zeichne ... ich müsste ja im prinzip das ganze SetPixelV() zeug in eine andere funktion (so eine art preloader) packen... oder?

    mfg, TFTS

    PS:

    dd->BitBlt(0,0,m_width,m_height, m_pDC,0,0, SRCCOPY);
    

    so hab ichs jetz ...

    x
    Specifies the logical x-coordinate of the upper-left corner of the destination rectangle.
    y
    Specifies the logical y-coordinate of the upper-left corner of the destination rectangle.
    nWidth
    Specifies the width (in logical units) of the destination rectangle and source bitmap.
    nHeight
    Specifies the height (in logical units) of the destination rectangle and source bitmap.
    pSrcDC
    Pointer to a CDC object that identifies the device context from which the bitmap will be copied. It must be NULL if dwRop specifies a raster operation that does not include a source.
    xSrc
    Specifies the logical x-coordinate of the upper-left corner of the source bitmap.
    ySrc
    Specifies the logical y-coordinate of the upper-left corner of the source bitmap.
    dwRop
    Specifies the raster operation to be performed. Raster-operation codes define how the GDI combines colors in output operations that involve a current brush, a possible source bitmap, and a destination bitmap. See BitBlt in the Platform SDK for a list of the raster-operation codes for dwRop and their descriptions

    ... the upper left corner ... kann ja bei beiden 0 sein ... wobei nWitdh und nHeight ja schon die breite und höhe des bildes sein sollten oder?



  • was muss ich mir eigentlich unter der "upperleft corner" von meiner source bitmap vorstellen ... das ist doch nur ein haufen RGB werte...



  • Also so wie ich's verstanden hab ist das der Punkt deines Bitmaps welcher an die Stelle von x,y verschoben wird (funktioniert auch ganz gut 😉 ), Du kannst sozusagen jeden beliebigen Ausschnitt deines Bildes darstellen (siehe auch StretchBlt).

    So wie's jetzt ist sollte es eigentlich funktionieren (dd->...)???
    Sonst fällt mir noch auf:
    -bist Du sicher, dass m_width und m_height korrekt initialisiert sind?
    -SetPixel() usw. verwenden als obere linke Ecke immer (0,0) d.h Deine Schleifenkonstruktion lässt immer einen Rand (beabsichtigt?) zum anderen sind Vergleichsoperatoren mit = ungünstig (Feinheit!) besser wäre also einfach for(y=0;y<höhe;y++){...}



  • ok ... das macht schon mal nen sinn ... aber wieso wird nichts gezeichnet?

    von welcher basis klasse ist denn die klasse die du für soetwas verwendest abgelitten? und wieso sollte ich ein teil des codes in die OnPaint() bringen, oder wär das nur notwendig wenn ich permanent ein bild auf meinem Dialog darstellen lassen möchte und dies nicht über einen Button auslöse

    mfg, TFTS

    PS: gibt es vielleicht ganz andere Verfahren bzw. schon fertige klassen, die das zeichnen eines RGB Datenstromes übernehmen? kennst du dich zufällig mit "IStream" aus ... ich lese immer wieder davon, bin aber noch nicht so recht draus schlau geworden wie so ein istream aufgebaut ist.



  • Sorry habe vorherigen Beitrag nochmal editiert, hab zu schnell gelesen!
    Zu den anderen Problemen:
    Also funktionieren müsste es für alle von CWnd abgeleiteten Klassen.
    Die Sache mit OnPaint() hat den Vorteil, daß wenn Du den Dialog verschiebst immer noch dein Bild dargestellt wird und nicht irgendwelche Steuerelemente o.ä.. Ausserdem musst Du, wenn Das Bild aktualisiert wurde nicht jedesmal BitBlt(...) aufrufen sondern es genügt ein einfaches Invalidate(FALSE).
    Problematisch: Wenn das Bild im Speicher neu gezeichnet wird und gerade in diesem Augenblick jemand den Aufruf von OnPaint verursacht (Fenster ziehen etc.) dann kanns schon mal passieren, daß Bildsalat entsteht, ist aber sehr selten und unwahrscheinlich.



  • hmm mein problem ist aber, dass (anders als bei deiner OnDraw(CDC* pDC) Funktion) in die OnPaint() keine CDC* Variable hereingegeben wird ... ich müsste sie als extra irgendwo definieren ... aber wo dann? als member der klasse? oder nur in der OnPaint?

    Die Schleife stimmt soweit ... erarbeitet den gesamten stream ab ... x geht jetz von 0 bis <1600 und y von 0 bis <1200

    void CJpglibDlg::OnPaint() 
    {
    	if (IsIconic())
    	{
    		CPaintDC dc(this); // device context for painting
    
    		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
    
    		// Center icon in client rectangle
    		int cxIcon = GetSystemMetrics(SM_CXICON);
    		int cyIcon = GetSystemMetrics(SM_CYICON);
    		CRect rect;
    		GetClientRect(&rect);
    		int x = (rect.Width() - cxIcon + 1) / 2;
    		int y = (rect.Height() - cyIcon + 1) / 2;
    
    		// Draw the icon
    		dc.DrawIcon(x, y, m_hIcon);
    
    	}
    	else
    	{
    		CDialog::OnPaint();
    	}
    
    	pDC = GetDC();
    	pDC->BitBlt(0,0,m_width,m_height, m_pDC,0,0, SRCCOPY);
    }
    
    void CJpglibDlg::BytestreamToDialog()
    {
    	UpdateData(true);
    	int x,y;
    	int breite;
    	int hoehe;
    	int byte_nr;
    	int i;
    	byte_nr=0;
    						//by TFTS created: farbige Legenden Quadrate löschen
    
    	breite = int(m_width);
    	hoehe = int(m_height);
    
    		byte_nr=0;
    		for(y=0;y<hoehe;y++)
    		{
    			for(x=0;x<breite;x++)
    			{
    
    				m_pDC->SetPixelV( x,y, RGB(RGBbuffer[byte_nr],RGBbuffer[byte_nr+1],RGBbuffer[byte_nr+2]));
    				byte_nr=byte_nr+3;
    			}
    		}
    	this->Invalidate(FALSE);  
    
    }
    

    hab in dem bsp die variable pDC im header deklariert ... es malt aber immer noch nicht



  • Versuch mal

    CPaintDC dc(this);
    dc.BitBlt(...);
    

    direkt in das else-Statement der OnPaint Methode und nicht Vergessen: Invalidate(versuchs mal mit TRUE)!



  • hmm .. es tuts einfach nich .. hast du vielleicht ein kleines bsp programm bei dem es funktioniert .. da könnt ich vielleicht besser finden wo der fehler ist.

    mfg, TFTS





  • LINK : fatal error LNK1104: cannot open file "nafxcwd.lib"
    Error executing link.exe.

    die lib ist aber auch nich bei dem projekt dabei...


Anmelden zum Antworten