public ResizedImageInfo Resize(DpiPath dpi, string inputsFile) { var destination = GetFileDestination(dpi); if (Info.IsVector) { destination = Path.ChangeExtension(destination, ".png"); } if (IsUpToDate(Info.Filename, destination, inputsFile, Logger)) { return new ResizedImageInfo { Filename = destination, Dpi = dpi } } ; if (tools == null) { tools = SkiaSharpTools.Create(Info.IsVector, Info.Filename, Info.BaseSize, Info.TintColor, Logger); } tools.Resize(dpi, destination); return(new ResizedImageInfo { Filename = destination, Dpi = dpi }); } }
public ResizedImageInfo Resize(DpiPath dpi, string destination, Func <Stream>?getStream = null) { var sw = new Stopwatch(); sw.Start(); // 1. if an explicit size was given by the type of image, use that // 2. if an explicit size was given in the csproj, use that // 3. try determine the best size based on the background then foreground var(canvasSize, unscaledCanvasSize) = SkiaSharpTools.GetCanvasSize( dpi, Info.BaseSize, backgroundTools ?? foregroundTools); using (var tempBitmap = new SKBitmap(canvasSize.Width, canvasSize.Height)) { Draw(tempBitmap, dpi, unscaledCanvasSize); Save(tempBitmap, destination, getStream); } sw.Stop(); Logger?.Log($"Save app icon took {sw.ElapsedMilliseconds}ms ({destination})"); return(new ResizedImageInfo { Dpi = dpi, Filename = destination }); }
void ProcessBackground(List <ResizedImageInfo> results, DirectoryInfo fullIntermediateOutputPath) { var backgroundFile = Info.Filename; var backgroundExists = File.Exists(backgroundFile); var backgroundDestFilename = AppIconName + "_background.png"; if (backgroundExists) { Logger.Log("Converting Background SVG to PNG: " + backgroundFile); } else { Logger.Log("Background was not found (will manufacture): " + backgroundFile); } foreach (var dpi in DpiPath.Android.AppIconParts) { var dir = Path.Combine(fullIntermediateOutputPath.FullName, dpi.Path); var destination = Path.Combine(dir, backgroundDestFilename); Directory.CreateDirectory(dir); Logger.Log($"App Icon Background Part: " + destination); if (backgroundExists) { // resize the background var tools = SkiaSharpTools.Create(Info.IsVector, Info.Filename, dpi.Size, Info.Color, null, Logger); tools.Resize(dpi, destination, dpiSizeIsAbsolute: true); } else { // manufacture var tools = SkiaSharpTools.CreateImaginary(Info.Color, Logger); tools.Resize(dpi, destination); } results.Add(new ResizedImageInfo { Dpi = dpi, Filename = destination }); } }
public SkiaSharpAppIconTools(ResizeImageInfo info, ILogger logger) { Info = info; Logger = logger; AppIconName = info.OutputName; hasForeground = File.Exists(info.ForegroundFilename); if (hasForeground) { foregroundTools = SkiaSharpTools.Create(info.ForegroundIsVector, info.ForegroundFilename, null, info.TintColor, logger); } backgroundTools = SkiaSharpTools.Create(info.IsVector, info.Filename, null, null, logger); backgroundOriginalSize = backgroundTools.GetOriginalSize(); if (hasForeground) { foregroundOriginalSize = foregroundTools.GetOriginalSize(); } }
public SkiaSharpAppIconTools(ResizeImageInfo info, ILogger?logger) { Info = info; Logger = logger; AppIconName = info.OutputName; var hasBackground = !string.IsNullOrWhiteSpace(info.Filename) && File.Exists(info.Filename); var hasForeground = !string.IsNullOrWhiteSpace(info.ForegroundFilename) && File.Exists(info.ForegroundFilename); if (!hasBackground && !hasForeground) { throw new InvalidOperationException("An app icon needs at least one image."); } if (hasBackground) { backgroundTools = SkiaSharpTools.Create(info.IsVector, info.Filename, null, null, null, logger); } if (hasForeground) { foregroundTools = SkiaSharpTools.Create(info.ForegroundIsVector, info.ForegroundFilename, null, null, info.TintColor, logger); } }
public static (SKSizeI Scaled, SKSize Unscaled) GetCanvasSize(DpiPath dpi, SKSize?baseSize = null, SkiaSharpTools baseTools = null) { // if an explicit size was given by the type of image, use that if (dpi.Size is SKSize size) { var scale = (float)dpi.Scale; var scaled = new SKSizeI( (int)(size.Width * scale), (int)(size.Height * scale)); return(scaled, size); } // if an explicit size was given in the csproj, use that if (baseSize is SKSize bs) { var scale = (float)dpi.Scale; var scaled = new SKSizeI( (int)(bs.Width * scale), (int)(bs.Height * scale)); return(scaled, bs); } // try determine the best size based on the loaded image if (baseTools is not null) { var baseOriginalSize = baseTools.GetOriginalSize(); var(baseScaledSize, _) = baseTools.GetScaledSize(baseOriginalSize, dpi.Scale); return(baseScaledSize, baseOriginalSize); } throw new InvalidOperationException("The canvas size cannot be calculated if there is no size to start from (DPI size, BaseSize or image size)."); }
public IEnumerable <ResizedImageInfo> Generate() { var results = new List <ResizedImageInfo>(); var fullIntermediateOutputPath = new DirectoryInfo(IntermediateOutputPath); var backgroundFile = Info.Filename; var backgroundIsVector = UseVectors && Info.IsVector; var backgroundExt = backgroundIsVector ? ".xml" : ".png"; var backgroundDestFilename = AppIconName + "_background" + backgroundExt; var foregroundFile = Info.ForegroundFilename; var foregroundExists = File.Exists(foregroundFile); var foregroundIsVector = !foregroundExists || (UseVectors && Info.ForegroundIsVector); var foregroundExt = foregroundIsVector ? ".xml" : ".png"; var foregroundDestFilename = AppIconName + "_foreground" + foregroundExt; if (backgroundIsVector) { Logger.Log("Converting Background SVG to Android Drawable Vector: " + backgroundFile); var dir = Path.Combine(fullIntermediateOutputPath.FullName, "drawable-v24"); var destination = Path.Combine(dir, backgroundDestFilename); Directory.CreateDirectory(dir); Svg2VectorDrawable.Svg2Vector.Convert(backgroundFile, destination); results.Add(new ResizedImageInfo { Dpi = new DpiPath("drawable-v24", 1, "_background"), Filename = destination }); } else { Logger.Log("Converting Background SVG to PNG: " + backgroundFile); foreach (var dpi in DpiPath.Android.AppIconParts) { var dir = Path.Combine(fullIntermediateOutputPath.FullName, dpi.Path); var destination = Path.Combine(dir, backgroundDestFilename); Directory.CreateDirectory(dir); Logger.Log($"App Icon Background Part: " + destination); var tools = SkiaSharpTools.Create(Info.IsVector, Info.Filename, dpi.Size, null, Logger); tools.Resize(dpi, destination); results.Add(new ResizedImageInfo { Dpi = dpi, Filename = destination }); } } Logger.Log("Looking for Foreground File: " + foregroundFile); var foregroundDestinationDir = Path.Combine(fullIntermediateOutputPath.FullName, "drawable"); var foregroundDestination = Path.Combine(foregroundDestinationDir, foregroundDestFilename); Directory.CreateDirectory(foregroundDestinationDir); if (foregroundExists) { if (foregroundIsVector) { Logger.Log("Converting Foreground SVG to Android Drawable Vector: " + foregroundFile); Svg2VectorDrawable.Svg2Vector.Convert(foregroundFile, foregroundDestination); results.Add(new ResizedImageInfo { Dpi = new DpiPath("drawable", 1, "_foreground"), Filename = foregroundDestination }); } else { Logger.Log("Converting Foreground SVG to PNG: " + foregroundFile); foreach (var dpi in DpiPath.Android.AppIconParts) { var dir = Path.Combine(fullIntermediateOutputPath.FullName, dpi.Path); var destination = Path.Combine(dir, foregroundDestFilename); Directory.CreateDirectory(dir); Logger.Log($"App Icon Foreground Part: " + destination); var tools = SkiaSharpTools.Create(Info.ForegroundIsVector, Info.ForegroundFilename, dpi.Size, null, Logger); tools.Resize(dpi, destination); results.Add(new ResizedImageInfo { Dpi = dpi, Filename = destination }); } } } else { Logger.Log("Foreground was not found: " + foregroundFile); File.WriteAllText(foregroundDestination, EmptyVectorDrawable); } // process adaptive icon xml { var adaptiveIconXmlStr = AdaptiveIconDrawableXml .Replace("{name}", AppIconName) .Replace("{backgroundType}", backgroundIsVector ? "drawable" : "mipmap") .Replace("{foregroundType}", foregroundIsVector ? "drawable" : "mipmap"); var dir = Path.Combine(fullIntermediateOutputPath.FullName, "mipmap-anydpi-v26"); var adaptiveIconDestination = Path.Combine(dir, AppIconName + ".xml"); var adaptiveIconRoundDestination = Path.Combine(dir, AppIconName + "_round.xml"); Directory.CreateDirectory(dir); // Write out the adaptive icon xml drawables File.WriteAllText(adaptiveIconDestination, adaptiveIconXmlStr); File.WriteAllText(adaptiveIconRoundDestination, adaptiveIconXmlStr); results.Add(new ResizedImageInfo { Dpi = new DpiPath("mipmap-anydpi-v26", 1), Filename = adaptiveIconDestination }); results.Add(new ResizedImageInfo { Dpi = new DpiPath("mipmap-anydpi-v26", 1, "_round"), Filename = adaptiveIconRoundDestination }); } return(results); }