Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate the Android 7 round app icon #23276

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/SingleProject/Resizetizer/src/DpiPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,25 @@

namespace Microsoft.Maui.Resizetizer
{
internal enum ClipShape
{
None,
// RoundedSquare,
Circle,
// Squircle
}

internal class DpiPath
{
public DpiPath(string path, decimal scale, string nameSuffix = null, string scaleSuffix = null, SKSize? size = null, string[] idioms = null)
public DpiPath(string path, decimal scale, string nameSuffix = null, string scaleSuffix = null, SKSize? size = null, string[] idioms = null, ClipShape clip = ClipShape.None)
{
Path = path;
Scale = scale;
NameSuffix = nameSuffix;
ScaleSuffix = scaleSuffix;
Size = size;
Idioms = idioms;
ClipShape = clip;
}

public string Path { get; set; }
Expand All @@ -32,6 +41,8 @@ public DpiPath(string path, decimal scale, string nameSuffix = null, string scal

public string[] Idioms { get; set; }

public ClipShape ClipShape { get; set; }

public static class Android
{
public static DpiPath Original =>
Expand All @@ -50,11 +61,18 @@ public static DpiPath[] Image
public static DpiPath[] AppIcon
=> new[]
{
// legacy square
new DpiPath("mipmap-mdpi", 1.0m, size: new SKSize(48, 48)),
new DpiPath("mipmap-hdpi", 1.5m, size: new SKSize(48, 48)),
new DpiPath("mipmap-xhdpi", 2.0m, size: new SKSize(48, 48)),
new DpiPath("mipmap-xxhdpi", 3.0m, size: new SKSize(48, 48)),
new DpiPath("mipmap-xxxhdpi", 4.0m, size: new SKSize(48, 48)),
// legacy round for Android 7
new DpiPath("mipmap-mdpi", 1.0m, "_round", size: new SKSize(48, 48), clip: ClipShape.Circle),
new DpiPath("mipmap-hdpi", 1.5m, "_round", size: new SKSize(48, 48), clip: ClipShape.Circle),
new DpiPath("mipmap-xhdpi", 2.0m, "_round", size: new SKSize(48, 48), clip: ClipShape.Circle),
new DpiPath("mipmap-xxhdpi", 3.0m, "_round", size: new SKSize(48, 48), clip: ClipShape.Circle),
new DpiPath("mipmap-xxxhdpi", 4.0m, "_round", size: new SKSize(48, 48), clip: ClipShape.Circle),
};

public static DpiPath[] AppIconParts
Expand Down
24 changes: 24 additions & 0 deletions src/SingleProject/Resizetizer/src/SkiaSharpAppIconTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ void Draw(SKBitmap tempBitmap, DpiPath dpi, SKSize unscaledCanvasSize)

using var canvas = new SKCanvas(tempBitmap);

if (GetClipPath(dpi, canvasSize, unscaledCanvasSize) is { } clipPath)
{
canvas.Clear(SKColors.Transparent);

canvas.ClipPath(clipPath, antialias: true);
}

canvas.Clear(Info.Color ?? SKColors.Transparent);

// draw background
Expand Down Expand Up @@ -141,5 +148,22 @@ void Draw(SKBitmap tempBitmap, DpiPath dpi, SKSize unscaledCanvasSize)
foregroundTools.DrawUnscaled(canvas, fgScale);
}
}

static SKPath? GetClipPath(DpiPath dpi, SKSize canvasSize, SKSize unscaledCanvasSize)
{
if (dpi.ClipShape == ClipShape.Circle)
{
var radius = Math.Min(canvasSize.Width, canvasSize.Height) / 2;

var clip = new SKPath();
clip.AddCircle(
canvasSize.Width / 2,
canvasSize.Height / 2,
radius);
return clip;
}

return null;
}
}
}
31 changes: 20 additions & 11 deletions src/SingleProject/Resizetizer/test/UnitTests/BaseTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,20 @@ void AssertFileMatchesReal(string actualFilename, object[] args = null, [CallerM

if (!isSimilar)
{
var maskFilename = Path.Combine(DestinationDirectory, GetTestImageFileName(args, methodName));
var root = GetTestProjectRoot();
var filename = GetTestImageFileName(args, methodName);

var maskFilename = Path.Combine(root, "errors", filename);
maskFilename = Path.ChangeExtension(maskFilename, ".mask.png");

Directory.CreateDirectory(Path.GetDirectoryName(maskFilename));

using var mask = SKPixelComparer.GenerateDifferenceMask(actual, expected);
using var data = mask.Encode(SKEncodedImageFormat.Png, 100);
using var maskFile = File.Create(maskFilename);
data.SaveTo(maskFile);
using (var mask = SKPixelComparer.GenerateDifferenceMask(actual, expected))
using (var data = mask.Encode(SKEncodedImageFormat.Png, 100))
using (var maskFile = File.Create(maskFilename))
{
data.SaveTo(maskFile);
}

Assert.True(
isSimilar,
Expand All @@ -155,12 +160,7 @@ void AssertFileMatchesReal(string actualFilename, object[] args = null, [CallerM

void SaveImageResultFileReal(string destinationFilename, object[] args = null, [CallerMemberName] string methodName = null)
{
// working + up 3 levels (../../..)
var root = Directory.GetCurrentDirectory();
root = Path.GetDirectoryName(root);
root = Path.GetDirectoryName(root);
root = Path.GetDirectoryName(root);

var root = GetTestProjectRoot();
var imagePath = GetTestImageFileName(args, methodName);
var path = Path.Combine(root, imagePath);

Expand Down Expand Up @@ -194,5 +194,14 @@ private string GetTestImageFileName(object[] args, string methodName)

return Path.Combine(TestImagesFolderName, name, methodName, filename);
}

private static string GetTestProjectRoot()
{
var cwd = Directory.GetCurrentDirectory();

var root = Path.Combine(cwd, "../../../../../src/SingleProject/Resizetizer/test/UnitTests/");

return root;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -523,10 +523,12 @@ public void SingleRasterAppIconWithOnlyPathSucceedsWithoutVectors(string name, s
Assert.True(success, LogErrorEvents.FirstOrDefault()?.Message);

AssertFileSize($"mipmap-mdpi/{outputName}.png", 48, 48);
AssertFileSize($"mipmap-mdpi/{outputName}_round.png", 48, 48);
AssertFileSize($"mipmap-mdpi/{outputName}_background.png", 108, 108);
AssertFileSize($"mipmap-mdpi/{outputName}_foreground.png", 108, 108);

AssertFileSize($"mipmap-xhdpi/{outputName}.png", 96, 96);
AssertFileSize($"mipmap-xhdpi/{outputName}_round.png", 96, 96);
AssertFileSize($"mipmap-xhdpi/{outputName}_background.png", 216, 216);
AssertFileSize($"mipmap-xhdpi/{outputName}_foreground.png", 216, 216);

Expand All @@ -542,9 +544,11 @@ public void SingleRasterAppIconWithOnlyPathSucceedsWithoutVectors(string name, s
$"<background android:drawable=\"@mipmap/{outputName}_background\"/>");

AssertFileMatches($"mipmap-mdpi/{outputName}.png", new object[] { name, alias, "m", "i" });
AssertFileMatches($"mipmap-mdpi/{outputName}_round.png", new object[] { name, alias, "m", "r" });
AssertFileMatches($"mipmap-mdpi/{outputName}_background.png", new object[] { name, alias, "m", "b" });
AssertFileMatches($"mipmap-mdpi/{outputName}_foreground.png", new object[] { name, alias, "m", "f" });
AssertFileMatches($"mipmap-xhdpi/{outputName}.png", new object[] { name, alias, "xh", "i" });
AssertFileMatches($"mipmap-xhdpi/{outputName}_round.png", new object[] { name, alias, "xh", "r" });
AssertFileMatches($"mipmap-xhdpi/{outputName}_background.png", new object[] { name, alias, "xh", "b" });
AssertFileMatches($"mipmap-xhdpi/{outputName}_foreground.png", new object[] { name, alias, "xh", "f" });
}
Expand Down Expand Up @@ -582,10 +586,12 @@ public void SingleVectorAppIconWithOnlyPathSucceedsWithoutVectors(string name, s
Assert.True(success, LogErrorEvents.FirstOrDefault()?.Message);

AssertFileSize($"mipmap-mdpi/{outputName}.png", 48, 48);
AssertFileSize($"mipmap-mdpi/{outputName}_round.png", 48, 48);
AssertFileSize($"mipmap-mdpi/{outputName}_background.png", 108, 108);
AssertFileSize($"mipmap-mdpi/{outputName}_foreground.png", 108, 108);

AssertFileSize($"mipmap-xhdpi/{outputName}.png", 96, 96);
AssertFileSize($"mipmap-xhdpi/{outputName}_round.png", 96, 96);
AssertFileSize($"mipmap-xhdpi/{outputName}_background.png", 216, 216);
AssertFileSize($"mipmap-xhdpi/{outputName}_foreground.png", 216, 216);

Expand All @@ -601,9 +607,11 @@ public void SingleVectorAppIconWithOnlyPathSucceedsWithoutVectors(string name, s
$"<background android:drawable=\"@mipmap/{outputName}_background\"/>");

AssertFileMatches($"mipmap-mdpi/{outputName}.png", new object[] { name, alias, "m", "i" });
AssertFileMatches($"mipmap-mdpi/{outputName}_round.png", new object[] { name, alias, "m", "r" });
AssertFileMatches($"mipmap-mdpi/{outputName}_background.png", new object[] { name, alias, "m", "b" });
AssertFileMatches($"mipmap-mdpi/{outputName}_foreground.png", new object[] { name, alias, "m", "f" });
AssertFileMatches($"mipmap-xhdpi/{outputName}.png", new object[] { name, alias, "xh", "i" });
AssertFileMatches($"mipmap-xhdpi/{outputName}_round.png", new object[] { name, alias, "xh", "r" });
AssertFileMatches($"mipmap-xhdpi/{outputName}_background.png", new object[] { name, alias, "xh", "b" });
AssertFileMatches($"mipmap-xhdpi/{outputName}_foreground.png", new object[] { name, alias, "xh", "f" });
}
Expand Down Expand Up @@ -643,10 +651,12 @@ public void MultipleVectorAppIconWithOnlyPathConvertsToRaster(string name, strin
Assert.True(success, LogErrorEvents.FirstOrDefault()?.Message);

AssertFileSize($"mipmap-mdpi/{outputName}.png", 48, 48);
AssertFileSize($"mipmap-mdpi/{outputName}_round.png", 48, 48);
AssertFileSize($"mipmap-mdpi/{outputName}_background.png", 108, 108);
AssertFileSize($"mipmap-mdpi/{outputName}_foreground.png", 108, 108);

AssertFileSize($"mipmap-xhdpi/{outputName}.png", 96, 96);
AssertFileSize($"mipmap-xhdpi/{outputName}_round.png", 96, 96);
AssertFileSize($"mipmap-xhdpi/{outputName}_background.png", 216, 216);
AssertFileSize($"mipmap-xhdpi/{outputName}_foreground.png", 216, 216);

Expand All @@ -662,10 +672,12 @@ public void MultipleVectorAppIconWithOnlyPathConvertsToRaster(string name, strin
$"<background android:drawable=\"@mipmap/{outputName}_background\"/>");

AssertFileMatches($"mipmap-mdpi/{outputName}.png", new object[] { name, alias, "m", "i" });
AssertFileMatches($"mipmap-mdpi/{outputName}_round.png", new object[] { name, alias, "m", "r" });
AssertFileMatches($"mipmap-mdpi/{outputName}_background.png", new object[] { name, alias, "m", "b" });
AssertFileMatches($"mipmap-mdpi/{outputName}_foreground.png", new object[] { name, alias, "m", "f" });

AssertFileMatches($"mipmap-xhdpi/{outputName}.png", new object[] { name, alias, "xh", "i" });
AssertFileMatches($"mipmap-xhdpi/{outputName}_round.png", new object[] { name, alias, "xh", "r" });
AssertFileMatches($"mipmap-xhdpi/{outputName}_background.png", new object[] { name, alias, "xh", "b" });
AssertFileMatches($"mipmap-xhdpi/{outputName}_foreground.png", new object[] { name, alias, "xh", "f" });
}
Expand Down Expand Up @@ -707,6 +719,7 @@ public void SingleAppIconWithColors(string filename, string colorString, string

var fn = filename.Replace("camera.", "", StringComparison.OrdinalIgnoreCase);
AssertFileMatches($"mipmap-mdpi/camera.png", new object[] { fn, colorString, tintColorString, "m", "i" });
AssertFileMatches($"mipmap-mdpi/camera_round.png", new object[] { fn, colorString, tintColorString, "m", "r" });
AssertFileMatches($"mipmap-mdpi/camera_background.png", new object[] { fn, colorString, tintColorString, "m", "b" });
AssertFileMatches($"mipmap-mdpi/camera_foreground.png", new object[] { fn, colorString, tintColorString, "m", "f" });
}
Expand Down Expand Up @@ -749,6 +762,7 @@ public void SingleAppIconGeneratesCorrectFilesWithForegroundScale(string filenam

var fn = filename.Replace("camera.", "", StringComparison.OrdinalIgnoreCase);
AssertFileMatches($"mipmap-mdpi/camera.png", new object[] { fn, colorString, tintColorString, "m", "i" });
AssertFileMatches($"mipmap-mdpi/camera_round.png", new object[] { fn, colorString, tintColorString, "m", "r" });
AssertFileMatches($"mipmap-mdpi/camera_background.png", new object[] { fn, colorString, tintColorString, "m", "b" });
AssertFileMatches($"mipmap-mdpi/camera_foreground.png", new object[] { fn, colorString, tintColorString, "m", "f" });
}
Expand Down Expand Up @@ -791,6 +805,7 @@ public void MultipleAppIconWithColors(string filename, string colorString, strin

var fn = filename.Replace("camera.", "", StringComparison.OrdinalIgnoreCase);
AssertFileMatches($"mipmap-mdpi/dotnet_background.png", new object[] { fn, colorString, tintColorString, "m", "i" });
AssertFileMatches($"mipmap-mdpi/dotnet_background_round.png", new object[] { fn, colorString, tintColorString, "m", "r" });
AssertFileMatches($"mipmap-mdpi/dotnet_background_background.png", new object[] { fn, colorString, tintColorString, "m", "b" });
AssertFileMatches($"mipmap-mdpi/dotnet_background_foreground.png", new object[] { fn, colorString, tintColorString, "m", "f" });
}
Expand Down Expand Up @@ -834,6 +849,7 @@ public void MultipleAppIconGeneratesCorrectFilesWithForegroundScale(string filen

var fn = filename.Replace("camera.", "", StringComparison.OrdinalIgnoreCase);
AssertFileMatches($"mipmap-mdpi/dotnet_background.png", new object[] { fn, colorString, tintColorString, "m", "i" });
AssertFileMatches($"mipmap-mdpi/dotnet_background_round.png", new object[] { fn, colorString, tintColorString, "m", "r" });
AssertFileMatches($"mipmap-mdpi/dotnet_background_background.png", new object[] { fn, colorString, tintColorString, "m", "b" });
AssertFileMatches($"mipmap-mdpi/dotnet_background_foreground.png", new object[] { fn, colorString, tintColorString, "m", "f" });
}
Expand Down Expand Up @@ -884,10 +900,12 @@ public void DiffPropoprtionAppIconWithoutBaseUseBackgroundSize(double fgScale, s
AssertFileSize($"mipmap-xhdpi/{Path.GetFileNameWithoutExtension(bg)}_foreground.png", 216, 216);

AssertFileMatches($"mipmap-mdpi/{Path.GetFileNameWithoutExtension(bg)}.png", new object[] { fgScale, bg, fg, "m", "i" });
AssertFileMatches($"mipmap-mdpi/{Path.GetFileNameWithoutExtension(bg)}_round.png", new object[] { fgScale, bg, fg, "m", "r" });
AssertFileMatches($"mipmap-mdpi/{Path.GetFileNameWithoutExtension(bg)}_background.png", new object[] { fgScale, bg, fg, "m", "b" });
AssertFileMatches($"mipmap-mdpi/{Path.GetFileNameWithoutExtension(bg)}_foreground.png", new object[] { fgScale, bg, fg, "m", "f" });

AssertFileMatches($"mipmap-xhdpi/{Path.GetFileNameWithoutExtension(bg)}.png", new object[] { fgScale, bg, fg, "xh", "i" });
AssertFileMatches($"mipmap-xhdpi/{Path.GetFileNameWithoutExtension(bg)}_round.png", new object[] { fgScale, bg, fg, "xh", "r" });
AssertFileMatches($"mipmap-xhdpi/{Path.GetFileNameWithoutExtension(bg)}_background.png", new object[] { fgScale, bg, fg, "xh", "b" });
AssertFileMatches($"mipmap-xhdpi/{Path.GetFileNameWithoutExtension(bg)}_foreground.png", new object[] { fgScale, bg, fg, "xh", "f" });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>$(_MauiDotNetTfm)</TargetFramework>
<AssemblyName>Microsoft.Maui.Resizetizer.UnitTests</AssemblyName>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<DefineConstants Condition="'$(OS)' == 'Windows_NT'">$(DefineConstants);WINDOWS</DefineConstants>
</PropertyGroup>

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading