Article Purpose
This article illustrates the process of generating icon files (*.ico) from user specified input images. The accompanying Sample Source Code implements a Windows Forms application, allowing for easily testing the icon generation process.
Sample source code
This article is accompanied by a sample source code Visual Studio project which is available for download here.
Using the sample Application
The Sample Application can be used to test/implement the concepts described in this article. The user interface enables the user to browse and select an Image file from the file system, which loads as a scaled preview. In addition, the user can select an icon size from a list of standard icon dimensions: 16×16, 24×24, 32×32, 48×48, 64×64, 96×96 and 128×128 pixels. When a user clicks on the “Save Icon” button the sample application generates an icon in memory based on the specified size converting and scaling the provided input image. If an icon was successfully generated, the in-memory representation will be saved to the file system, based on the filename and file path specified by the user.
The image below is screenshot of the Image to Icon Generator application in action:
The source image features Bellis perennis also known as the common European Daisy (see Wikipedia). The image file is licensed under the Creative Commons Attribution-Share Alike 2.5 Generic license. The original image can be downloaded from Wikipedia.
The resulting icon file generated by the sample application:
Scaling and Aspect Ratio
Icons conform to a set of standard dimensions, all of which equate to a square image due to the width and height values being equal. A potential issue exists in that the specified source image might not have exact square dimensions. In other words, the width and height values of specified source images might differ. The solution lies in creating a square image based on the specified source image. Consider the concept of a square canvas onto which is drawn the source image whilst maintaining its aspect ratio, implementing center alignment from the horizontal and vertical aspect. Listed below is the implementation of an extension method defined as CopyToSquareCanvas, targeting the Bitmap class.
public static Bitmap CopyToSquareCanvas(this Bitmap sourceBitmap, Color canvasBackground) { int maxSide = sourceBitmap.Width > sourceBitmap.Height ? sourceBitmap.Width : sourceBitmap.Height;
Bitmap bitmapResult = new Bitmap(maxSide, maxSide, PixelFormat.Format32bppArgb);
using (Graphics graphicsResult = Graphics.FromImage(bitmapResult)) { graphicsResult.Clear(canvasBackground);
int xOffset = (sourceBitmap.Width - maxSide) / 2; int yOffset = (sourceBitmap.Height - maxSide) / 2;
graphicsResult.DrawImage(sourceBitmap, new Point(xOffset, xOffset)); }
return bitmapResult; }
The size of the resulting Bitmap image is determined by the source image’s longest side, either width or height. To ensure middle alignment both vertically and horizontally the source image is drawn at an offset, determined by the additional buffer area added by the canvas.
Generating the Icon
Once we have created an image conforming to exact square dimensions the next step would be to scale said image to the desired icon size. A convenient method of quickly scaling source images to icon dimensions comes in the form of creating thumbnails.
The sample source code defines the enumeration IconSizeDimensions, which serves to provide a developer friendly reference coupled with actual dimension values by means of specifying explicit enumeration values. Consider the following code snippet:
public enum IconSizeDimensions { IconSize16x16Pixels = 16, IconSize24x24Pixels = 24, IconSize32x32Pixels = 32, IconSize48x48Pixels = 48, IconSize64x64Pixels = 64, IconSize96x96Pixels = 96, IconSize128x128Pixels = 128 }
The crux of this article and sample source code can considered to be the definition of the CreateIcon extension method, which targets the Bitmap class. The definition is as follows:
public static Icon CreateIcon(this Bitmap sourceBitmap, IconSizeDimensions iconSize) { Bitmap squareCanvas = sourceBitmap.CopyToSquareCanvas(Color.Transparent); squareCanvas = (Bitmap)squareCanvas.GetThumbnailImage((int)iconSize, (int)iconSize, null, new IntPtr());
Icon iconResult = Icon.FromHandle(squareCanvas.GetHicon());
return iconResult; }
As discussed the first step is to ensure that the source image conforms to square dimensions, implemented here by invoking the CopyToSquareCanvas extension method. Next the source code implements image scaling by creating a thumbnail image of which the size is based on the specified IconSizeDimensions enum value. The Bitmap.GetHicon method returns a handle to an Icon in the form of an IntPtr, which serves as a parameter to the Icon.FromHandle static method, which returns an instance of the Icon class.
The Implementation
When the user clicks the “Save” button the Sample Application will present the user with a file save dialog. After the user specifies a file name and file path the Sample Application creates a Bitmap reference of the source image by casting the picturebox’s Image property to type Bitmap.
private void btnSaveIcon_Click(object sender, EventArgs e) { if (picSource.Image != null) { SaveFileDialog sfd = new SaveFileDialog(); sfd.Title = "Specify a file name and file path"; sfd.Filter = "Icon Files(*.ico)|*.ico";
if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { System.Drawing.Icon tempIcon = ((Bitmap)picSource.Image).CreateIcon( (IconSizeDimensions)cmbIconSize.SelectedItem);
using (StreamWriter streamWriter = new StreamWriter(sfd.FileName, false)) { tempIcon.Save(streamWriter.BaseStream);
streamWriter.Flush(); streamWriter.Close(); } } } }
When the CreateIcon extension method is invoked, the Icon dimensions selected through the user interface will be passed as a parameter. The last step performed involves persisting the in-memory Icon data to the file system.