Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A simple class that converts a image to a icon in c# without losing image color data, unlike System.Drawing.Icon; ico with png data requires Windows Vista or above
class PngIconConverter
{
/* input image with width = height is suggested to get the best result */
/* png support in icon was introduced in Windows Vista */
public static bool Convert(System.IO.Stream input_stream, System.IO.Stream output_stream, int size, bool keep_aspect_ratio = false)
{
System.Drawing.Bitmap input_bit = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromStream(input_stream);
if (input_bit != null)
{
int width, height;
if (keep_aspect_ratio)
{
width = size;
height = input_bit.Height / input_bit.Width * size;
}
else
{
width = height = size;
}
System.Drawing.Bitmap new_bit = new System.Drawing.Bitmap(input_bit, new System.Drawing.Size(width, height));
if (new_bit != null)
{
// save the resized png into a memory stream for future use
System.IO.MemoryStream mem_data = new System.IO.MemoryStream();
new_bit.Save(mem_data, System.Drawing.Imaging.ImageFormat.Png);
System.IO.BinaryWriter icon_writer = new System.IO.BinaryWriter(output_stream);
if (output_stream != null && icon_writer != null)
{
// 0-1 reserved, 0
icon_writer.Write((byte)0);
icon_writer.Write((byte)0);
// 2-3 image type, 1 = icon, 2 = cursor
icon_writer.Write((short)1);
// 4-5 number of images
icon_writer.Write((short)1);
// image entry 1
// 0 image width
icon_writer.Write((byte)width);
// 1 image height
icon_writer.Write((byte)height);
// 2 number of colors
icon_writer.Write((byte)0);
// 3 reserved
icon_writer.Write((byte)0);
// 4-5 color planes
icon_writer.Write((short)0);
// 6-7 bits per pixel
icon_writer.Write((short)32);
// 8-11 size of image data
icon_writer.Write((int)mem_data.Length);
// 12-15 offset of image data
icon_writer.Write((int)(6 + 16));
// write image data
// png data must contain the whole png data file
icon_writer.Write(mem_data.ToArray());
icon_writer.Flush();
return true;
}
}
return false;
}
return false;
}
public static bool Convert(string input_image, string output_icon, int size, bool keep_aspect_ratio = false)
{
System.IO.FileStream input_stream = new System.IO.FileStream(input_image, System.IO.FileMode.Open);
System.IO.FileStream output_stream = new System.IO.FileStream(output_icon, System.IO.FileMode.OpenOrCreate);
bool result = Convert(input_stream, output_stream, size, keep_aspect_ratio);
input_stream.Close();
output_stream.Close();
return result;
}
}
@kipusoep

This comment has been minimized.

Copy link

@kipusoep kipusoep commented Nov 6, 2014

Very nice, thanks!
I've added some documentation and renamed variables to comply with Microsoft standards:

/// <summary>
/// Provides helper methods for imaging
/// </summary>
public static class ImagingHelper
{
    /// <summary>
    /// Converts a PNG image to a icon (ico)
    /// </summary>
    /// <param name="input">The input stream</param>
    /// <param name="output">The output stream</param>
    /// <param name="size">The size (16x16 px by default)</param>
    /// <param name="preserveAspectRatio">Preserve the aspect ratio</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(Stream input, Stream output, int size = 16, bool preserveAspectRatio = false)
    {
        Bitmap inputBitmap = (Bitmap)Bitmap.FromStream(input);
        if (inputBitmap != null)
        {
            int width, height;
            if (preserveAspectRatio)
            {
                width = size;
                height = inputBitmap.Height / inputBitmap.Width * size;
            }
            else
            {
                width = height = size;
            }
            Bitmap newBitmap = new Bitmap(inputBitmap, new Size(width, height));
            if (newBitmap != null)
            {
                // save the resized png into a memory stream for future use
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    newBitmap.Save(memoryStream, ImageFormat.Png);

                    BinaryWriter iconWriter = new BinaryWriter(output);
                    if (output != null && iconWriter != null)
                    {
                        // 0-1 reserved, 0
                        iconWriter.Write((byte)0);
                        iconWriter.Write((byte)0);

                        // 2-3 image type, 1 = icon, 2 = cursor
                        iconWriter.Write((short)1);

                        // 4-5 number of images
                        iconWriter.Write((short)1);

                        // image entry 1
                        // 0 image width
                        iconWriter.Write((byte)width);
                        // 1 image height
                        iconWriter.Write((byte)height);

                        // 2 number of colors
                        iconWriter.Write((byte)0);

                        // 3 reserved
                        iconWriter.Write((byte)0);

                        // 4-5 color planes
                        iconWriter.Write((short)0);

                        // 6-7 bits per pixel
                        iconWriter.Write((short)32);

                        // 8-11 size of image data
                        iconWriter.Write((int)memoryStream.Length);

                        // 12-15 offset of image data
                        iconWriter.Write((int)(6 + 16));

                        // write image data
                        // png data must contain the whole png data file
                        iconWriter.Write(memoryStream.ToArray());

                        iconWriter.Flush();

                        return true;
                    }
                }
            }
            return false;
        }
        return false;
    }

    /// <summary>
    /// Converts a PNG image to a icon (ico)
    /// </summary>
    /// <param name="inputPath">The input path</param>
    /// <param name="outputPath">The output path</param>
    /// <param name="size">The size (16x16 px by default)</param>
    /// <param name="preserveAspectRatio">Preserve the aspect ratio</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(string inputPath, string outputPath, int size = 16, bool preserveAspectRatio = false)
    {
        using (FileStream inputStream = new FileStream(inputPath, FileMode.Open))
        using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
        {
            return ConvertToIcon(inputStream, outputStream, size, preserveAspectRatio);
        }
    }
}
@AbdlrhmanSheahta

