public async static Task ExportStylesheet(IEnumerable <SpriteFragment> fragments, SpriteDocument doc, SpriteGenerator generator) { if (doc.Stylesheet == Stylesheet.None) { return; } var mainClass = SpriteHelpers.GetIdentifier(doc.FileName); string outputFile = doc.FileName + "." + doc.Stylesheet.ToString().ToLowerInvariant(); var outputDirectory = Path.GetDirectoryName(outputFile); var bgUrl = doc.PathPrefix + SpriteHelpers.MakeRelative(outputFile, doc.FileName + doc.OutputExtension); StringBuilder sb = new StringBuilder(GetDescription(doc.Stylesheet)); if (doc.Stylesheet == Stylesheet.Css) { sb.AppendLine($".{mainClass} {{"); sb.AppendLine($"\tbackground-image: url('{bgUrl}');"); sb.AppendLine($"\tbackground-repeat: no-repeat;"); sb.AppendLine($"\tdisplay: block;"); sb.AppendLine("}"); } foreach (SpriteFragment fragment in fragments) { if (doc.Stylesheet == Stylesheet.Css) { sb.AppendLine($"{GetSelector(fragment.ID, mainClass, doc.Stylesheet)} {{"); sb.AppendLine($"\twidth: {fragment.Width}px;"); sb.AppendLine($"\theight: {fragment.Height}px;"); sb.AppendLine($"\tbackground-position: -{fragment.X}px -{fragment.Y}px;"); sb.AppendLine("}"); } else { sb.AppendLine(GetSelector(fragment.ID, mainClass, doc.Stylesheet) + " {"); sb.AppendLine($"\twidth: {fragment.Width}px;"); sb.AppendLine($"\theight: {fragment.Height}px;"); sb.AppendLine($"\tdisplay: block;"); sb.AppendLine($"\tbackground: url('{bgUrl}') -{fragment.X}px -{fragment.Y}px no-repeat;"); sb.AppendLine("}"); } } if (File.Exists(outputFile) && File.ReadAllText(outputFile) == sb.ToString()) { return; } Directory.CreateDirectory(outputDirectory); using (var writer = new StreamWriter(outputFile)) { generator.OnSaving(outputFile, doc); await writer.WriteAsync(sb.ToString().Replace("-0px", "0")); generator.OnSaved(outputFile, doc); } }
/// <summary> /// Generates an image sprite based on the specified <see cref="SpriteDocument"/>. /// </summary> public async Task Generate(SpriteDocument doc) { var images = GetImages(doc); int width = doc.Orientation == Orientation.Vertical ? images.Values.Max(i => i.Width) + (doc.Padding * 2) : images.Values.Sum(i => i.Width) + (doc.Padding * images.Count) + doc.Padding; int height = doc.Orientation == Orientation.Vertical ? images.Values.Sum(img => img.Height) + (doc.Padding * images.Count) + doc.Padding : images.Values.Max(img => img.Height) + (doc.Padding * 2); List <SpriteFragment> fragments = new List <SpriteFragment>(); using (var bitmap = new Bitmap(width, height)) { bitmap.SetResolution(doc.Dpi, doc.Dpi); using (Graphics canvas = Graphics.FromImage(bitmap)) { if (doc.Orientation == Orientation.Vertical) { Vertical(images, fragments, canvas, doc.Padding); } else { Horizontal(images, fragments, canvas, doc.Padding); } } string outputFile = doc.FileName + doc.OutputExtension; OnSaving(outputFile, doc); bitmap.Save(outputFile, SpriteHelpers.ExtensionFromFormat(doc.Output)); OnSaved(outputFile, doc); } await SpriteExporter.ExportStylesheet(fragments, doc, this); }
/// <summary>Creates a new instance and calculates values based in provided images.</summary> public SpriteDocument(string fileName, IEnumerable <string> images) { FileName = fileName; AddImages(images); if (images.Any()) { var first = Image.FromFile(images.First()); Dpi = (int)Math.Round(first.HorizontalResolution); Output = SpriteHelpers.GetImageFormatFromExtension(images.First()); } }
/// <summary> /// Add image files to the sprite. /// </summary> /// <param name="files">A list of relative file paths.</param> private void AddImages(IEnumerable <string> files) { var dic = new Dictionary <string, string>(); foreach (var file in files) { string name = SpriteHelpers.GetIdentifier(file); string relative = SpriteHelpers.MakeRelative(FileName, file); if (dic.ContainsKey(name)) { name += "_" + Guid.NewGuid().ToString().Replace("-", string.Empty); } dic.Add(name, relative); } Images = dic; }
public async static Task ExportStylesheet(IEnumerable <SpriteFragment> fragments, SpriteDocument doc, SpriteImageGenerator generator) { if (doc.Stylesheet == Stylesheet.None) { return; } var mainClass = SpriteHelpers.GetIdentifier(doc.FileName); string outputFile = doc.FileName + "." + doc.Stylesheet.ToString().ToLowerInvariant(); var outputDirectory = Path.GetDirectoryName(outputFile); var bgUrl = doc.PathPrefix + SpriteHelpers.MakeRelative(outputFile, doc.FileName + doc.OutputExtension); if (doc.AppendCacheBustSpriteSuffix) { using (HashAlgorithm sha = new SHA256Managed()) { byte[] spriteContent = File.ReadAllBytes(doc.FileName + doc.OutputExtension); string spriteHash = Convert.ToBase64String(sha.ComputeHash(spriteContent)); bgUrl += $"?hash={WebUtility.UrlEncode(spriteHash)}"; } } StringBuilder sb = new StringBuilder(GetDescription(doc.Stylesheet)); if (doc.Stylesheet == Stylesheet.Css) { sb.AppendLine($".{mainClass} {{"); sb.AppendLine($"\tbackground-image: url('{bgUrl}');"); sb.AppendLine($"\tbackground-repeat: no-repeat;"); AddCustomStyles(doc.CustomStyles, sb); sb.AppendLine("}"); } foreach (SpriteFragment fragment in fragments) { if (doc.Stylesheet == Stylesheet.Css) { sb.AppendLine($"{GetSelector(fragment.ID, mainClass, doc.Stylesheet)} {{"); sb.AppendLine($"\twidth: {fragment.Width}px;"); sb.AppendLine($"\theight: {fragment.Height}px;"); sb.AppendLine($"\tbackground-position: -{fragment.X}px -{fragment.Y}px;"); sb.AppendLine("}"); } else if (doc.Stylesheet == Stylesheet.Styl) { sb.AppendLine(GetSelector(fragment.ID, mainClass, doc.Stylesheet)); sb.AppendLine($"\twidth {fragment.Width}px"); sb.AppendLine($"\theigh {fragment.Height}px"); sb.AppendLine($"\tbackground-position -{fragment.X}px -{fragment.Y}px"); } else { sb.AppendLine(GetSelector(fragment.ID, mainClass, doc.Stylesheet) + " {"); sb.AppendLine($"\twidth: {fragment.Width}px;"); sb.AppendLine($"\theight: {fragment.Height}px;"); AddCustomStyles(doc.CustomStyles, sb); sb.AppendLine($"\tbackground: url('{bgUrl}') -{fragment.X}px -{fragment.Y}px no-repeat;"); sb.AppendLine("}"); } } if (File.Exists(outputFile) && File.ReadAllText(outputFile) == sb.ToString()) { return; } Directory.CreateDirectory(outputDirectory); using (var writer = new StreamWriter(outputFile)) { generator.OnSaving(outputFile, doc); await writer.WriteAsync(sb.ToString().Replace("-0px", "0")); generator.OnSaved(outputFile, doc); } }