WinForms .NET 2.0: Как нарисовать иконку нужного размера? - PullRequest
1 голос
/ 11 ноября 2008

У меня есть файл ico, который содержит 48x48 и 256x256 Vista PNG версии (а также 32x32 и 16x16 версии). я хочу нарисовать иконку, используя соответствующую версию внутреннего размера.

я пробовал:

Icon ico = Properties.Resources.TestIcon;
e.Graphics.DrawIcon(ico, new Rectangle(0, 0, 48, 48));
e.Graphics.DrawIcon(ico, new Rectangle(48, 0, 256, 256));

Но они рисуют версию 32x32, увеличенную до 48x48 и 256x256 соответственно.

я пробовал:

Icon ico = Properties.Resources.TestIcon;
e.Graphics.DrawIconUnstretched(ico, new Rectangle(0, 0, 48, 48));
e.Graphics.DrawIconUnstretched(ico, new Rectangle(48 0, 256, 256));

Но те рисуют 32x32 версию без натяжения.

я пробовал:

Icon ico = Properties.Resources.TestIcon;
e.Graphics.DrawImage(ico.ToBitmap(), new Rectangle(0, 0, 48, 48));
e.Graphics.DrawImage(ico.ToBitmap(), new Rectangle(48, 0, 256, 256));

Но те рисуют растянутую версию значка 32x32.

Как сделать так, чтобы значок нарисовал себя, используя соответствующий размер?

Кроме того, я хочу рисовать, используя версию 16x16. я пробовал:

Icon ico = Properties.Resources.TestIcon;
e.Graphics.DrawIcon(ico, new Rectangle(0, 0, 16, 16));
e.Graphics.DrawIconUnstretched(ico, new Rectangle(24, 0, 16, 16));
e.Graphics.DrawImage(ico.ToBitmap(), new Rectangle(48, 0, 16, 16));

Но все они используют уменьшенную версию 32x32, за исключением вызова Unstretched, который обрезает его до 16x16.

Как сделать так, чтобы значок нарисовал себя, используя соответствующий размер?


Следуя предложению schnaader о создании копии значка нужного размера, он не работает для размера 256x256. то есть следующее не работает (используется уменьшенная версия значка 48x48):

e.Graphics.DrawIcon(
        new Icon(ico, new Size(256, 256)), 
        new Rectangle(0, 0, 256, 256));

Пока работают следующие два:

e.Graphics.DrawIcon(
        new Icon(ico, new Size(16, 16)), 
        new Rectangle(0, 0, 16, 16));

e.Graphics.DrawIcon(
        new Icon(ico, new Size(48, 48)), 
        new Rectangle(0, 0, 48, 48));

1 Ответ

1 голос
/ 22 декабря 2009

Сегодня я сделал очень хорошую функцию для извлечения растровых изображений 256x256 из значков Vista .

Я использую его для отображения большого значка ( 256x256 ) в качестве растрового изображения в поле «О программе». Например, этот код получает значок Vista в виде изображения PNG и отображает его в PictureBox 256x256:

picboxAppLogo.Image = ExtractVistaIcon(Icon.ExtractAssociatedIcon(myIcon));

Эта функция принимает объект Icon в качестве параметра. Таким образом, вы можете использовать его с любыми иконками - из ресурсов , из файлов, из потоков и так далее. (Читайте ниже о извлечении значка EXE).

Он работает на любой ОС , потому что не использует любой Win32 API, это 100% управляемый код : -)

// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx
// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx

Bitmap ExtractVistaIcon(Icon icoIcon)
{
    Bitmap bmpPngExtracted = null;
    try
    {
        byte[] srcBuf = null;
        using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
            { icoIcon.Save(stream); srcBuf = stream.ToArray(); }
        const int SizeICONDIR = 6;
        const int SizeICONDIRENTRY = 16;
        int iCount = BitConverter.ToInt16(srcBuf, 4);
        for (int iIndex=0; iIndex<iCount; iIndex++)
        {
            int iWidth  = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex];
            int iHeight = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex + 1];
            int iBitCount   = BitConverter.ToInt16(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 6);
            if (iWidth == 0 && iHeight == 0 && iBitCount == 32)
            {
                int iImageSize   = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 8);
                int iImageOffset = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 12);
                System.IO.MemoryStream destStream = new System.IO.MemoryStream();
                System.IO.BinaryWriter writer = new System.IO.BinaryWriter(destStream);
                writer.Write(srcBuf, iImageOffset, iImageSize);
                destStream.Seek(0, System.IO.SeekOrigin.Begin);
                bmpPngExtracted = new Bitmap(destStream); // This is PNG! :)
                break;
            }
        }
    }
    catch { return null; }
    return bmpPngExtracted;
}

ВАЖНО! Если вы хотите загрузить этот значок непосредственно из EXE-файла, тогда вы НЕ МОЖЕТЕ использовать Icon.ExtractAssociatedIcon (Application.ExecutablePath) как параметр, потому что .NET-функция ExtractAssociatedIcon () настолько глупа, что извлекает ТОЛЬКО значок 32x32!

Вместо этого вам лучше использовать весь класс IconExtractor , созданный Цудой Кагейю (http://www.codeproject.com/KB/cs/IconExtractor.aspx).. Вы можете немного упростить этот класс, чтобы сделать его меньше. Используйте IconExtractor таким образом:

// Getting FILL icon set from EXE, and extracting 256x256 version for logo...
using (TKageyu.Utils.IconExtractor IconEx = new TKageyu.Utils.IconExtractor(Application.ExecutablePath))
{
    Icon icoAppIcon = IconEx.GetIcon(0); // Because standard System.Drawing.Icon.ExtractAssociatedIcon() returns ONLY 32x32.
    picboxAppLogo.Image = ExtractVistaIcon(icoAppIcon);
}

Примечание: я все еще использую свою функцию ExtractVistaIcon (), потому что мне не нравится, как IconExtractor выполняет это задание - во-первых, он извлекает все форматы значков с помощью IconExtractor.SplitIcon (icoAppIcon) , а затем вы должны знать точный индекс значка 256x256, чтобы получить желаемый значок перспективы. Итак, использование моего ExtractVistaIcon () здесь намного быстрее и проще:)

...