This comment has been minimized.

Copy link

@AbdlrhmanSheahta AbdlrhmanSheahta commented Oct 29, 2015

thank you very much dude , it's working well on converting , png to ico

@maurosampietro

This comment has been minimized.

Copy link

@maurosampietro maurosampietro commented Mar 29, 2016

Fail fast, less indentation.

 public static class ImagingHelper
 {
        /// <summary>
        /// Converts a PNG image to a icon (ico)
        /// </summary>
        /// <param name="input">The input stream</param>
        /// <param name="output">The output stream</param>
        /// <param name="size">The size (16x16 px by default)</param>
        /// <param name="preserveAspectRatio">Preserve the aspect ratio</param>
        /// <returns>Wether or not the icon was succesfully generated</returns>
        public static bool ConvertToIcon( Stream input, Stream output, int size = 16, bool preserveAspectRatio = false )
        {
            var inputBitmap = (Bitmap)Bitmap.FromStream( input );
            if( inputBitmap == null )
                return false;

            int width = size, height = size;
            if( preserveAspectRatio )
            {
                width = size;
                height = inputBitmap.Height / inputBitmap.Width * size;
            }

            var newBitmap = new Bitmap( inputBitmap, new Size( width, height ) );
            if( newBitmap == null )
                return false;

            // save the resized png into a memory stream for future use
            using( MemoryStream memoryStream = new MemoryStream() )
            {
                newBitmap.Save( memoryStream, ImageFormat.Png );

                var iconWriter = new BinaryWriter( output );
                if( output == null || iconWriter == null )
                    return false;

                // 0-1 reserved, 0
                iconWriter.Write( (byte)0 );
                iconWriter.Write( (byte)0 );

                // 2-3 image type, 1 = icon, 2 = cursor
                iconWriter.Write( (short)1 );

                // 4-5 number of images
                iconWriter.Write( (short)1 );

                // image entry 1
                // 0 image width
                iconWriter.Write( (byte)width );
                // 1 image height
                iconWriter.Write( (byte)height );

                // 2 number of colors
                iconWriter.Write( (byte)0 );

                // 3 reserved
                iconWriter.Write( (byte)0 );

                // 4-5 color planes
                iconWriter.Write( (short)0 );

                // 6-7 bits per pixel
                iconWriter.Write( (short)32 );

                // 8-11 size of image data
                iconWriter.Write( (int)memoryStream.Length );

                // 12-15 offset of image data
                iconWriter.Write( (int)(6 + 16) );

                // write image data
                // png data must contain the whole png data file
                iconWriter.Write( memoryStream.ToArray() );

                iconWriter.Flush();
            }

            return true;
        }
 }
@DeepakkSHAW

This comment has been minimized.

Copy link

@DeepakkSHAW DeepakkSHAW commented Jul 22, 2016

Thanks.

@ratheeshalon

This comment has been minimized.

Copy link

@ratheeshalon ratheeshalon commented Nov 29, 2016

Thanks

@ChuckSavage

This comment has been minimized.

Copy link

@ChuckSavage ChuckSavage commented Jun 22, 2017

Preserve Aspect Ratio fixed.

Thanks so much for this code, it works amazing!

