Skip to content

Instantly share code, notes, and snippets.

@michaelbramwell
Last active October 9, 2021 18:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save michaelbramwell/88524358e7d90fab7695 to your computer and use it in GitHub Desktop.
Save michaelbramwell/88524358e7d90fab7695 to your computer and use it in GitHub Desktop.
C# Sprite Generator / Maker (zero config) - generates a sprite-sheet with css classes outputted as a string
internal class SpriteInfo
{
public string Name { get; private set; }
public int X { get; private set; }
public int Y { get; private set; }
public int W { get; private set; }
public int H { get; private set; }
public SpriteInfo(string name, int x, int y, int w, int h)
{
Name = name;
X = x;
Y = y;
W = w;
H = h;
}
}
/// <summary>
/// Add images in a target dir and output as a base64 png sprite sheet referenced in a generated style sheet with css classes
/// Reference - http://codeinreview.com/126/generating-a-css-sprite-image-file/
/// TODO: provide various sprite sorting alg options e.g tilings, vertical. Only hoz at the moment.
/// TODO: Provide alt return type of stream. Only string at the moment
/// TODO: Convert to github repo?
/// </summary>
public static class SpriteMaker
{
public static string Execute(string path)
{
var info = new DirectoryInfo(path);
var dictionary = new Dictionary<FileInfo, Image>();
var padding = 10;
int maxWidth, maxHeight;
maxWidth = maxHeight = 0;
foreach (var file in info.GetFiles())
{
var img = Image.FromFile(file.FullName);
maxWidth += (img.Width + padding);
maxHeight = Math.Max(img.Height, maxHeight);
img.Tag = Path.GetFileNameWithoutExtension(file.FullName);
dictionary.Add(file, img);
}
var generated = dictionary.GenerateSprite(maxWidth, maxHeight, padding);
using (Bitmap sprite = generated.Key)
using (var memoryStream = new MemoryStream())
{
sprite.Save(memoryStream, ImageFormat.Png);
byte[] bytes = memoryStream.GetBuffer();
return GenerateStyleSheet(Convert.ToBase64String(bytes, Base64FormattingOptions.None), generated);
}
}
/// <summary>
/// Iterate over each sprite and add to sprite sheet
/// </summary>
/// <param name="dictionary"></param>
/// <param name="maxWidth"></param>
/// <param name="maxHeight"></param>
/// <param name="padding"></param>
/// <returns></returns>
internal static KeyValuePair<Bitmap, List<SpriteInfo>> GenerateSprite(this Dictionary<FileInfo, Image> dictionary, int maxWidth, int maxHeight, int padding)
{
var sprite = new Bitmap(maxWidth, maxHeight);
var spriteProps = new List<SpriteInfo>();
using (Graphics graphics = Graphics.FromImage(sprite))
{
int xCoord = 0;
foreach (var kvp in dictionary)
{
using (Image img = kvp.Value)
{
graphics.DrawImage(img, xCoord, 0, img.Width, img.Height);
spriteProps.Add(new SpriteInfo(kvp.Key.Name.Replace(kvp.Key.Extension, ""), xCoord, 0, img.Width, img.Height));
xCoord += (img.Width + padding);
}
}
return new KeyValuePair<Bitmap, List<SpriteInfo>>(sprite, spriteProps);
}
}
/// <summary>
/// Create StyleSheet with background positioning for each image
/// </summary>
/// <param name="base64SpriteSheet"></param>
/// <param name="kvp"></param>
/// <returns></returns>
private static string GenerateStyleSheet(string base64SpriteSheet, KeyValuePair<Bitmap, List<SpriteInfo>> kvp)
{
var sb = new StringBuilder();
// sprite sheet
sb.AppendFormat(".spriteSheet {{ display: inline-block; width: {0}px; height: {1}px; background: url('data:image/png;base64,{2}') no-repeat top left; }}",
kvp.Key.Width, kvp.Key.Height, base64SpriteSheet);
// descendants of sprite sheet
kvp.Value.Aggregate(sb, (a, b) => a.AppendLine(string.Format(".spriteSheet.{0} {{ background-position: -{1}px {2}px; width: {3}px; height: {4}px; {5} }} ",
b.Name, b.X, b.Y, b.W, b.H, (b.Name.Contains("display_block")) ? "display: block;" : "")));
return sb.ToString();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment