/// <summary> /// Saves the specified <see cref="Bitmap"/> objects as a single /// icon into the output stream. /// </summary> /// <param name="images">The bitmaps to save as an icon.</param> /// <param name="stream">The output stream.</param> /// <remarks> /// The expected input for the <paramref name="images"/> parameter are /// portable network graphic files that have a <see cref="Image.PixelFormat"/> /// of <see cref="PixelFormat.Format32bppArgb"/> and where the /// width is less than or equal to <see cref="IconFactory.MaxIconWidth"/> and the /// height is less than or equal to <see cref="MaxIconHeight"/>. /// </remarks> /// <exception cref="InvalidOperationException"> /// Occurs if any of the input images do /// not follow the required image format. See remarks for details. /// </exception> /// <exception cref="ArgumentNullException"> /// Occurs if any of the arguments are null. /// </exception> public static void SavePngsAsIcon(IEnumerable <Bitmap> images, Stream stream) { if (images == null) { throw new ArgumentNullException("images"); } if (stream == null) { throw new ArgumentNullException("stream"); } // validates the pngs IconFactory.ThrowForInvalidPngs(images); Bitmap[] orderedImages = images.OrderBy(i => i.Width) .ThenBy(i => i.Height) .ToArray(); using (var writer = new BinaryWriter(stream)) { // write the header writer.Write(IconFactory.HeaderReserved); writer.Write(IconFactory.HeaderIconType); writer.Write((ushort)orderedImages.Length); // save the image buffers and offsets Dictionary <uint, byte[]> buffers = new Dictionary <uint, byte[]>(); // tracks the length of the buffers as the iterations occur // and adds that to the offset of the entries uint lengthSum = 0; uint baseOffset = (uint)(IconFactory.HeaderLength + IconFactory.EntryLength * orderedImages.Length); for (int i = 0; i < orderedImages.Length; i++) { Bitmap image = orderedImages[i]; // creates a byte array from an image byte[] buffer = IconFactory.CreateImageBuffer(image); // calculates what the offset of this image will be // in the stream uint offset = (baseOffset + lengthSum); // writes the image entry writer.Write(IconFactory.GetIconWidth(image)); writer.Write(IconFactory.GetIconHeight(image)); writer.Write(IconFactory.PngColorsInPalette); writer.Write(IconFactory.EntryReserved); writer.Write(IconFactory.PngColorPlanes); writer.Write((ushort)Image.GetPixelFormatSize(image.PixelFormat)); writer.Write((uint)buffer.Length); writer.Write(offset); lengthSum += (uint)buffer.Length; // adds the buffer to be written at the offset buffers.Add(offset, buffer); } // writes the buffers for each image foreach (var kvp in buffers) { // seeks to the specified offset required for the image buffer writer.BaseStream.Seek(kvp.Key, SeekOrigin.Begin); // writes the buffer writer.Write(kvp.Value); } } }