using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

    /// <summary>
    /// Provides helper methods for imaging
    /// </summary>
    public static class IconHelper
    {
        /// <summary>
        /// Converts a PNG image to a icon (ico)
        /// </summary>
        /// <param name="input">The input stream</param>
        /// <param name="output">The output stream</param>
        /// <param name="size">Needs to be a factor of 2 (16x16 px by default)</param>
        /// <param name="preserveAspectRatio">Preserve the aspect ratio</param>
        /// <returns>Wether or not the icon was succesfully generated</returns>
        public static bool ConvertToIcon(Stream input, Stream output, int size = 16, bool preserveAspectRatio = false)
        {
            var inputBitmap = (Bitmap)Bitmap.FromStream(input);
            if (inputBitmap == null)
                return false;

            float width = size, height = size;
            if (preserveAspectRatio)
            {
                if (inputBitmap.Width > inputBitmap.Height)
                    height = ((float)inputBitmap.Height / inputBitmap.Width) * size;
                else
                    width = ((float)inputBitmap.Width / inputBitmap.Height) * size;
            }

            var newBitmap = new Bitmap(inputBitmap, new Size((int)width, (int)height));
            if (newBitmap == null)
                return false;

            // save the resized png into a memory stream for future use
            using (MemoryStream memoryStream = new MemoryStream())
            {
                newBitmap.Save(memoryStream, ImageFormat.Png);

                var iconWriter = new BinaryWriter(output);
                if (output == null || iconWriter == null)
                    return false;

                // 0-1 reserved, 0
                iconWriter.Write((byte)0);
                iconWriter.Write((byte)0);

                // 2-3 image type, 1 = icon, 2 = cursor
                iconWriter.Write((short)1);

                // 4-5 number of images
                iconWriter.Write((short)1);

                // image entry 1
                // 0 image width
                iconWriter.Write((byte)width);
                // 1 image height
                iconWriter.Write((byte)height);

                // 2 number of colors
                iconWriter.Write((byte)0);

                // 3 reserved
                iconWriter.Write((byte)0);

                // 4-5 color planes
                iconWriter.Write((short)0);

                // 6-7 bits per pixel
                iconWriter.Write((short)32);

                // 8-11 size of image data
                iconWriter.Write((int)memoryStream.Length);

                // 12-15 offset of image data
                iconWriter.Write((int)(6 + 16));

                // write image data
                // png data must contain the whole png data file
                iconWriter.Write(memoryStream.ToArray());

                iconWriter.Flush();
            }

            return true;
        }

        /// <summary>
        /// Converts a PNG image to a icon (ico)
        /// </summary>
        /// <param name="inputPath">The input path</param>
        /// <param name="outputPath">The output path</param>
        /// <param name="size">Needs to be a factor of 2 (16x16 px by default)</param>
        /// <param name="preserveAspectRatio">Preserve the aspect ratio</param>
        /// <returns>Wether or not the icon was succesfully generated</returns>
        public static bool ConvertToIcon(string inputPath, string outputPath, int size = 16, bool preserveAspectRatio = false)
        {
            using (FileStream inputStream = new FileStream(inputPath, FileMode.Open))
            using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
            {
                return ConvertToIcon(inputStream, outputStream, size, preserveAspectRatio);
            }
        }
    }

@0x10Ayoub

This comment has been minimized.

Copy link

@0x10Ayoub 0x10Ayoub commented Jul 16, 2017

thank you so much

@bananbl

This comment has been minimized.

Copy link

@bananbl bananbl commented Aug 1, 2017

Thank you!
Wrapper added: converting Image object to Ico byte array.

using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

/// <summary>
/// Provides helper methods for imaging
/// </summary>
public static class IconHelper
{
    /// <summary>
    /// Converts a PNG image to an icon (ico)
    /// </summary>
    /// <param name="input">The input stream</param>
    /// <param name="output">The output stream</param>
    /// <param name="size">Needs to be a factor of 2 (16x16 px by default)</param>
    /// <param name="preserveAspectRatio">Preserve the aspect ratio</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(Stream input, Stream output, int size = 16, bool preserveAspectRatio = false)
    {
        var inputBitmap = (Bitmap)Bitmap.FromStream(input);
        if (inputBitmap == null)
            return false;

        float width = size, height = size;
        if (preserveAspectRatio)
        {
            if (inputBitmap.Width > inputBitmap.Height)
                height = ((float)inputBitmap.Height / inputBitmap.Width) * size;
            else
                width = ((float)inputBitmap.Width / inputBitmap.Height) * size;
        }

        var newBitmap = new Bitmap(inputBitmap, new Size((int)width, (int)height));
        if (newBitmap == null)
            return false;

        // save the resized png into a memory stream for future use
        using (MemoryStream memoryStream = new MemoryStream())
        {
            newBitmap.Save(memoryStream, ImageFormat.Png);

            var iconWriter = new BinaryWriter(output);
            if (output == null || iconWriter == null)
                return false;

            // 0-1 reserved, 0
            iconWriter.Write((byte)0);
            iconWriter.Write((byte)0);

            // 2-3 image type, 1 = icon, 2 = cursor
            iconWriter.Write((short)1);

            // 4-5 number of images
            iconWriter.Write((short)1);

            // image entry 1
            // 0 image width
            iconWriter.Write((byte)width);
            // 1 image height
            iconWriter.Write((byte)height);

            // 2 number of colors
            iconWriter.Write((byte)0);

            // 3 reserved
            iconWriter.Write((byte)0);

            // 4-5 color planes
            iconWriter.Write((short)0);

            // 6-7 bits per pixel
            iconWriter.Write((short)32);

            // 8-11 size of image data
            iconWriter.Write((int)memoryStream.Length);

            // 12-15 offset of image data
            iconWriter.Write((int)(6 + 16));

            // write image data
            // png data must contain the whole png data file
            iconWriter.Write(memoryStream.ToArray());

            iconWriter.Flush();
        }

        return true;
    }

