JPG laden mit GDI+



  • @ CtecS: Danke, jetzt klappts mit dem Anzeigen der Linie. Ich musste OnPaint() usw. alles in der von CView abgeleiteten Klasse machen, nicht in der von CWinApp abgeleiteten, wie ich es zuerst gemacht hatte.

    Es gelingt mir nun zwar, die Linie zu zeichnen, dennoch das mit dem Bild laden funktioniert immer noch nicht. Warum wird das Jpg denn nicht angezeigt. Was ist an dem folgenden Code beim Laden des Bildes falsch, denn es wird ja immer nur die Linie angezeigt:

    void Cxxx::OnPaint()
    {
        CPaintDC dc( this );
        Graphics graphics(dc.GetSafeHdc());
    
        // Mein Zusatz zum Bild laden Anfang
    
        Image image(L"C://Winter.jpg");
        graphics.DrawImage(&image, 0, 0);
    
        // Mein Zusatz zum Bild laden Ende
    
        Pen MyPen(Color(255, 0, 255));
        graphics.DrawLine(&MyPen, 0, 0, 200, 100);
    }
    

    Muss ich die OnPaint Methode anders initialisieren um DrawImage statt DrawLine zu benutzen, aber das macht wahrscheinlich keinen Unterschied, oder?!?
    Wenn das kein Problem darstellt, dann liegt es mit großer Wahrscheinlichkeit daran, dass

    Image image(L"C://Winter.jpg");
    

    nicht geladen wird. Wie kann ich das denn noch anders als so ausdrücken? Kann ich Winter.jpg als Ressource laden, sodass es dann funktioniert, oder wo muss ich meine jpg-Datei platzieren, damit sie vc++ endlich benutzen kann.

    P.S.: Entschuldigung an alle die genervt sind, aber mich nervts auch und daher möchte ich es endlich mal hinkriegen, dieses widerspenstige JPG-Bild zu laden, arrgghh 😕

    Danke nochmal für alle Hilfe auch bis jetzt,

    Fabian



  • Ich habs jetzt nicht ausprobiert, aber ist es denn richtig c://winter.jpg zuschreiben? Also mit doppeltem slash? Du meinst wohl eher ein slash? Doppelt macht man es ur bei backslash, weil ein backslash als Sonderzeichen gilt. Das was du gemacht hast, ist ja schon eher eine URI...

    Und ich wette, das Bild wird nicht geladen (weil der Dateipfad ungültig ist) und deshalb wird nichts gezeichnet.

    Ob der Ladevorgang korrekt war, kannst du überprüfen:

    Image image(L"C:/Winter.jpg");
    if(image.GetLastStatus() == Status::Ok) {
       graphics.DrawImage(&image, 0, 0);   
    }
    else {
       std::cout << "Gdiplus Image Status: " << image.GetLastStatus();
    }
    

    Dann mußt du auch nicht mehr rumraten.

    Doku zu den Status Codes gibts hier:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdicpp/GDIPlus/GDIPlusReference/Enumerations/Status.asp



  • Meines erachtens werden Pfade immer so angegeben:

    C:\\Winter.jpg

    und

    file://C:/Winter.jpg

    benutzt der Browser. Vergleich das mal mit den Laufwerkspfaden im Explorer oder nach der alswahl in CFileDialog da bekommst Du auch keinen Pfad zurück der mit '/' getrennt ist.

    Gruß



  • Pfade mit Slash (/) funktionieren unter Windows ohne Problem. Kannste auch in der CMD.EXE mit Slashes durch die Verzeichnisse wechseln. Backslash (\) ist ein altes Relikt aus DOS-Zeiten, muß er nicht nicht benutzen.



  • @Artchi:
    Ich habe den von dir empfohlenen Code jetzt noch mit eingebaut:

    void CJpgs_laden_MFCView::OnPaint()
    {
    
    	CPaintDC dc( this );
    	Graphics graphics(dc.GetSafeHdc());
    
    	Image image(L"C:/Winter.jpg");
    
    	if (image.GetLastStatus() == Status::Ok)	{
    	graphics.DrawImage(&image, 0, 0, image.GetWidth(), image.GetHeight());
    
    	}
    	else	{
    	std::cout << "Gdiplus Image Status: " << image.GetLastStatus();
    	}
    
    }
    

    Allerdings bekomme ich dann immer folgende Fehlermeldung zurückgesandt:

    ------ Erstellen gestartet: Projekt: Jpgs_laden_MFC, Konfiguration: Debug Win32 ------
    
    Kompilieren...
    Jpgs_laden_MFC.cpp
    c:\vcppnet\Jpgs_laden_MFC\Jpgs_laden_MFC.cpp(153) : error C2825: 'Gdiplus::Status::Ok': Ein qualifizierter Name kann nicht gebildet werden
    c:\vcppnet\Jpgs_laden_MFC\Jpgs_laden_MFC.cpp(153) : error C2275: 'Gdiplus::Status': Ungültige Verwendung dieses Typs als Ausdruck
            d:\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include\GdiPlusTypes.h(88): Siehe Deklaration von 'Gdiplus::Status'
    c:\vcppnet\Jpgs_laden_MFC\Jpgs_laden_MFC.cpp(153) : error C2143: Syntaxfehler: Es fehlt ')' vor 'Ok'
    c:\vcppnet\Jpgs_laden_MFC\Jpgs_laden_MFC.cpp(153) : error C2059: Syntaxfehler: ')'
    c:\vcppnet\Jpgs_laden_MFC\Jpgs_laden_MFC.cpp(153) : error C2143: Syntaxfehler: Es fehlt ';' vor '{'
    c:\vcppnet\Jpgs_laden_MFC\Jpgs_laden_MFC.cpp(157) : error C2181: Ungültiges 'else' ohne zugehöriges 'if'
    
    Das Build-Protokoll wurde unter "file://c:\vcppnet\Jpgs_laden_MFC\Debug\BuildLog.htm" gespeichert.
    Jpgs_laden_MFC - 6 Fehler, 0 Warnung(en)
    
    ---------------------- Fertig ----------------------
    
        Erstellen: 0 erfolgreich, 1 fehlgeschlagen, 0 Übersprungen
    

    Ich habe zudem schon alle möglichen Dateipfade ausprobiert (Backslash, Slash, einzeln, doppelt, ganz ohne). Es will einfach nicht klappen. Weiß irgendwer noch weiter, wie ich das obige Problem und/oder das mit dem Dateipfad beheben kann?

    P.S.: In allen anderen Beispielen für DrawImage, wurde die Funktion

    OnPaint()
    

    nicht mit leeren Klammern, sondern mit

    (HDC hdc)
    

    initialisiert, worauf dann

    Graphics graphics(hdc)
    

    folgte. Könnte das vielleicht auch ein Grund sein oder ist das ausgeschlossen kein Problem?

    Vielen Dank im Voraus,

    Fabian Alt



  • if (image.GetLastStatus() == Ok)    {
    

    Probier mal ohne Status:: vor dem Ok. Bin da jetzt selbst etwas verwirrt...

    Zu dem Graphics-Kontext: wenn du eine Linie auf diesem Weg zeichnen kannst, dann geht auch ein Image.

    Normalerweise mußt du die OnPaint()-Methode deiner View-Klasse überschreiben. Ich weiß jetzt nicht wo du Paint() herhast oder woher du es aufrufst. Du kannst natürlich alles so belassen, nur wäre es vorteilhafter von OnPaint() diese Methode aufzurufen und den Device Context zu übergeben. Jetzt mal völlig unabhängig von dem Image-Problem, ich mache es jedenfalls generell so.

    MyDialog::OnPaint() {
    	CDialog::OnPaint();  // Super-OnPaint() einmal aufrufen
    	using namespace Gdiplus;
    	Gdiplus::Graphics g(*this);
    }
    

    Funktioniert natürlich auch für CViews, entsprechend anpassen.



  • Gut, wenn ich

    Status::
    

    weglasse, dann lässt sich das Programm immerhin starten. Danke dafür. Ein Bild wird allerdings immer noch nicht angezeigt.

    Weder das Bild, noch der durch

    std::cout
    

    eigentlich ausgegebene Text!?

    Auch wenn ich unabhängig von meiner "if / else" Verschachtelung mit cout einen Text ausgeben will, tut sich nichts auf dem Bildschirm. Ich muss doch, um mit cout den Text ausgeben zu können einfach nur

    #include <iostream>
    

    mit einbinden, das müsste doch reichen, oder was muss ich ändern damit der Text angezeigt werden würde?

    Meine OnPaint-Methode habe ich, da ich sie mit

    afx-Msg void OnPaint();
    

    in meiner von CView abgeleiteten Klasse überschrieben habe. Das müsste doch so stimmen, funktioniert ja auch. Daran kann es also wahrscheinlich nicht liegen.

    Danke an alle meine Unterstützer, nur nicht die Nerven verlieren :-),

    Fabian



  • Setz doch mal einen Breakpoint rein und schau ob die Methode überhaupt aufgerufen wird.

    Eines von den beiden Bedingungen des ifs muß ja aufgerufen werden.



  • Entschuldigung, aber wie setze ich einen Breakpoint?



  • Du hast noch viel zu lernen...

    Setze den Cursor in die if-Zeile mit dem GetLastStatus() und drücke die Taste F9. Dann lässt du das Programm laufen (mit F5) und wenn die pikante Stelle aufgerufen werden sollte, müsste der Debugger erscheinen. Dann einfach immer mit F10 weiter durch laufen lassen und schauen wie der Programmablauf ist.

    Estratu hat auch im C++ Magazin einen ausführlichen Artikel über Debuggen geschrieben:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-120832.html

    Undbedingt durchlesen!



  • Achja, die cout hat ein Problem: die Ausgabe erscheint so nirgens... du mußt die Konsole einschalten. Hier eine Datei die ich für meine Projekte erstellt habe:

    Console_cpp.zip

    Einmalig zum Programmstart redirectConsole() aufrufen, z.B. in CMyApp::InitInstance(), dann erscheint beim Debug eine Konsole wo cout-Ausgaben drauf erscheinen. Wenn du eine Release-Version erstellst (also für Enduser) wird die Konsole nicht geöffnet, sondern eine Logdatei cout.txt erstellt und dort werden die Ausgaben reingeschrieben.



  • Da das mit dem cout nicht funktionierte, habe ich mir eine CString variable erstellt, dann image.GetLastStatus() als integer abgespeichert und anschließend in meine CString variable konvertiert.
    Dadurch konnte ich mir das Ergebnis von GetLastStatus über TextOut() anzeigen lassen:

    void CJpgs_laden_MFCView::OnPaint()
    {
    
    	CPaintDC dc( this );
    	Graphics graphics(dc.GetSafeHdc());
    
    	Image image(L"Winter.jpg");
    
    	CString mein_Status;
    	int c = image.GetLastStatus();
    
    	mein_Status.Format("%i", c);
    
    	if (image.GetLastStatus() == 0)	{
    	graphics.DrawImage(&image, 0, 0);
    	dc.TextOut(40, 100, mein_Status);
    	dc.TextOut(40, 200, "Bild wird geladen");
    	}
    
    	else	{
    	dc.TextOut(40, 100, mein_Status);
    	dc.TextOut(40, 200, "Bild wird nicht geladen");
    	}
    
    }
    

    So, das verwirrende ist, dass die Rückmeldung in if(... == Ok) immer True ist und mein Programm somit gar nicht erst in die else-Schleife springt.
    Wenn ich mir jetzt aber in der if-Schleife den Rückgabewert von GetLastStatus() auf dem Bildschirm anzeigen lasse, erhalte ich folgendes Ergebnis:

    3

    Das bedeutet doch eigentlich, dass das Bild nicht geladen werden konnte. Trotzdem ist der Wert in der if(Bedingung) immer 0.

    Es macht übrigens auch gar keinen Unterschied, ob ich nun mit (L"Winter.jpg") dieses vorhanden Bild lade oder ein random-Bild, das gar nicht existiert.
    Und dennoch bleibt der Rückgabewert in meiner if-Schleife für GetLastStatus() immer Ok und der Wert, den ich danach auf dem Bildschirm ausgegeben bekomme immer 3.

    Wie kann ich das verstehen?

    Vielen Dank,

    Fabian



  • Sehr komisch. Status 3 heißt eigentlich OutOfMemory. Klingt doof, aber hast du genug Hauptspeicher frei? Wie groß ist das Bild, das du laden willst? (breite x höhe)



  • In der Msdn Library steht unten nach der Angabe der Bedeutungen aller Ziffern noch, dass 3 auch für alle anderen Arten von Problemen angezeigt wird, wenn sich das Bild nicht laden lässt. D.h. es muss gar nichts mit Speicherplatzmangel o.ä. zu tun haben.
    Ich versuch jetzt einfach weiter, irgendwann muss es ja klappen!

    Vielen Dank für alle Hilfe,

    Fabian



  • So, ich habe jetzt nochmal in einem neuen Projekt von vorne begonnen. Ich weiß zwar nicht was ich jetzt anders gemacht habe, dennoch klappt es nun, das Bild zu laden 🙂 !

    Vielen Dank nochmal an Artchi und CTecS für die klasse Unterstützung!

    Gruß,

    Fabian



  • Vergleiche mal in deinem alten Projekt und auf deiner Festplatte, ob die Datei, die du öffnen wolltest auch wirklich im angegebenen Pfad liegt. Ich hatte mich da auch selbst reingelegt, is ja aber auch sowas von logisch, dass 'Out of Memory' 'File not found' bedeutet.... 😉


Anmelden zum Antworten