3

I am creating images in various formats in WPF using BitmapEncoder. For example, to create a png image from a FrameworkElement, i am using the following code,

        BitmapEncoder imgEncoder = new PngBitmapEncoder();
        RenderTargetBitmap renderBitmap = new RenderTargetBitmap(32, 32, 96d, 96d, PixelFormats.Pbgra32);
        renderBitmap.Render(controlToConvert);
        imgEncoder.Frames.Add(BitmapFrame.Create(renderBitmap));

I like to create an .ico file in the same way. But I cannot find any IconBitmapEncoder in WPF. Is there any other way to do it?

Regards,

Jawahar

3 Answers 3

2

There is none.

I have tried to save images as *.ico in the past and other .NET classes did not really help (if i remember correctly they could only decode, not encode; but maybe i just did something wrong). *.ico can be a container for PNG images (there may be backwards compatibility issues though), so you can stick a full PNG in there with the right headers which could be found on wikipedia.

Example implementation:

public static class PngToIcoConverter
{
    public static byte[] Convert(byte[] data)
    {
        Image source;
        using (var inStream = new MemoryStream(data))
        {
            source = Image.FromStream(inStream);
        }
        byte[] output;
        using (var outStream = new MemoryStream())
        {
            // Header
            {
                // Reserved
                outStream.WriteByte(0);
                outStream.WriteByte(0);
                // File format (ico)
                outStream.WriteByte(1);
                outStream.WriteByte(0);
                // Image count (1)
                outStream.WriteByte(1);
                outStream.WriteByte(0);
            }

            // Image entry
            {
                // Width
                outStream.WriteByte((byte)source.Width);
                // Height
                outStream.WriteByte((byte)source.Height);
                // Number of colors (0 = No palette)
                outStream.WriteByte(0);
                // Reserved
                outStream.WriteByte(0);
                // Color plane (1)
                outStream.WriteByte(1);
                outStream.WriteByte(0);
                // Bits per pixel
                var bppAsLittle = IntToLittle2(Image.GetPixelFormatSize(source.PixelFormat));
                outStream.Write(bppAsLittle, 0, 2);
                // Size of data in bytes
                var byteCountAsLittle = IntToLittle4(data.Length);
                outStream.Write(byteCountAsLittle, 0, 4);
                // Offset of data from beginning of file (data begins right here = 22)
                outStream.WriteByte(22);
                outStream.WriteByte(0);
                outStream.WriteByte(0);
                outStream.WriteByte(0);
                // Data
                outStream.Write(data, 0, data.Length);
            }
            output = outStream.ToArray();
        }
        return output;
    }

    private static byte[] IntToLittle2(int input)
    {
        byte[] b = new byte[2];
        b[0] = (byte)input;
        b[1] = (byte)(((uint)input >> 8) & 0xFF);
        return b;
    }
    private static byte[] IntToLittle4(int input)
    {
        byte[] b = new byte[4];
        b[0] = (byte)input;
        b[1] = (byte)(((uint)input >> 8) & 0xFF);
        b[2] = (byte)(((uint)input >> 16) & 0xFF);
        b[3] = (byte)(((uint)input >> 24) & 0xFF);
        return b;
    }
}
Sign up to request clarification or add additional context in comments.

Comments

2

MSDN says that there is no "IcoBitmapEncoder". I could suggest you to get Bitmap from BitmapFrame and then convert it to icon, like this:

    BitmapEncoder imgEncoder = new PngBitmapEncoder();
    RenderTargetBitmap renderBitmap = new RenderTargetBitmap(32, 32, 96d, 96d, PixelFormats.Pbgra32);
    renderBitmap.Render(comboBox1);
    var frame = BitmapFrame.Create(renderBitmap);

    Bitmap bitmap = GetBitmap(frame);
    bitmap.SetResolution(72, 72);
    System.Drawing.Icon icon = System.Drawing.Icon.FromHandle(bitmap.GetHicon());
    FileStream fs = new FileStream(filename, FileMode.OpenOrCreate);
    icon.Save(fs);
    fs.Close();

Method GetBitmap you can get from here:

    static Bitmap GetBitmap(BitmapSource source)
    {
        Bitmap bmp = new Bitmap(source.PixelWidth, source.PixelHeight, 
            System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
        BitmapData data = bmp.LockBits(
            new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size), ImageLockMode.WriteOnly, 
            System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
        source.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
        bmp.UnlockBits(data);
        return bmp;
    }

Comments

0

I use this extension method to create a System.Drawing.Icon:

public static System.Drawing.Icon ToGDIIcon(this System.Windows.Media.ImageSource icon)
        {
            var image = (System.Windows.Media.Imaging.BitmapSource)icon;
            var encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
            encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(image));
            using (var ms = new MemoryStream())
            {
                encoder.Save(ms);
                using (var tempBitmap = new System.Drawing.Bitmap(ms))
                {
                    return System.Drawing.Icon.FromHandle(tempBitmap.GetHicon());
                }
            }
        }

...

var icon = imageSource.ToGDIIcon();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.