    /// <summary>
    /// Converts a PNG image to an icon (ico)
    /// </summary>
    /// <param name="inputPath">The input path</param>
    /// <param name="outputPath">The output path</param>
    /// <param name="size">Needs to be a factor of 2 (16x16 px by default)</param>
    /// <param name="preserveAspectRatio">Preserve the aspect ratio</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(string inputPath, string outputPath, int size = 16, bool preserveAspectRatio = false)
    {
        using (FileStream inputStream = new FileStream(inputPath, FileMode.Open))
        using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
        {
            return ConvertToIcon(inputStream, outputStream, size, preserveAspectRatio);
        }
    }

    /// <summary>
    /// Converts a PNG image to an icon (ico)
    /// </summary>
    /// <param name="inputPath">Image object</param>
    /// <param name="preserveAspectRatio">Preserve the aspect ratio</param>
    /// <returns>ico byte array / null for error</returns>
    public static byte[] ConvertToIcon(Image image, bool preserveAspectRatio = false)
    {
        MemoryStream inputStream = new MemoryStream();
        image.Save(inputStream, ImageFormat.Png);
        inputStream.Seek(0, SeekOrigin.Begin);
        MemoryStream outputStream = new MemoryStream();
        int size = image.Size.Width;
        if (!ConvertToIcon(inputStream, outputStream, size, preserveAspectRatio))
        {
            return null;
        }
        return outputStream.ToArray();
    }
}
@mdiller

This comment has been minimized.

Copy link

@mdiller mdiller commented Mar 10, 2018

This was super useful to me. I modified it to create multiple images in one ico of varying sizes.

/// <summary>
/// Adapted from this gist: https://gist.github.com/darkfall/1656050
/// Provides helper methods for imaging
/// </summary>
public static class ImagingHelper
{
    /// <summary>
    /// Converts a PNG image to a icon (ico) with all the sizes windows likes
    /// </summary>
    /// <param name="inputBitmap">The input bitmap</param>
    /// <param name="output">The output stream</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(Bitmap inputBitmap, Stream output)
    {
        if (inputBitmap == null)
            return false;

        int[] sizes = new int[] { 256, 48, 32, 16 };

        // Generate bitmaps for all the sizes and toss them in streams
        List<MemoryStream> imageStreams = new List<MemoryStream>();
        foreach (int size in sizes)
        {
            Bitmap newBitmap = ResizeImage(inputBitmap, size, size);
            if (newBitmap == null)
                return false;
            MemoryStream memoryStream = new MemoryStream();
            newBitmap.Save(memoryStream, ImageFormat.Png);
            imageStreams.Add(memoryStream);
        }

        BinaryWriter iconWriter = new BinaryWriter(output);
        if (output == null || iconWriter == null)
            return false;

        int offset = 0;

        // 0-1 reserved, 0
        iconWriter.Write((byte)0);
        iconWriter.Write((byte)0);

        // 2-3 image type, 1 = icon, 2 = cursor
        iconWriter.Write((short)1);

        // 4-5 number of images
        iconWriter.Write((short)sizes.Length);

        offset += 6 + (16 * sizes.Length);

        for (int i = 0; i < sizes.Length; i++)
        {
            // image entry 1
            // 0 image width
            iconWriter.Write((byte)sizes[i]);
            // 1 image height
            iconWriter.Write((byte)sizes[i]);

            // 2 number of colors
            iconWriter.Write((byte)0);

            // 3 reserved
            iconWriter.Write((byte)0);

            // 4-5 color planes
            iconWriter.Write((short)0);

            // 6-7 bits per pixel
            iconWriter.Write((short)32);

            // 8-11 size of image data
            iconWriter.Write((int)imageStreams[i].Length);

            // 12-15 offset of image data
            iconWriter.Write((int)offset);

            offset += (int)imageStreams[i].Length;
        }

        for (int i = 0; i < sizes.Length; i++)
        {
            // write image data
            // png data must contain the whole png data file
            iconWriter.Write(imageStreams[i].ToArray());
            imageStreams[i].Close();
        }

        iconWriter.Flush();

        return true;
    }

    /// <summary>
    /// Converts a PNG image to a icon (ico)
    /// </summary>
    /// <param name="input">The input stream</param>
    /// <param name="output">The output stream</param
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(Stream input, Stream output)
    {
        Bitmap inputBitmap = (Bitmap)Bitmap.FromStream(input);
        return ConvertToIcon(inputBitmap, output);
    }

    /// <summary>
    /// Converts a PNG image to a icon (ico)
    /// </summary>
    /// <param name="inputPath">The input path</param>
    /// <param name="outputPath">The output path</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(string inputPath, string outputPath)
    {
        using (FileStream inputStream = new FileStream(inputPath, FileMode.Open))
        using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
        {
            return ConvertToIcon(inputStream, outputStream);
        }
    }



    /// <summary>
    /// Converts an image to a icon (ico)
    /// </summary>
    /// <param name="inputImage">The input image</param>
    /// <param name="outputPath">The output path</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(Image inputImage, string outputPath)
    {
        using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
        {
            return ConvertToIcon(new Bitmap(inputImage), outputStream);
        }
    }


