File: GenerateSplashStoryboard.cs
Web Access
Project: src\src\SingleProject\Resizetizer\src\Resizetizer.csproj (Microsoft.Maui.Resizetizer)
#nullable enable
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using SkiaSharp;
 
namespace Microsoft.Maui.Resizetizer
{
	/// <summary>
	/// Generates the MauiSplash.storyboard file for iOS splash screens
	/// </summary>
	public class GenerateSplashStoryboard : Task, ILogger
	{
		[Required]
		public string IntermediateOutputPath { get; set; } = null!;
 
		public ITaskItem[]? MauiSplashScreen { get; set; }
 
		public string? InputsFile { get; set; }
 
		public override bool Execute()
		{
			Log.LogMessage(MessageImportance.Low, $"Splash Screen: Intermediate Path " + IntermediateOutputPath);
 
			try
			{
				var splash = MauiSplashScreen?.FirstOrDefault();
				if (splash is null)
				{
					// write an empty (white) storyboard
					WriteEmptyStoryboard();
				}
				else
				{
					// write a storyboard with an image and background color
					var info = ResizeImageInfo.Parse(splash);
 
					var resizer = new Resizer(info, IntermediateOutputPath, this);
 
					WriteImages(resizer);
					WriteStoryboard(resizer);
				}
 
				return !Log.HasLoggedErrors;
			}
			catch (Exception ex)
			{
				Log.LogError(null, "MAUI0000", null, null, 0, 0, 0, 0, ex.ToString());
				return false;
			}
		}
 
		private void WriteImages(Resizer resizer)
		{
			if (resizer.Info.Resize)
			{
				foreach (var dpi in DpiPath.Ios.Image)
				{
					Log.LogMessage(MessageImportance.Low, $"Splash Screen Resize: " + dpi);
					resizer.Resize(dpi, InputsFile);
				}
			}
			else
			{
				var dpi = DpiPath.Ios.Original;
 
				Log.LogMessage(MessageImportance.Low, $"Splash Screen Copy: " + dpi);
				resizer.CopyFile(dpi, InputsFile);
			}
		}
 
		private void WriteStoryboard(Resizer resizer)
		{
			Directory.CreateDirectory(IntermediateOutputPath);
			var storyboardFile = Path.Combine(IntermediateOutputPath, "MauiSplash.storyboard");
 
			Log.LogMessage(MessageImportance.Low, $"Splash Screen Storyboard: " + storyboardFile);
 
			DpiPath dpi;
			if (resizer.Info.Resize)
				dpi = DpiPath.Ios.Image[0];
			else
				dpi = DpiPath.Ios.Original;
 
			var image = resizer.GetRasterFileDestination(dpi, includeIntermediate: false, includeScale: false);
 
			var color = resizer.Info.Color ?? SKColors.White;
 
			using var writer = File.CreateText(storyboardFile);
			SubstituteStoryboard(writer, "MauiSplash.storyboard", image, color);
		}
 
		private void WriteEmptyStoryboard()
		{
			Directory.CreateDirectory(IntermediateOutputPath);
			var storyboardFile = Path.Combine(IntermediateOutputPath, "MauiSplash.storyboard");
 
			Log.LogMessage(MessageImportance.Low, $"Splash Screen Storyboard (empty): " + storyboardFile);
 
			using var writer = File.CreateText(storyboardFile);
			SubstituteStoryboard(writer, "MauiNoSplash.storyboard", null, SKColors.White);
		}
 
		internal static void SubstituteStoryboard(TextWriter writer, string resourceName, string? image, SKColor color)
		{
			float r = color.Red / (float)byte.MaxValue;
			float g = color.Green / (float)byte.MaxValue;
			float b = color.Blue / (float)byte.MaxValue;
			float a = color.Alpha / (float)byte.MaxValue;
 
			var rStr = r.ToString(CultureInfo.InvariantCulture);
			var gStr = g.ToString(CultureInfo.InvariantCulture);
			var bStr = b.ToString(CultureInfo.InvariantCulture);
			var aStr = a.ToString(CultureInfo.InvariantCulture);
 
			SubstituteStoryboard(writer, resourceName, image, rStr, gStr, bStr, aStr);
		}
 
		internal static void SubstituteStoryboard(TextWriter writer, string resourceName, string? image, string r, string g, string b, string a)
		{
			using var resourceStream = typeof(GenerateSplashStoryboard).Assembly.GetManifestResourceStream(resourceName);
			using var reader = new StreamReader(resourceStream);
 
			while (!reader.EndOfStream)
			{
				var line = reader.ReadLine()
					.Replace("{color.red}", r)
					.Replace("{color.green}", g)
					.Replace("{color.blue}", b)
					.Replace("{color.alpha}", a);
 
				if (!string.IsNullOrEmpty(image))
					line = line.Replace("{imageView.image}", image);
 
 
				writer.WriteLine(line);
			}
		}
 
		void ILogger.Log(string message)
		{
			Log?.LogMessage(message);
		}
	}
}