2

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

WPF Lover
  • 299
  • 6
  • 16

4 Answers4

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;
    }
}
H.B.
  • 166,899
  • 29
  • 327
  • 400
1

I know the question has already been answered, but recently I wrote an article on Code Project where I share the source code of a IconBitmapEncoder. It encodes BitmapImage in icon files, without the need for third-party dll's or the use of the Win Forms. 100% Windows Presentation Foundation.

A High-Quality IconBitmapEncoder for WPF

I expect it to be useful for you.

1

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;
    }
Community
  • 1
  • 1
Seekeer
  • 1,344
  • 2
  • 18
  • 31
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();
fsbflavio
  • 664
  • 10
  • 22