    /// <summary>
    /// Resize the image to the specified width and height.
    /// Found on stackoverflow: https://stackoverflow.com/questions/1922040/resize-an-image-c-sharp
    /// </summary>
    /// <param name="image">The image to resize.</param>
    /// <param name="width">The width to resize to.</param>
    /// <param name="height">The height to resize to.</param>
    /// <returns>The resized image.</returns>
    public static Bitmap ResizeImage(Image image, int width, int height)
    {
        var destRect = new Rectangle(0, 0, width, height);
        var destImage = new Bitmap(width, height);

        destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

        using (var graphics = Graphics.FromImage(destImage))
        {
            graphics.CompositingMode = CompositingMode.SourceCopy;
            graphics.CompositingQuality = CompositingQuality.HighQuality;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.SmoothingMode = SmoothingMode.HighQuality;
            graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

            using (var wrapMode = new ImageAttributes())
            {
                wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
            }
        }

        return destImage;
    }
}
@prepare

This comment has been minimized.

Copy link

@prepare prepare commented May 20, 2019

Hello @darkfall, @mdiller
Could you provide a license for your source code?

@darkfall

This comment has been minimized.

Copy link
Owner Author

@darkfall darkfall commented May 20, 2019

Hello @darkfall, @mdiller
Could you provide a license for your source code?

CC-BY-SA. Feel free to use it

@prepare

This comment has been minimized.

Copy link

@prepare prepare commented May 20, 2019

Thank you 👍

@mdiller

This comment has been minimized.

Copy link

@mdiller mdiller commented May 20, 2019

Hello @darkfall, @mdiller
Could you provide a license for your source code?

As darkfall said, CC-BY-SA. Feel free to use my modifications!

@zzxxhhzxh

This comment has been minimized.

Copy link

@zzxxhhzxh zzxxhhzxh commented Aug 4, 2019

This was super useful to me. I modified it to create multiple images in one ico of varying sizes.

/// <summary>
/// Adapted from this gist: https://gist.github.com/darkfall/1656050
/// Provides helper methods for imaging
/// </summary>
public static class ImagingHelper
{
    /// <summary>
    /// Converts a PNG image to a icon (ico) with all the sizes windows likes
    /// </summary>
    /// <param name="inputBitmap">The input bitmap</param>
    /// <param name="output">The output stream</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(Bitmap inputBitmap, Stream output)
    {
        if (inputBitmap == null)
            return false;

        int[] sizes = new int[] { 256, 48, 32, 16 };

        // Generate bitmaps for all the sizes and toss them in streams
        List<MemoryStream> imageStreams = new List<MemoryStream>();
        foreach (int size in sizes)
        {
            Bitmap newBitmap = ResizeImage(inputBitmap, size, size);
            if (newBitmap == null)
                return false;
            MemoryStream memoryStream = new MemoryStream();
            newBitmap.Save(memoryStream, ImageFormat.Png);
            imageStreams.Add(memoryStream);
        }

        BinaryWriter iconWriter = new BinaryWriter(output);
        if (output == null || iconWriter == null)
            return false;

        int offset = 0;

        // 0-1 reserved, 0
        iconWriter.Write((byte)0);
        iconWriter.Write((byte)0);

        // 2-3 image type, 1 = icon, 2 = cursor
        iconWriter.Write((short)1);

        // 4-5 number of images
        iconWriter.Write((short)sizes.Length);

        offset += 6 + (16 * sizes.Length);

        for (int i = 0; i < sizes.Length; i++)
        {
            // image entry 1
            // 0 image width
            iconWriter.Write((byte)sizes[i]);
            // 1 image height
            iconWriter.Write((byte)sizes[i]);

            // 2 number of colors
            iconWriter.Write((byte)0);

            // 3 reserved
            iconWriter.Write((byte)0);

            // 4-5 color planes
            iconWriter.Write((short)0);

            // 6-7 bits per pixel
            iconWriter.Write((short)32);

            // 8-11 size of image data
            iconWriter.Write((int)imageStreams[i].Length);

            // 12-15 offset of image data
            iconWriter.Write((int)offset);

            offset += (int)imageStreams[i].Length;
        }

        for (int i = 0; i < sizes.Length; i++)
        {
            // write image data
            // png data must contain the whole png data file
            iconWriter.Write(imageStreams[i].ToArray());
            imageStreams[i].Close();
        }

        iconWriter.Flush();

        return true;
    }

    /// <summary>
    /// Converts a PNG image to a icon (ico)
    /// </summary>
    /// <param name="input">The input stream</param>
    /// <param name="output">The output stream</param
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(Stream input, Stream output)
    {
        Bitmap inputBitmap = (Bitmap)Bitmap.FromStream(input);
        return ConvertToIcon(inputBitmap, output);
    }

    /// <summary>
    /// Converts a PNG image to a icon (ico)
    /// </summary>
    /// <param name="inputPath">The input path</param>
    /// <param name="outputPath">The output path</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(string inputPath, string outputPath)
    {
        using (FileStream inputStream = new FileStream(inputPath, FileMode.Open))
        using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
        {
            return ConvertToIcon(inputStream, outputStream);
        }
    }



