Add multiple image sizes in windows folder icons

This commit is contained in:
Michael Bucari-Tovo
2025-11-03 13:58:21 -07:00
parent 9533f80e89
commit a34efb5e61

View File

@@ -1,7 +1,9 @@
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@@ -11,39 +13,57 @@ namespace WindowsConfigApp;
public class IcoEncoder : IImageEncoder
{
public bool SkipMetadata { get; init; } = true;
public ReadOnlyCollection<int> ExportSizes { get; }
public IcoEncoder(): this(512, 256, 128, 96, 64, 48, 32, 24) { }
public IcoEncoder(params int[] icoSizes)
{
Array.Sort(icoSizes);
ExportSizes = new(icoSizes);
}
public void Encode<TPixel>(Image<TPixel> image, Stream stream) where TPixel : unmanaged, IPixel<TPixel>
{
// https://stackoverflow.com/a/21389253
using var ms = new MemoryStream();
//Knowing the image size ahead of time removes the
//requirement of the output stream to support seeking.
image.SaveAsPng(ms);
byte[][] iconPngs = new byte[ExportSizes.Count][];
for (int i = 0; i < ExportSizes.Count; i++)
{
int size = ExportSizes[i];
using var resized = image.Clone(x => x.Resize(size, size, KnownResamplers.Lanczos2));
using var pngMs = new MemoryStream();
resized.SaveAsPng(pngMs);
iconPngs[i] = pngMs.ToArray();
}
//Disposing of the BinaryWriter disposes the soutput stream. Let the caller clean up.
var bw = new BinaryWriter(stream);
// Header
bw.Write((short)0); // 0-1 : reserved
bw.Write((short)1); // 2-3 : 1=ico, 2=cur
bw.Write((short)1); // 4-5 : number of images
bw.Write((short)0); // 0-1 : reserved
bw.Write((short)1); // 2-3 : 1=ico, 2=cur
bw.Write((short)ExportSizes.Count); // 4-5 : number of images
int dataStart = 6 + (16 * ExportSizes.Count);
// Image directory
var w = image.Width;
if (w >= 256) w = 0;
bw.Write((byte)w); // 0 : width of image
var h = image.Height;
if (h >= 256) h = 0;
bw.Write((byte)h); // 1 : height of image
bw.Write((byte)0); // 2 : number of colors in palette
bw.Write((byte)0); // 3 : reserved
bw.Write((short)0); // 4 : number of color planes
bw.Write((short)0); // 6 : bits per pixel
bw.Write((int)ms.Position); // 8 : image size
bw.Write((int)stream.Position + 4); // 12: offset of image data
ms.Position = 0;
ms.CopyTo(stream); // Image data
for (int i = 0; i < ExportSizes.Count; i++)
{
var size = ExportSizes[i] < 256 ? ExportSizes[i] : 0;
bw.Write((byte)size); // 0 : width of image
bw.Write((byte)size); // 1 : height of image
bw.Write((byte)0); // 2 : number of colors in palette
bw.Write((byte)0); // 3 : reserved
bw.Write((short)0); // 4 : number of color planes
bw.Write((short)0); // 6 : bits per pixel
bw.Write(iconPngs[i].Length); // 8 : image size
bw.Write(dataStart); // 12: offset of image data
dataStart += iconPngs[i].Length;
}
// Image data
for (int i = 0; i < ExportSizes.Count; i++)
bw.Write(iconPngs[i]);
}
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel<TPixel>