JPG laden mit GDI+



  • Hallo zusammen,

    der Theorie nach weiß ich eigentlich wie ich ein Bild in MFC laden kann, doch irgendwie wills nicht klappen. Ich beschreibe mal kurz wie ich denke wie es geht, da ich nicht weiß wo das Problem liegt. In dem Beispiel würde ich gerne die Bilderbeispiel-datei "Winter.jpg" laden, die auf jedem Windows Computer drauf ist.

    Zuerst erstelle ich ein neues MFC-Projekt mit dem Titel JPG, in dem ich dann zuerst in JPG.cpp GDI+ initialisiere

    #include <gdiplus.h>
    using namespace Gdiplus;
    

    in JPG.h in meiner von CWinApp abgeleiteten Klasse schreibe ich

    ULONG_PTR m_gdiplusToken;
    

    in JPG.cpp in InitInstance() ergänze ich

    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
    

    am Ende von JPG.cpp erstelle ich die Funktion

    void OnPaint (HDC hdc)
    (
          Graphics graphics(hdc);
    
          Image image(L"Winter.jpg");
          graphics.DrawImage(&image, 60, 10);
    )
    

    Wenn ich das erstellen will, bekomme ich immer Fehlermeldungen, was ist das Problem? Wer kann mir weiterhelfen? Ich probiere schon so lange herum, aber es will nie klappen. Habe auch schon Stunden im Internet nach hilfreichen Seiten mit Beispielen und Hilfen zu diesem Thema gesucht, aber nichts gefunden.

    Vielen Dank im Voraus an alle die sich die Mühe machen,

    Fabian



  • Hast Du die gdiplus.lib gelinkt? Ansonsten mal die Fehlermeldung Posten.

    Gruß



  • Zuerst kann ich noch sagen, dass ich das Programm einwandfrei kompilieren kann ohne Fehlermeldung. Erst wenn ich die .exe Datei erstellen will, treten beim Linken irgendwelche Probleme auf.

    gdiplus.lib hatte ich bisher noch nicht explizit verlinkt, habe es nun aber getan worauf sich allerdings nichts änderte. (Ich weiß allerdings nicht ob ich es richtig verlinkt habe: Ich bin unter Extras, Optionen, ... und dann bei den Bibliotheksdateien habe ich einfach gdiplus.lib dazugeschrieben und mit OK bestätigt. So richtig?)

    Als Fehlermeldungen kommen ungefähr 15, dass irgendwelche __gdiplus... Funktionen und ähnliches nicht gefunden werden konnte oder dass sie nicht deklariert sind.
    Ist es vielleicht auch möglich, dass die Datei "Winter.jpg" nicht geladen werden kann. Kann man denn einfach L"Winter.jpg" hinschreiben und darauf hoffen, dass die Umgebung sich das passende Bild aus dem Bilder-Beispielorder herauszieht ohne dass man davor einen Pfad angegeben hätte, wo sich "Winter.jpg" befindet?

    Vielen Dank im Voraus an alle,

    Fabian



  • Das nächste Mal bitte die Error-Meldung posten. Wir können nicht hellsehen! Postings wie "das funktionert nicht bei mir" müsste man am besten gleich löschen. 😡

    Also, verlinke mal die GDI+ so wie man auch alle Libs verlinkt. Das was du gemacht hast, ist nur ein Lib-Verzeichnis bekannt geben, aber nicht verlinken.

    Projekt->Eigenschaften->Linker->Befehlszeile... und dort einfach nur gdiplus.lib eintragen. Pfad oder so nicht nötig.



  • Und ohne kompletten Pfad wenn deine exe nicht im gleichen Verzeichnis liegt, wird das Bild sicher nicht gefunden werden.

    Gruß



  • Danke für die Hilfe, ich musste die gdiplus.lib nur richtig einbinden (bin noch recht neu und unerfahren).
    Das Programm lässt sich nun starten, also keine Fehlermeldungen mehr. Allerdings sehe ich nur einen weißen Bildschirm und das Menü. "Winter.jpg" wird also nicht richtig angezeigt.
    Ich habe auch schon versucht, die Bilddatei in alle möglichen Verzeichnissse meines Projekts zu legen (Debug, Ressources, ...) und trotzdem hat es nicht funktioniert. Auch die Parameter von DrawLine hinter L"Winter.jpg" habe ich schon geändert (0, 0 oder 10, 10 usw.). Wie kann ich den schnell einen Pfad erstellen, meinetwegen nur C://Winter.jpg oder ähnliches?

    P.S.: Fehlermeldungen posten hätte sich leider etwas schwieriger gestaltet, da ich das Projekt auf einem anderen Computer erstelle, als der, der ans Internet angeschlossen ist. Zudem erkennt jener PC meine gesamten 256MB-Sticks nicht, mit denen ich die Meldungen hier herüber ziehen könnte. Entschuldigung dafür,

    Gruß,

    Fabian



  • Weiß denn niemand woran es liegen könnte oder was ich vergessen habe?

    Danke,

    Fabian



  • Eigentlich muß

    Image(L"C:\\Cprog\\MediaCenter\\res\\Amorous1024x768.jpg");
    

    gehen. Ansonsten kannst Du auch

    Image::FromFile(L"C:\\Cprog\\MediaCenter\\res\\Amorous1024x768.jpg");
    

    versuchen. Beachte das der übergebene String in Unicode sein muß.

    Gruß



  • Danke, aber so hab ich es auch schon probiert. Funktioniert leider auch nicht. Allerdings habe ich gerade festgestellt, dass es anscheinend gar nichts mit dem Bildladen zu tun hat, denn in der Statusleiste wird dann schon Winter.jpg angezeigt, doch der Bildschirm ist einfach nur weiß.

    Auch bei anderen Gdi+_Funktionen wie z.B. DrawLine passiert nichts, ich kann es zwar erstellen, aber der Bildschirm bleibt weiß.

    void OnPaint(HDC hdc)
    
    (
    Graphics graphics(hdc);
    
    Pen MyPen(Color(255, 0, 255));
    graphics.DrawLine(&MyPen, 0, 0, 200, 100);
    )
    

    Hieran kann ja nichts falsch geladen werden. Ich habe ja nun auch die Bibliothek eingebunden und das Projekt kann erstellt werden. Nur es tut sich halt nichts in meinem Fenster.
    Geht das überhaupt so, dass man ans Ende seiner JPG.cpp Datei z.B. noch die OnPaint Methode dranhängt oder muss man das gesamte irgendwo in InitInstance() oder sonstwo einbauen?

    Vielen Dank im Voraus,

    Fabian



  • Hast Du einfach void OnPaint(...) geschrieben und hoffst das es jetzt läuft? Eigentlich wird dir Methode OnPaint überladen

    in *.cpp

    BEGIN_MESSAGE_MAP(Cxxx, CDialog)
    	//{{AFX_MSG_MAP(Cxxx)
    	ON_WM_PAINT()
    END_MESSAGE_MAP()
    
    void Cxxx::OnPaint()
    {
        CPaintDC dc( this );
        Graphics graphics(dc.GetSafeHdc());
    
        Pen MyPen(Color(255, 0, 255));
        graphics.DrawLine(&MyPen, 0, 0, 200, 100);
    }
    

    in *.h

    afx_msg void OnPaint();
    

    aber wie gesagt, das geht über den Klassenassistenten(VC6.0) oder über Eigenschaften der Klasse(VC7.0/2002 und höher). Ansonsten wird das nie was. Sollte ich jetzt Total auf dem Holzweg sein, dann setz doch mal nen Tracepunkt und lauf mal Schritt für Schritt durch.

    Gruß



  • @ 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!


Anmelden zum Antworten