Skip to content

Instantly share code, notes, and snippets.

@equinox2k
Last active September 9, 2019 20:56
Show Gist options
  • Select an option

  • Save equinox2k/1763c79d68fe01e8b0553c8c4209a34b to your computer and use it in GitHub Desktop.

Select an option

Save equinox2k/1763c79d68fe01e8b0553c8c4209a34b to your computer and use it in GitHub Desktop.
Example ICNS encoder using ImageSharp
using System;
using System.Linq;
using System.IO;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.PixelFormats;
namespace EQL.IconAutosizer.ImageEncoders
{
//https://en.wikipedia.org/wiki/Apple_Icon_Image_format
public static class ICNSEncoder
{
private struct IconType
{
public string OsType { get; }
public int Size { get; }
public IconType(string osType, int size)
{
OsType = osType;
Size = size;
}
}
private static void ResizeImageToPngBinaryWriter(BinaryWriter binaryWriter, Image<Bgra32> image, int size, out int imageSize)
{
using (var sizedImage = image.Clone(i => i.Resize(size, size)))
{
var position = binaryWriter.BaseStream.Position;
sizedImage.SaveAsPng(binaryWriter.BaseStream);
imageSize = (int)(binaryWriter.BaseStream.Position - position);
}
}
private static byte[] IntToBigEndian(int value)
{
byte[] bytes = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(bytes);
}
return bytes;
}
public static void Encode(string filePath, Image<Bgra32> image)
{
using (var fileStream = File.Create(filePath))
{
Encode(fileStream, image);
}
}
private static IconType[] GetIconTypes()
{
return new IconType[]
{
new IconType("icp4", 16),
new IconType("icp5", 32),
new IconType("icp6", 64),
new IconType("ic07", 128),
new IconType("ic08", 256),
new IconType("ic09", 512),
new IconType("ic10", 1024),
new IconType("ic11", 32),
new IconType("ic12", 64),
new IconType("ic13", 256),
new IconType("ic14", 512)
};
}
public static void Encode(Stream stream, Image<Bgra32> image)
{
if (!stream.CanSeek)
{
throw new Exception("Seekable stream is required");
}
if (image.Width != image.Height || image.Width < 16)
{
throw new Exception("Image should be square and at least 16px in size");
}
var iconTypes = GetIconTypes().Where(i => i.Size < image.Width).ToArray();
var totalSize = 8;
using (var binaryWriter = new BinaryWriter(stream))
{
binaryWriter.Write("icns".ToCharArray());
binaryWriter.Write(0);
foreach (var iconType in iconTypes)
{
stream.Seek(0, SeekOrigin.End);
binaryWriter.Write(iconType.OsType.ToCharArray());
binaryWriter.Write(0);
ResizeImageToPngBinaryWriter(binaryWriter, image, iconType.Size, out var imageSize);
stream.Position = totalSize + 4;
var size = imageSize + 8;
binaryWriter.Write(IntToBigEndian(size));
totalSize += size;
}
stream.Position = 4;
binaryWriter.Write(IntToBigEndian(totalSize));
binaryWriter.Flush();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment