Icon aus .png Datei laden (und dann mit WM_SETICON setzen)



  • Ich möchte das Icon meines Fenster setzen, allerdings nicht mit einer ICO-Datei sondern aus einer PNG-Datei. Das Laden von PNGs mit libpng kann ich auch, nur ich weiß nicht, wie ich die rohen Bilddaten dann an WM_SETICON übergeben kann.

    Ich haber mir das erstmal so vorgestellt:

    Mittels CreateBitmap ein HBITMAP aus den PNG-Bild-Daten erstellen. Dieses Handle als hbmColor einer neuen ICONINFO-Struktur benutzen. Aus dieser Struktur ein Icon mittels CreateIconIndirect erstellen und dass dann mit WM_SETICON an mein Fenster senden.

    Könnte das so klappen oder gibt es noch eine einfachere Möglichkeit?



  • Ist doch einfach genug, oder?



  • Geht so, bin nicht sehr erfahren mit der WinAPI. Würde das denn so überhaupt klappen? Und kann ich aus den RGBA Daten von PNGs einfach so ein Bitmap erstellen?
    Ist es in Ordnung wenn ich hbmMask der ICONINFO-Sturktur auf NULL setzte?


  • Mod

    Man kann ohne Probleme die PNG mit GDI+ laden und weiter verarbeiten.



  • Martin Richter schrieb:

    Man kann ohne Probleme die PNG mit GDI+ laden und weiter verarbeiten.

    Was meinst du mit weiter verarbeiten? Also das Laden ist ja auch kein Problem mit libpng, nur wie ich das ganze dann in eine für WM_SETICON richtige Form kriege. Bei der Image-Klasse von GDI+ seh ich jetzt auf die schnelle keine Möglichkeit dafür. Hab mich auch noch nie mit GDI+ befasst. Kannst du mir ein wenig weiter helfen?


  • Mod

    GIDF.

    Die GDI+ Doku findest Du in der MSDN.
    Hier ein nettes Beispiel:
    http://www.codeproject.com/KB/GDI-plus/cgdiplusbitmap.aspx

    BTW: Warum sollte ich eine weitere LIB wie LIBPNG einbinden wenn Windows das alles schon mitbringt mit GDI+...



  • Martin Richter schrieb:

    Die GDI+ Doku findest Du in der MSDN.

    Die hab ich auch schon durchsucht und so wie es aussieht ist es nicht möglich ein mit der GDI+ geladenes Bild als Fenstericon zu finden. Oder irre ich mich da?

    Hier ein nettes Beispiel:
    http://www.codeproject.com/KB/GDI-plus/cgdiplusbitmap.aspx

    Das Beispiel hat leider nichts mit meinem Problem zu tun, denn es behandelt das Laden von Resourcen, was ich nicht möchte, und es behandelt an sich das Laden von PNG-Dateien und darstellen von PNG-Dateien. Das kann ich alles schon und brauch ich nicht, ich suche eine Möglichkeit ein PNG-Bild (bzw. rohe Bilddaten) als Fenstericon zu verwenden mittels WinAPI. Meinetwegen auch mit Hilfe von GDI+, denke aber nicht, dass die mir dabei helfen wird.



  • Vielleicht die Bitmap an http://msdn.microsoft.com/en-us/library/ms648062 übergeben?


  • Mod

    Wenn man die PNG Datei laden kann mit GDI+ kannst Du sie in jeder Art auf einem Memory DC wiedergeben oder die Bitmaps extrahieren.

    Warum sollte dies nicht helfen?



  • Martin Richter schrieb:

    Wenn man die PNG Datei laden kann mit GDI+ kannst Du sie in jeder Art auf einem Memory DC wiedergeben oder die Bitmaps extrahieren.

    Okay das ist nicht schlecht. Ich habe aber festgestellt, dass MinGW GDI+ nicht mitbringt und mich deswegen erstmal nicht weiter damit befasst. Habe es jetzt auch mit libpng hingekriegt:

    FILE* fp = fopen("icon.png", "rb");
    if(!fp)
    	throw std::runtime_error(std::string("File not found: icon.png"));
    png_byte buf[PNG_BYTES_TO_CHECK];
    assert(PNG_BYTES_TO_CHECK >= sizeof(unsigned short));
    
    // Read in some of the signature bytes
    if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK)
    	throw std::runtime_error(std::string("Error reading signature bytes."));
    
    assert(png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0);
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, png_error_ptr_NULL, png_error_ptr_NULL);
    if(!png_ptr)
    {
    	throw std::runtime_error("libpng error while reading");
    }
    
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if(!info_ptr)
    {
    	throw std::runtime_error("libpng error while reading");
    }
    
    if(setjmp(png_jmpbuf(png_ptr)))
    {
    	// Free all of the memory associated with the png_ptr and info_ptr
    	png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
    	throw std::runtime_error("Error reading file.");
    }
    png_init_io(png_ptr, fp);
    png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
    int colorType = png_get_color_type(png_ptr, info_ptr);
    if(colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
    {
    	png_set_gray_to_rgb(png_ptr);
    }
    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_BGR, png_voidp_NULL);
    
    png_ptr->num_rows = png_ptr->height; // Make sure this is set correctly
    
    const int x = png_ptr->width;
    const int y = png_ptr->height;
    
    std::vector<char> imageData(x * y * png_ptr->channels);
    for(int i = 0; i < y; ++i)
    {
    	memcpy(&imageData[i*x*png_ptr->channels], info_ptr->row_pointers[i], x * png_ptr->channels);
    }
    
    ICONINFO icon;
    icon.fIcon = true;
    std::vector<char> blackMask(x * y);
    icon.hbmMask = CreateBitmap(x, y, 1, 8, &blackMask[0]);
    icon.hbmColor = CreateBitmap(x, y, 1, png_ptr->channels * 8, &imageData[0]);
    
    png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
    
    HICON hIcon = CreateIconIndirect(&icon);
    SendMessage(hwnd, WM_SETICON, WPARAM(ICON_SMALL), LPARAM(hIcon));
    


  • Sieht ziemlich frickelig aus. Benutz doch Visual Studio.


Anmelden zum Antworten