    /// <summary>
    /// Converts an image to a icon (ico)
    /// </summary>
    /// <param name="inputImage">The input image</param>
    /// <param name="outputPath">The output path</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(Image inputImage, string outputPath)
    {
        using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
        {
            return ConvertToIcon(new Bitmap(inputImage), outputStream);
        }
    }


    /// <summary>
    /// Resize the image to the specified width and height.
    /// Found on stackoverflow: https://stackoverflow.com/questions/1922040/resize-an-image-c-sharp
    /// </summary>
    /// <param name="image">The image to resize.</param>
    /// <param name="width">The width to resize to.</param>
    /// <param name="height">The height to resize to.</param>
    /// <returns>The resized image.</returns>
    public static Bitmap ResizeImage(Image image, int width, int height)
    {
        var destRect = new Rectangle(0, 0, width, height);
        var destImage = new Bitmap(width, height);

        destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

        using (var graphics = Graphics.FromImage(destImage))
        {
            graphics.CompositingMode = CompositingMode.SourceCopy;
            graphics.CompositingQuality = CompositingQuality.HighQuality;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.SmoothingMode = SmoothingMode.HighQuality;
            graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

            using (var wrapMode = new ImageAttributes())
            {
                wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
            }
        }

        return destImage;
    }
}

I use your code to create a icon including some sizes like 3232, 4848, 256*256. But if I use var bmp = (Bitmap)Image.FromFile(iconFilePath).Clone(), it failed, shows"GDI+ error". So how to open the icon file correctly?

@jamesbrindle

This comment has been minimized.

Copy link

@jamesbrindle jamesbrindle commented Apr 26, 2020

This is absolutely perfect!

@lextm

This comment has been minimized.

Copy link

@lextm lextm commented May 6, 2020

Converted the logic to PowerShell,

function ConvertTo-Icon
{
    <#
    .Synopsis
        Converts image to icons
    .Description
        Converts an image to an icon
    .Example
        ConvertTo-Icon -File .\Logo.png -OutputFile .\Favicon.ico
    #>
    [CmdletBinding()]
    param(
    # The file
    [Parameter(Mandatory=$true, Position=0,ValueFromPipelineByPropertyName=$true)]
    [Alias('Fullname')]
    [string]$File,
   
    # If provided, will output the icon to a location
    [Parameter(Position=1, ValueFromPipelineByPropertyName=$true)]
    [string]$OutputFile
    )
    
    begin {
        Add-Type -AssemblyName System.Windows.Forms, System.Drawing   
    }
    
    process {
        #region Load Icon
        $resolvedFile = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($file)
        if (-not $resolvedFile) { return }
        $inputBitmap = [Drawing.Image]::FromFile($resolvedFile)
        $width = $inputBitmap.Width
        $height = $inputBitmap.Height
        $size = New-Object Drawing.Size $width, $height
        $newBitmap = New-Object Drawing.Bitmap $inputBitmap, $size
        #endregion Load Icon

        #region Save Icon                     
        $memoryStream = New-Object System.IO.MemoryStream
        $newBitmap.Save($memoryStream, [System.Drawing.Imaging.ImageFormat]::Png)

        $resolvedOutputFile = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($outputFile)
        $output = [IO.File]::Create("$resolvedOutputFile")
        
        $iconWriter = New-Object System.IO.BinaryWriter($output)
        # 0-1 reserved, 0
        $iconWriter.Write([byte]0)
        $iconWriter.Write([byte]0)

        # 2-3 image type, 1 = icon, 2 = cursor
        $iconWriter.Write([short]1);

        # 4-5 number of images
        $iconWriter.Write([short]1);

        # image entry 1
        # 0 image width
        $iconWriter.Write([byte]$width);
        # 1 image height
        $iconWriter.Write([byte]$height);

        # 2 number of colors
        $iconWriter.Write([byte]0);

        # 3 reserved
        $iconWriter.Write([byte]0);

        # 4-5 color planes
        $iconWriter.Write([short]0);

        # 6-7 bits per pixel
        $iconWriter.Write([short]32);

        # 8-11 size of image data
        $iconWriter.Write([int]$memoryStream.Length);

        # 12-15 offset of image data
        $iconWriter.Write([int](6 + 16));

        # write image data
        # png data must contain the whole png data file
        $iconWriter.Write($memoryStream.ToArray());

        $iconWriter.Flush();
        $output.Close()               
        #endregion Save Icon

        #region Cleanup
        $memoryStream.Dispose()
        $newBitmap.Dispose()
        $inputBitmap.Dispose()
        #endregion Cleanup
    }
}
@FreakLign

This comment has been minimized.

Copy link

@FreakLign FreakLign commented May 24, 2020

