File: GenerateSplashAndroidResources.cs
Web Access
Project: src\src\SingleProject\Resizetizer\src\Resizetizer.csproj (Microsoft.Maui.Resizetizer)
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using SkiaSharp;
 
namespace Microsoft.Maui.Resizetizer
{
	/// <summary>
	/// Generates files relating to the Android splash screen:
	///  - Resources/values/maui_colors.xml
	///  - Resources/drawable/maui_splash_image.xml
	///  - Resources/drawable-v31/maui_splash_image.xml
	///  - Resources/[drawable]/[splash].png
	/// </summary>
	public class GenerateSplashAndroidResources : Task, ILogger
	{
		[Required]
		public string IntermediateOutputPath { get; set; }
 
		[Required]
		public ITaskItem[] MauiSplashScreen { get; set; }
 
		public string InputsFile { get; set; }
 
		public override bool Execute()
		{
			Log.LogMessage(MessageImportance.Low, $"Splash Screen: Intermediate Path " + IntermediateOutputPath);
 
			var splash = MauiSplashScreen?.FirstOrDefault();
			if (splash is null)
			{
				Log.LogMessage(MessageImportance.Low, $"Splash Screen: No images found.");
				return true;
			}
 
			try
			{
				var info = ResizeImageInfo.Parse(splash);
 
				var resizer = new Resizer(info, IntermediateOutputPath, this);
 
				WriteImages(resizer);
				WriteColors(resizer);
				WriteDrawable(resizer);
				WriteDrawable_v31(resizer);
 
				return !Log.HasLoggedErrors;
			}
			catch (Exception ex)
			{
				Log.LogError(null, "MAUI0000", null, null, 0, 0, 0, 0, ex.ToString());
				return false;
			}
		}
 
		static readonly XmlWriterSettings Settings = new XmlWriterSettings { Indent = true };
		const string Namespace = "http://schemas.android.com/apk/res/android";
		const string Comment = "This file was auto-generated by .NET MAUI.";
		const float PreferredImageSize = 108f;
 
		private void WriteImages(Resizer resizer)
		{
			if (resizer.Info.Resize)
			{
				foreach (var dpi in DpiPath.Android.Image)
				{
					Log.LogMessage(MessageImportance.Low, $"Splash Screen Resize: " + dpi);
					resizer.Resize(dpi, InputsFile);
				}
			}
			else
			{
				var dpi = DpiPath.Android.Original;
 
				Log.LogMessage(MessageImportance.Low, $"Splash Screen Copy: " + dpi);
				resizer.CopyFile(dpi, InputsFile);
			}
		}
 
		void WriteColors(Resizer resizer)
		{
			var dir = Path.Combine(IntermediateOutputPath, "values");
			Directory.CreateDirectory(dir);
 
			var colorsFile = Path.Combine(dir, "maui_colors.xml");
 
			Log.LogMessage(MessageImportance.Low, $"Splash Screen Colors: " + colorsFile);
 
			using var writer = XmlWriter.Create(colorsFile, Settings);
			writer.WriteComment(Comment);
			writer.WriteStartElement("resources");
 
			if (resizer.Info.Color is not null)
			{
				writer.WriteStartElement("color");
				writer.WriteAttributeString("name", "maui_splash_color");
				writer.WriteString(resizer.Info.Color.ToString());
				writer.WriteEndElement();
			}
 
			writer.WriteEndDocument();
		}
 
		void WriteDrawable(Resizer resizer)
		{
			var dir = Path.Combine(IntermediateOutputPath, "drawable");
			Directory.CreateDirectory(dir);
 
			var drawableFile = Path.Combine(dir, "maui_splash_image.xml");
 
			Log.LogMessage(MessageImportance.Low, $"Splash Screen Drawable: " + drawableFile);
 
			using var writer = XmlWriter.Create(drawableFile, Settings);
			writer.WriteComment(Comment);
			writer.WriteStartElement("layer-list");
			writer.WriteAttributeString("xmlns", "android", ns: null, value: Namespace);
 
			writer.WriteStartElement("item");
 
			writer.WriteStartElement("bitmap");
			writer.WriteAttributeString("android", "gravity", Namespace, "center");
			writer.WriteAttributeString("android", "src", Namespace, "@drawable/" + resizer.Info.OutputName);
			writer.WriteAttributeString("android", "mipMap", Namespace, "true");
 
			writer.WriteEndDocument();
		}
 
		void WriteDrawable_v31(Resizer resizer)
		{
			var size = CalculateScaledSize(resizer);
 
			var dir = Path.Combine(IntermediateOutputPath, "drawable-v31");
			Directory.CreateDirectory(dir);
 
			var drawableFile = Path.Combine(dir, "maui_splash_image.xml");
 
			Log.LogMessage(MessageImportance.Low, $"Splash Screen Drawable (v31): " + drawableFile);
 
			using var writer = XmlWriter.Create(drawableFile, Settings);
			writer.WriteComment(Comment);
			writer.WriteStartElement("layer-list");
			writer.WriteAttributeString("xmlns", "android", ns: null, value: Namespace);
 
			writer.WriteStartElement("item");
			writer.WriteAttributeString("android", "width", Namespace, size.Width.ToString("0", CultureInfo.InvariantCulture) + "dp");
			writer.WriteAttributeString("android", "height", Namespace, size.Height.ToString("0", CultureInfo.InvariantCulture) + "dp");
			writer.WriteAttributeString("android", "gravity", Namespace, "center");
 
			writer.WriteStartElement("bitmap");
			writer.WriteAttributeString("android", "gravity", Namespace, "fill");
			writer.WriteAttributeString("android", "src", Namespace, "@drawable/" + resizer.Info.OutputName);
			writer.WriteAttributeString("android", "mipMap", Namespace, "true");
 
			writer.WriteEndDocument();
		}
 
		void ILogger.Log(string message)
		{
			Log?.LogMessage(message);
		}
 
		static SKSize CalculateScaledSize(Resizer resizer)
		{
			var size = resizer.BaseSize ?? resizer.GetOriginalSize();
 
			var width = PreferredImageSize;
			var height = PreferredImageSize;
 
			if (size.Width > size.Height)
				height = size.Height / size.Width * width;
			else
				width = size.Width / size.Height * height;
 
			return new SKSize(width, height);
		}
	}
}