ATL::CImage Problem, schon wieder



  • Seit längerem kämpfe ich an einer Funktion zum Bilder skalieren, basierend auf der ATL::CImage-Klasse. Ich denke das ist schon die beste Lösung um viele Bildformate zu unterstützen? Kenne GDI+ von C# her, wo ich keinerlei Probleme habe.
    Nun hier will es einfach nicht so recht wie ich. Das Bild ist in einer globalen Instanz "img" gespeichert und wird in OnPaint neu gezeichnet und der Funktion "Resize" soll es skaliert werden. Öffnen und anzeigen geht problemlos, doch beim Skalieren ist nacher einfach kein Bild sichtbar und ein Debug Assertion-Fehler erscheint bei der Zeile

    img.StretchBlt(dc,0,0,img.GetWidth()/dGroessenFaktor,img.GetHeight()/dGroessenFaktor,SRCCOPY);
    

    in OnPaint, also bei der Ausgabe des Bildes (hBitmap==m_Bitmap). Im Debugger zeigt die Schnellüberwachung

    img = {m_hBitmap=0x0505064f m_pBits=0x01d4c184 m_nWidth=261 ...}
    

    und die richtige neue Grösse an.
    Der Code zum skalieren ist der folgende (inkl. ein paar auskommentierter Versuche:

    inline void Resize(int width, int height) {
    
    	Gdiplus::InterpolationMode mode=Gdiplus::InterpolationModeHighQualityBicubic;
    /*	CBitmap b;
    	CDC c;
    	CDC* imgDC=(CDC*)img.GetDC();
    	c.CreateCompatibleDC(NULL);
    
    	b.CreateBitmap(width, height, 1, 32, NULL);
    
    	HGDIOBJ restore=c.SelectObject(b);
    	//img.Draw(c.m_hDC,0,0,width, height,0,0,img.GetWidth(), img.GetHeight());
        img.StretchBlt(c.m_hDC,0,0,width, height,HALFTONE);
    	c.SelectObject(restore);
    	img.Attach((HBITMAP)b.Detach());
    	c.DeleteDC();
    //  c.BitBlt(0,0,width,height,imgDC,0,0,SRCCOPY);
    	*/
    CImage img1;
    	img1.Create(width,height,32); 
    
        CDC dc; 
        dc.Attach(img1.GetDC()); 
    
        dc.SetStretchBltMode(HALFTONE); 
    
        img.StretchBlt(dc,0,0,width,height,SRCCOPY ); 
    
        dc.Detach(); 
    
        img1.ReleaseDC(); 
    
        img = img1;
    


  • Aber Du wirst uns doch mitteilen können was der Assertion in der OnPaint sagt. Desweiteren würde ich vielleicht in Resize noch:

    ...
    img.Destroy();
    img = img1;
    

    ich weiss net ob Du sonnst ein memory leek erzeugst, aber ich denke schaden kann es nicht.



  • Hallo,
    1.)
    dc keinen Bitmap enthält.
    in auskomentierten Zeilen gibt das notwendiges Teil.

    CBitmap b;

    HGDIOBJ restore=dc.SelectObject(b);

    img.StretchBlt(c.m_hDC,0,0,width, height,HALFTONE);

    am Ende dann Bitmap widerherstellen.
    dc.SelectObject(restore);

    2.)
    img1.GetDC(); ///??? Funktioniert es so? so intuitive wurde ich sagen, dass man hier den dc aus dem Fenster holt, wo es ausgegeben werden soll, und nict aus img1. Wenn es auch schneller funktionieren soll, einen DC mit CreateCompatibleDC von Fenster DC erzeugen, und dann mit BitBlt zusammenfügen.

    hier gibt es noch ein Beispiel : http://msdn.microsoft.com/de-de/library/kwxzck32.aspx



  • @Sigie:

    Bitte informier dich doch erst mal über die Klasse CImage bevor du hier Tips Postest.

    zu 1.
    sein DC hat eine Bitmap, da er den DC direkt von CImage bekommt.

    zu 2.
    img1.GetDC(); // hattest du dir mal die member von CImage angeschaut hättest du dir die antwort erspaaren können

    wobei der Fehler ja net wie geschrieben in Resize() entsteht sondern in OnPaint und solange der Assert nicht bekannt ist, is das ein Rätzelraten



  • Hatte nun wieder unzählige erfolglose Versuche; irgendwie werden immer die falschen Parameter verlangt bei Funktionen (CDC/HDC) oder die CImage-Klasse gibt den falschen. Die Klasse sollte ja schon ausgelegt sein auf Zusammenarbeit mit nicht-GDI+-Funktionen.....

    Zum Assertion-Fehler, er lautet (habe ich etwas versteckt geschrieben):

    hBitmap==m_Bitmap
    

    Das Problem liegt schon an der Resize-Funktion, denn solange ein Bild nicht durch diese Funktion geschickt wird kann es unendlich oft "gepaintet" werden, gezoomt usw.

    EDIT: Hab's nun:

    inline void Resize(int width, int height) {
    
    	Gdiplus::InterpolationMode mode=Gdiplus::InterpolationModeHighQualityBicubic;
    
    CImage img1;
    	img1.Create(width,height,32); 
    
        CDC dc; 
        dc.Attach(img1.GetDC()); 
    
        dc.SetStretchBltMode(HALFTONE); 
    
        img.StretchBlt(dc,0,0,width,height,SRCCOPY ); 
    
        dc.Detach(); 
    
        img1.ReleaseDC(); 
    
        //img = img1;
    	img.Destroy(); img.Create(width, height,32);
    	img1.BitBlt(img.GetDC(),0,0,SRCCOPY);
    	img.ReleaseDC();
    

    es ist

    img=img1
    

    nicht zulässig.
    Ist das nun ein guter Weg? Möchte soweit wie möglich die beste Bildqualität, und Speicherlecks vermeiden; muss ich noch einen DC freigeben?

    Vielen Dank!!



  • Na wenn du schon mit einen Globalen CImage-Objekt rumhantierst, hast du es mal mit einem zeiger versucht, den du global hast, wo du immer das Objekt dahinter wechseln kannst. Denn ich bin mir nicht sicher bo CImage den Kopierkonstruktor unterstützt.

    Wobei ich eher für eine neue Klasse bin, die das CImage Objekt Kapselt und die entsprechenden Methoden bereit stellt. Da is das dann auch mit dem tauschen des Zeigers kein problem, weil das die Klasse in sich macht. Das sollte dann auch dein Problem erschlagen.



  • Ach so dass der Zeiger nach dem Bearbeiten auf das neue Image-Objekt zeigt z.B. img1 und dadurch dieser Kopiervorgang wegfällt... Wäre eine Idee!
    Das mit der Klasse mit den Methoden habe ich in C# so gelöst, da gibt es eine Klasse mit den Funktionen welche im Prinzip auch in einem anderen Programm verwendet werden könnte. In C++ bin ich aber nicht so gut und müsste dadurch etwas viel in dieses OO-Design stecken und daran rumstudieren, darum habe ich mich vorerst für diese Lösung entschieden.
    Aber hier ist OK mit den Freigaben etc. oder habe ich etwas übersehen?

    Eine andere Frage, gibt es diese CImage oder GDI+ auch für Windows Mobile? Im Compact Framework sind sie ja auch vorhanden, auch für MFC?



  • na wenn du das kapselst, ist das ok, an sonnsten globale variablen sind immer schlecht deswegen benutz ich die eigentlich nie, wenn ich einen Zeiger oder klasse im gesammten Programm benötige, wie Setup-einstellung/Klasse dann kommt die in die Application, da hab ich von überall Zugriff.
    Ob CImage auch in Windows mobile geht hab ich keine ahnung, hab ich noch nichts für gemacht, aber versuch macht klug, probiers einfach aus



  • Danke!
    Sehr schade, versuchte gerade mit Windows Mobile:

    Cannot open include file: 'Gdiplusimaging.h': No such file o.....
    


  • oh windows mobile, zum glück hatte ich noch net die bekanntschaft gemacht



  • Wieso meinst? 🙂


Anmelden zum Antworten