/// <summary>
/// Provides helper methods for imaging
/// </summary>
public static class ImagingHelper
{
    /// <summary>
    /// Converts a PNG image to a icon (ico)
    /// </summary>
    /// <param name="input">The input stream</param>
    /// <param name="output">The output stream</param>
    /// <param name="size">The size (16x16 px by default)</param>
    /// <param name="preserveAspectRatio">Preserve the aspect ratio</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(Stream input, Stream output, int size = 16, bool preserveAspectRatio = false)
    {
        Bitmap inputBitmap = (Bitmap)Bitmap.FromStream(input);
        if (inputBitmap != null)
        {
            int width, height;
            if (preserveAspectRatio)
            {
                width = size;
                height = inputBitmap.Height / inputBitmap.Width * size;
            }
            else
            {
                width = height = size;
            }
            Bitmap newBitmap = new Bitmap(inputBitmap, new Size(width, height));
            if (newBitmap != null)
            {
                // save the resized png into a memory stream for future use
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    newBitmap.Save(memoryStream, ImageFormat.Png);

                    BinaryWriter iconWriter = new BinaryWriter(output);
                    if (output != null && iconWriter != null)
                    {
                        // 0-1 reserved, 0
                        iconWriter.Write((byte)0);
                        iconWriter.Write((byte)0);

                        // 2-3 image type, 1 = icon, 2 = cursor
                        iconWriter.Write((short)1);

                        // 4-5 number of images
                        iconWriter.Write((short)1);

                        // image entry 1
                        // 0 image width
                        iconWriter.Write((byte)width);
                        // 1 image height
                        iconWriter.Write((byte)height);

                        // 2 number of colors
                        iconWriter.Write((byte)0);

                        // 3 reserved
                        iconWriter.Write((byte)0);

                        // 4-5 color planes
                        iconWriter.Write((short)0);

                        // 6-7 bits per pixel
                        iconWriter.Write((short)32);

                        // 8-11 size of image data
                        iconWriter.Write((int)memoryStream.Length);

                        // 12-15 offset of image data
                        iconWriter.Write((int)(6 + 16));

                        // write image data
                        // png data must contain the whole png data file
                        iconWriter.Write(memoryStream.ToArray());

                        iconWriter.Flush();

                        return true;
                    }
                }
            }
            return false;
        }
        return false;
    }

    /// <summary>
    /// Converts a PNG image to a icon (ico)
    /// </summary>
    /// <param name="inputPath">The input path</param>
    /// <param name="outputPath">The output path</param>
    /// <param name="size">The size (16x16 px by default)</param>
    /// <param name="preserveAspectRatio">Preserve the aspect ratio</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(string inputPath, string outputPath, int size = 16, bool preserveAspectRatio = false)
    {
        using (FileStream inputStream = new FileStream(inputPath, FileMode.Open))
        using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
        {
            return ConvertToIcon(inputStream, outputStream, size, preserveAspectRatio);
        }
    }
}

Thank You

@tristian2

This comment has been minimized.

Copy link

@tristian2 tristian2 commented Jun 18, 2020

this is great TY

@jessiewestlake

This comment has been minimized.

Copy link

@jessiewestlake jessiewestlake commented Oct 15, 2020

PowerShell Compatible Version

Although @lextm ported the code to PowerShell (many props, Sir), they did not include all the functionality added later by other contributors such as @kipusoep, @bananbl, and @mdiller.

Here is a usable version with the additional modifications and adapted to work with PowerShell.

I didn't have time to convert all the code to PowerShell syntax like @lextm did, so I added it as a custom type and included the required dependencies and command syntax that can be difficult to figure out with PowerShell. After adding the custom type, I wrapped it in a PowerShell function inspired by @lextm.

Parameters/Parameter Sets should be added later to take full advantage of all the constructors and for adjusting other things like size, etc.

The Preserve Aspect Ratio from @ChuckSavage wasn't included in the other C# code (possibly they accounted for it in another way), so I didn't end up adding it here yet, but maybe later; or someone else could do it.

Compatibility

OS Version PowerShell Version .NET Version ✔️
Windows 10, ver. 2004, build 19041.572 Windows PowerShell 5.1 4.8 ✔️

License

As per @darkfall, this work is licensed under CC BY-SA 4.0 BY: Credit must be given to you, the creator. SA: Adaptations must be shared under the same terms.

Code

$TypeDefinition = @'
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Collections.Generic;
using System.Drawing.Drawing2D;

