KeyWorksRW / wxUiEditor

RAD tool used to create and maintain wxWidgets UI elements.
Apache License 2.0
61 stars 6 forks source link

Add tool for converting an SVG file into a multiple-resolution Windows icon #1405

Open KeyWorksRW opened 5 months ago

KeyWorksRW commented 5 months ago

Description:

A common method of setting and Icon for a Windows executable is to set the APPICON in the resource file. Unfortunately, you can't supply a SVG file for this icon. It would be handy if wxUiEditor had a tool that would take an SVG file and convert it to a Windows icon using 16x16, 32x32, 48x48 and 256x256. Besides being useful for wxUiEditor itself, it could potentially be useful for anyone else wanting to use an SVG file for the application's icons.

KeyWorksRW commented 3 months ago

From @Kumazuma:

It is simple way that make ico file from wxBitmapBundle. the ICO file is supported from Windows Vista and later. This code was referenced from Wikipedia.

#include <wx/bmpbndl.h>
#include <wx/wfstream.h>

struct IconDir {
    uint16_t reserved;
    uint16_t image_type;
    uint16_t num_of_images;
};

struct IconDirEntry {
    uint8_t width;
    uint8_t height;
    uint8_t color_palette;
    uint8_t reserved;
    uint16_t color_planes;
    uint16_t bits_per_pixel;
    uint32_t bytes_width_of_image;
    uint32_t offset_of_image;
};

bool SaveBundleToIco(wxOutputStream& stream, wxBitmapBundle& bundle) {
    if(!stream.IsSeekable())
        return false;

    const wxFileOffset offset_start = stream.TellO();
    IconDir header{};
    IconDirEntry entries[4] {};

    header.image_type = 1;
    header.num_of_images = 4;

    entries[0].width = 16;
    entries[0].height = 16;

    entries[1].width = 32;
    entries[1].height = 32;

    entries[2].width = 48;
    entries[2].height = 48;

    entries[3].width = 0;
    entries[3].height = 0;

    stream.Write(&header, sizeof(header));
    stream.Write(&entries, sizeof(entries));
    for(auto& entry: entries) {
        int size = entry.width != 0 ? entry.width : 256;
        wxBitmap bitmap = bundle.GetBitmap(wxSize(size, size));
        wxImage img = bitmap.ConvertToImage();
        entry.offset_of_image = stream.TellO();
        img.SaveFile(stream, wxBITMAP_TYPE_PNG);
        entry.bytes_width_of_image = stream.TellO() - entry.offset_of_image;
        entry.bits_per_pixel = 32;
        entry.color_planes = 0;
    }

    stream.SeekO(offset_start + sizeof(header));
    stream.Write(&entries, sizeof(entries));
    return true;
}
KeyWorksRW commented 3 months ago

Thanks! I copied your email directly into the issue. I hadn't looked into wxIcon, so I mistakenly thought I could just create a wxIcon and call it's save method -- but it doesn't have one, so your info will be very helpful.

Kumazuma commented 3 months ago

I appreciate about it is helped you. however it should be changed in the code.

        entry.bits_per_pixel = (entry.bytes_width_of_image / (size * size)) * 8;

to

        entry.bits_per_pixel = 32;
KeyWorksRW commented 3 months ago

Okay, I updated the code above.