2012-03-25

ToolStripButton.Image, ToolStripMenuItem.Image - skalowanie wysokiej jakości

Jeśli rozmiar ToolStripButton.Image jest większy niż ToolStrip.ImageScalingSize obrazek zostanie przeskalowany, będzie to jednak skalowanie niskiej jakości - najbliższy sąsiad. To samo dotyczy ToolStripMenuItem.Image.

Rozwiązania tego problemu są następujące:
  • napisanie własnego menadżera rysowania (tego nie jestem pewny)
  • przygotowanie obrazków we właściwych rozmiarach
  • ich programowe  przeskalowanie na starcie aplikacji
Pierwszego nie jestem pewny. Drugie jest za mało uniwersalne. Co jeśli zmienimy rozmiar obrazków na toolbarach w trakcie projektowania - musimy wszystkie na nowo przygotować. Co jeśli zmieniamy je programowo - małe, średnie, duże - musimy przygotować trzy zestawy. I ostatni powód - taki sam problem jest z menu kontekstowym, tylko tam obrazki są 16x16.

Ja osobiście zdecydowałem się na trzecie rozwiązanie. Przygotowujemy sobie obrazki jako przeźroczyste PNG o rozmiarach 256x256 i skalujemy je do odpowiednich rozmiarów w razie potrzeby.

Wadą tego rozwiązania jest to, że nasz przeskalowany obrazek - 32x32 mniej, ale 16x16 już bardzo - to prawie pixel art - gdzie zręczny grafik dłubiąc ręcznie w pikselach jest w stanie uzyskać obrazek lepszej jakości niż przez przeskalowanie.

Kod jego implementacji:

private void ResizeContextMenuStripImages()
{
    foreach (var c in FindAll<Control>())
    {
        if (c.ContextMenuStrip == null)
            continue;

        foreach (var item in 
            c.ContextMenuStrip.Items.OfType<ToolStripMenuItem>())
        {
            if (item.Image == null)
                continue;

            var image = ResizeImage(
                item.Image, c.ContextMenuStrip.ImageScalingSize);
            item.Image.Dispose();
            item.Image = image;
        }
    }
}

private void ResizeToolStripImages()
{
    foreach (var toolstrip in FindAll<ToolStrip>())
    {
        foreach (var button in toolstrip.Items.OfType<ToolStripButton>())
        {
            if (button.Image == null)
                continue;

            var image = ResizeImage(button.Image, toolstrip.ImageScalingSize);
            button.Image.Dispose();
            button.Image = image;
        }
    }
}

private Bitmap ResizeImage(Image a_image, Size a_size)
{
    Bitmap bmp = new Bitmap(a_size.Width, a_size.Height, a_image.PixelFormat);

    using (Graphics g = Graphics.FromImage(bmp))
    {
        g.CompositingQuality = CompositingQuality.HighQuality;
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        g.SmoothingMode = SmoothingMode.HighQuality;
        g.DrawImage(a_image, 0, 0, bmp.Width, bmp.Height);
    }

    return bmp;
}

private IEnumerable<T> FindAll<T>(Control a_control = null)
{
    List<T> list = new List<T>();

    if (a_control == null)
        a_control = this;

    foreach (var c in a_control.Controls.OfType<T>())
        list.Add(c);

    foreach (var c in a_control.Controls.Cast<Control>())
        list.AddRange(FindAll<T>(c));

    return list;
}

Brak komentarzy:

Prześlij komentarz