/// <summary>
/// Adapted from this gist: https://gist.github.com/darkfall/1656050
/// Provides helper methods for imaging
/// </summary>
public static class ImagingHelper
{
    /// <summary>
    /// Converts a PNG image to a icon (ico) with all the sizes windows likes
    /// </summary>
    /// <param name="inputBitmap">The input bitmap</param>
    /// <param name="output">The output stream</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(Bitmap inputBitmap, Stream output)
    {
        if (inputBitmap == null)
            return false;

        int[] sizes = new int[] { 256, 48, 32, 16 };

        // Generate bitmaps for all the sizes and toss them in streams
        List<MemoryStream> imageStreams = new List<MemoryStream>();
        foreach (int size in sizes)
        {
            Bitmap newBitmap = ResizeImage(inputBitmap, size, size);
            if (newBitmap == null)
                return false;
            MemoryStream memoryStream = new MemoryStream();
            newBitmap.Save(memoryStream, ImageFormat.Png);
            imageStreams.Add(memoryStream);
        }

        BinaryWriter iconWriter = new BinaryWriter(output);
        if (output == null || iconWriter == null)
            return false;

        int offset = 0;

        // 0-1 reserved, 0
        iconWriter.Write((byte)0);
        iconWriter.Write((byte)0);

        // 2-3 image type, 1 = icon, 2 = cursor
        iconWriter.Write((short)1);

        // 4-5 number of images
        iconWriter.Write((short)sizes.Length);

        offset += 6 + (16 * sizes.Length);

        for (int i = 0; i < sizes.Length; i++)
        {
            // image entry 1
            // 0 image width
            iconWriter.Write((byte)sizes[i]);
            // 1 image height
            iconWriter.Write((byte)sizes[i]);

            // 2 number of colors
            iconWriter.Write((byte)0);

            // 3 reserved
            iconWriter.Write((byte)0);

            // 4-5 color planes
            iconWriter.Write((short)0);

            // 6-7 bits per pixel
            iconWriter.Write((short)32);

            // 8-11 size of image data
            iconWriter.Write((int)imageStreams[i].Length);

            // 12-15 offset of image data
            iconWriter.Write((int)offset);

            offset += (int)imageStreams[i].Length;
        }

        for (int i = 0; i < sizes.Length; i++)
        {
            // write image data
            // png data must contain the whole png data file
            iconWriter.Write(imageStreams[i].ToArray());
            imageStreams[i].Close();
        }

        iconWriter.Flush();

        return true;
    }

    /// <summary>
    /// Converts a PNG image to a icon (ico)
    /// </summary>
    /// <param name="input">The input stream</param>
    /// <param name="output">The output stream</param
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(Stream input, Stream output)
    {
        Bitmap inputBitmap = (Bitmap)Bitmap.FromStream(input);
        return ConvertToIcon(inputBitmap, output);
    }

    /// <summary>
    /// Converts a PNG image to a icon (ico)
    /// </summary>
    /// <param name="inputPath">The input path</param>
    /// <param name="outputPath">The output path</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(string inputPath, string outputPath)
    {
        using (FileStream inputStream = new FileStream(inputPath, FileMode.Open))
        using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
        {
            return ConvertToIcon(inputStream, outputStream);
        }
    }



    /// <summary>
    /// Converts an image to a icon (ico)
    /// </summary>
    /// <param name="inputImage">The input image</param>
    /// <param name="outputPath">The output path</param>
    /// <returns>Wether or not the icon was succesfully generated</returns>
    public static bool ConvertToIcon(Image inputImage, string outputPath)
    {
        using (FileStream outputStream = new FileStream(outputPath, FileMode.OpenOrCreate))
        {
            return ConvertToIcon(new Bitmap(inputImage), outputStream);
        }
    }


    /// <summary>
    /// Resize the image to the specified width and height.
    /// Found on stackoverflow: https://stackoverflow.com/questions/1922040/resize-an-image-c-sharp
    /// </summary>
    /// <param name="image">The image to resize.</param>
    /// <param name="width">The width to resize to.</param>
    /// <param name="height">The height to resize to.</param>
    /// <returns>The resized image.</returns>
    public static Bitmap ResizeImage(Image image, int width, int height)
    {
        var destRect = new Rectangle(0, 0, width, height);
        var destImage = new Bitmap(width, height);

        destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

        using (var graphics = Graphics.FromImage(destImage))
        {
            graphics.CompositingMode = CompositingMode.SourceCopy;
            graphics.CompositingQuality = CompositingQuality.HighQuality;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.SmoothingMode = SmoothingMode.HighQuality;
            graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

            using (var wrapMode = new ImageAttributes())
            {
                wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
            }
        }

        return destImage;
    }
}
'@

Add-Type -TypeDefinition $TypeDefinition -ReferencedAssemblies 'System.Drawing','System.IO','System.Collections'

<#
.Synopsis
    Converts .PNG images to icons
.Description
    Converts a .PNG image to an icon
.Example
    ConvertTo-Icon -Path .\Logo.png -Destination .\Favicon.ico
#>
Function ConvertTo-Icon
{
    [CmdletBinding()]
    param(
    # The file
    [Parameter(Mandatory=$true, Position=0,ValueFromPipelineByPropertyName=$true)]
    [Alias('Fullname','File')]
    [string]$Path,
   
    # If provided, will output the icon to a location
    [Parameter(Position=1, ValueFromPipelineByPropertyName=$true)]
    [Alias('OutputFile')]
    [string]$Destination
    )
    
    Begin
    {
        If (-Not 'ImagingHelper' -as [Type])
        {
            Throw 'The custom "ImagingHelper" type is not loaded'
        }
    }
    
    Process
    {
        #region Resolve Path
        $ResolvedFile = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($Path)
        If (-not $ResolvedFile)
        {
            return
        }
        #endregion        

        [ImagingHelper]::ConvertToIcon($ResolvedFile[0].Path,$Destination)
    }
    End
    {
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.