Bild kopieren in GDI+



  • Hallo, 😉

    ich habe folgendes Beispiel fast 1:1 aus der MSDN kopiert:

    INT main()
    {
        GdiplusStartupInput gdiplusStartupInput;
        ULONG_PTR           gdiplusToken;
        // Initialize GDI+.
        GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
        std::cout << "Starte GDI+" << std::endl;
    
        CLSID   encoderClsid;
        Status  stat;
        Image*   image = new Image(L"C:\\Quelle.bmp");
    
        // Get the CLSID of the PNG encoder.
        if(GetEncoderClsid(L"image/png", &encoderClsid))
            printf("Codec image/png gefunden\n");
        else
            printf("Codec image/png nicht gefunden\n");
    
        stat = image->Save(L"C:\\Ziel.png", &encoderClsid, NULL);
    
        if(stat == 0)
            printf("Ziel.png gespeichert\n");
        else
            printf("Fehler: %d\n", stat);
    
        delete image;
        GdiplusShutdown(gdiplusToken);
        return 0;
    }
    

    Selbst bei diesem simplen Programm erhalte ich jedoch einen Fehler:

    Starte GDI+
    Codec image/png gefunden
    Fehler: 10
    

    Die Ziel.png wird zwar angelegt, ist aber 0 Bytes groß.
    Die Quelle.bmp ist in jedem Fall am angegebenen Pfad vorhanden, lässt sich per MSPaint anzeigen und wird zur Laufzeit auch nicht von anderen Programmen verwendet. Versuche, die Datei zu verschieben und den Pfad entsprechend anzupassen, scheiterten, der Fehler blieb.

    MSDN sagt:

    Status 10 - FileNotFound
    
        Indicates that the specified image file or metafile cannot be found.
    

    Ich weiß nicht mehr weiter und Google schweigt zu dem Thema. Gibt es vielleicht jemanden, der in derselben Situation steckte?

    Ich verwende MinGW/GCC als Compiler und Windows XP SP2 als OS.



  • Verstehe auch nicht, dass der Fehler beim Aufruf von ::Save passiert...



  • Hallo,

    ändere diesen Teil:

    // Get the CLSID of the PNG encoder. 
        if(GetEncoderClsid(L"image/png", &encoderClsid)) 
            printf("Codec image/png gefunden\n"); 
        else 
            printf("Codec image/png nicht gefunden\n");
    

    in:

    if(GetEncoderClsid(L"image/png", &encoderClsid) >= 0) 
            printf("Codec image/png gefunden\n"); 
        else 
            printf("Codec image/png nicht gefunden\n");
    

    um zu sehen, ob der Encoder wirklich vorhanden ist.

    MfG,

    Probe-Nutzer



  • Ich mach das ähnlich, aber mit Bitmap anstelle Image, so klappt das.

    Gruss Frank



  • Wird nichts ändern, da die Funktion BOOL zurückgibt:

    BOOL GetEncoderClsid(wchar_t* wchMimeType, CLSID* clsidEncoder)
    {
        UINT uiNum   = 0;
        UINT uiSize  = 0;
        BOOL bOk     = FALSE;
    
        ImageCodecInfo* pImageCodecInfo = NULL;
    
        GetImageEncodersSize(&uiNum, &uiSize);
    
        if( uiSize > 0 )
        {
            pImageCodecInfo = (Gdiplus::ImageCodecInfo *)new char[uiSize];
    
            if( pImageCodecInfo )
            {
                Gdiplus::GetImageEncoders(uiNum, uiSize, pImageCodecInfo);
    
                for( UINT i = 0; i < uiNum; i++ )
                {
                    if( wcscmp(pImageCodecInfo[i].MimeType, wchMimeType) == 0 )
                    {
                        clsidEncoder = &pImageCodecInfo[i].Clsid;
                        bOk = TRUE;
                        break;
                    }
                }
            }
    
            delete pImageCodecInfo;
        }
    
       return bOk;
    }
    

    Ein paar Testläufe mit teilweise erfundenen Werten:

    Codec image/bmp gefunden
    
    Codec image/asdf nicht gefunden
    
    Codec image/png gefunden
    
    Codec image/test nicht gefunden
    
    Codec image/jpeg gefunden
    

    Der Teil scheint also zu funktionieren?

    Unabhängig davon, ob der Codec vorhanden ist, erhalte ich den Fehler 10.

    @DerAltenburger: Danke, werde ich mal ausprobieren.



  • Habe über Google gefunden, dass man Unicode-Pfaden ein \?\ voranstellen muss/kann.

    Bitmap* image = Bitmap::FromFile(L"\\\\?\\Quelle.bmp");
    ...
    stat = image->Save(L"\\\\?\\Ziel.png", &encoderClsid, NULL);
    

    So erhalte ich einen Fehler 2:

    InvalidParameter

    Indicates that one of the arguments passed to the method was not valid.

    Etwas weiter gelesen:

    Also, you cannot use the "\?\" prefix with a relative path.

    Also statische Pfade getestet:

    Bitmap* image = Bitmap::FromFile(L"\\\\?\\C:\\Quelle.bmp");
    ...
    stat = image->Save(L"\\\\?\\C:\\Ziel.png", &encoderClsid, NULL);
    

    Dann erhalte ich wieder Fehler 10, File not found.



  • @Altenburger: Ersetzen von Image durch Bitmap ändert leider nichts.

    Folgendes hinzugefügt:

    FILE *datei;
        datei= fopen("Quelle.bmp","r");
        if (datei == NULL)
            std::cout << "Quelle.bmp existiert nicht" << std::endl;
        else
            std::cout << "Quelle.bmp existiert!" << std::endl;
    

    ergibt:

    Quelle.bmp existiert!

    Der Bitmap::Save-Fehler 10 bleibt jedoch, langsam gehen mir die Ideen aus.



  • Sorry für das Multiposting, aber mir fehlen die Rechte zum Beiträge bearbeiten.

    UINT height = image->GetHeight();
        UINT width = image->GetWidth();
    
        std::cout << "Hoehe: " << height << ", Breite: " << width << std::endl;
    

    Dieser Code gibt die korrekten Bildmaße wieder, das Bild wurde also geöffnet. Nur der Save-Aufruf schlägt fehl mit "File not found" (Logik?), selbst wenn "image/bmp" als Encoder verwendet wird.

    FileNotFound

    Indicates that the specified image file or metafile cannot be found.



  • GdiGast schrieb:

    Habe über Google gefunden, dass man Unicode-Pfaden ein \?\ voranstellen muss/kann.

    Bitmap* image = Bitmap::FromFile(L"\\\\?\\Quelle.bmp");
    ...
    stat = image->Save(L"\\\\?\\Ziel.png", &encoderClsid, NULL);
    

    So erhalte ich einen Fehler 2:

    InvalidParameter

    Indicates that one of the arguments passed to the method was not valid.

    Etwas weiter gelesen:

    Also, you cannot use the "\?\" prefix with a relative path.

    Also statische Pfade getestet:

    Bitmap* image = Bitmap::FromFile(L"\\\\?\\C:\\Quelle.bmp");
    ...
    stat = image->Save(L"\\\\?\\C:\\Ziel.png", &encoderClsid, NULL);
    

    Dann erhalte ich wieder Fehler 10, File not found.

    Nein, völlig auf der falschen Spur (du hast doch geschrieben, die Datei wurde angelegt, der Pfad kann nicht das Problem sein), würde ich sagen...zum Thema:

    Wird nichts ändern, da die Funktion BOOL zurückgibt:
    

    Stimmt, jetzt da man auch sieht, wie die in der MSDN-Doku angegebene Funktion geändert wurde (ich bin von der anderen Funktion ausgegangen, dann muss man ändern) 😉

    und damit kommen wir zum "fast 1:1 -Kopieren":

    Die Funktion wurde so geändert, dass sie nicht mehr zuverlässig funktionieren kann:

    hier:

    delete pImageCodecInfo;
    

    wird das pImageCodecInfo-Objekt abgeräumt, und es verweist noch ein Zeiger (clsidEncoder) darauf, der dann auch noch weiter verwendet werden soll.

    Aber entscheidender ist, dass in der Funktion GetEncoderClsid zwar mit dem Wert von &encoderClsid gearbeitet wird, jedoch bringt die Zuweisung:

    clsidEncoder = &pImageCodecInfo[i].Clsid;

    überhaupt nichts, da einem lokalen Zeiger mit dem Namen clsidEncoder zwar ein neuer Wert zugewiesen wird (der übergebene Wert &encoderClsid wird überschrieben), aber der übergebene Zeiger &encoderClsid behält (natürlich) seinen Wert, so dass das encoderClsid-Objekt nicht verändert wird (und damit wird dort nie ein gültiger Encoder vorhanden sein).

    Die in der MSDN-Doku vorgestellte Funktion hat dieses Problem nicht, da mit der Zuweisung:

    *pClsid = pImageCodecInfo[j].Clsid;
    

    der Wert, auf den der Zeiger verweist, geändert wird, und das ist ok. Vielleicht weisst du jetzt, was du ändern musst, wenn du unbedingt mit der geänderten Funktion weiter arbeiten willst...

    MfG,

    Probe-Nutzer



  • Vielleicht fehlen dir einfach nur die Rechte eine datei in C:\ zu erstellen?
    Mach das doch mal auf dem desktop.



  • @Probe-Nutzer: Bist mein Held des Tages. Riesen-Dank.

    Kann geschlossen werden.


Anmelden zum Antworten