Skip to content

Commit 53a445a

Browse files
authored
Moved away from SkiaSharp in favor of lower footprint System.Drawing.Common (#193)
Fixes #192.
1 parent 091b1cc commit 53a445a

File tree

3 files changed

+76
-70
lines changed

3 files changed

+76
-70
lines changed

src/winapp-CLI/Directory.Packages.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
<PackageVersion Include="System.CommandLine" Version="2.0.0" />
66
<PackageVersion Include="System.Diagnostics.EventLog" Version="10.0.0" />
77
<PackageVersion Include="Microsoft.Telemetry.Inbox.Managed" Version="10.0.25148.1001-220626-1600.rs-fun-deploy-dev5" />
8-
<PackageVersion Include="SkiaSharp" Version="3.119.1" />
8+
<PackageVersion Include="System.Drawing.Common" Version="9.0.0" />
99
</ItemGroup>
10-
</Project>
10+
</Project>

src/winapp-CLI/WinApp.Cli/Services/ImageAssetService.cs

Lines changed: 73 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
// Licensed under the MIT License.
33

44
using Microsoft.Extensions.Logging;
5-
using SkiaSharp;
5+
using System.Drawing;
6+
using System.Drawing.Drawing2D;
7+
using System.Drawing.Imaging;
68
using WinApp.Cli.Helpers;
79

810
namespace WinApp.Cli.Services;
@@ -36,90 +38,94 @@ public async Task GenerateAssetsAsync(FileInfo sourceImagePath, DirectoryInfo ou
3638
logger.LogInformation("{UISymbol} Generating MSIX image assets from: {SourceImage}", UiSymbols.Info, sourceImagePath.Name);
3739

3840
// Load the source image
39-
using var sourceImage = SKBitmap.Decode(sourceImagePath.FullName);
40-
if (sourceImage == null)
41+
Bitmap sourceImage;
42+
try
4143
{
42-
throw new InvalidOperationException($"Failed to decode image: {sourceImagePath.FullName}. Please ensure the file is a valid image format.");
44+
sourceImage = new Bitmap(sourceImagePath.FullName);
4345
}
44-
45-
logger.LogDebug("Source image size: {Width}x{Height}", sourceImage.Width, sourceImage.Height);
46-
47-
// Ensure output directory exists
48-
if (!outputDirectory.Exists)
46+
catch (Exception ex)
4947
{
50-
outputDirectory.Create();
48+
throw new InvalidOperationException($"Failed to decode image: {sourceImagePath.FullName}. Please ensure the file is a valid image format.", ex);
5149
}
5250

53-
// Generate each required asset
54-
var successCount = 0;
55-
foreach (var (fileName, width, height) in AssetSpecifications)
51+
using (sourceImage)
5652
{
57-
try
53+
logger.LogDebug("Source image size: {Width}x{Height}", sourceImage.Width, sourceImage.Height);
54+
55+
// Ensure output directory exists
56+
if (!outputDirectory.Exists)
5857
{
59-
var outputPath = Path.Combine(outputDirectory.FullName, fileName);
60-
await GenerateAssetAsync(sourceImage, outputPath, width, height, cancellationToken);
61-
successCount++;
62-
logger.LogDebug(" {UISymbol} Generated: {FileName} ({Width}x{Height})", UiSymbols.Check, fileName, width, height);
58+
outputDirectory.Create();
6359
}
64-
catch (Exception ex)
60+
61+
// Generate each required asset
62+
var successCount = 0;
63+
foreach (var (fileName, width, height) in AssetSpecifications)
6564
{
66-
logger.LogWarning("{UISymbol} Failed to generate {FileName}: {ErrorMessage}", UiSymbols.Warning, fileName, ex.Message);
65+
try
66+
{
67+
var outputPath = Path.Combine(outputDirectory.FullName, fileName);
68+
await GenerateAssetAsync(sourceImage, outputPath, width, height, cancellationToken);
69+
successCount++;
70+
logger.LogDebug(" {UISymbol} Generated: {FileName} ({Width}x{Height})", UiSymbols.Check, fileName, width, height);
71+
}
72+
catch (Exception ex)
73+
{
74+
logger.LogWarning("{UISymbol} Failed to generate {FileName}: {ErrorMessage}", UiSymbols.Warning, fileName, ex.Message);
75+
}
6776
}
68-
}
6977

70-
logger.LogInformation("{UISymbol} Successfully generated {Count} of {Total} image assets",
71-
UiSymbols.Party, successCount, AssetSpecifications.Length);
78+
logger.LogInformation("{UISymbol} Successfully generated {Count} of {Total} image assets",
79+
UiSymbols.Party, successCount, AssetSpecifications.Length);
80+
}
7281
}
7382

74-
private static async Task GenerateAssetAsync(SKBitmap sourceImage, string outputPath, int targetWidth, int targetHeight, CancellationToken cancellationToken)
83+
private static async Task GenerateAssetAsync(Bitmap sourceImage, string outputPath, int targetWidth, int targetHeight, CancellationToken cancellationToken)
7584
{
76-
// Calculate scaling to fit target dimensions while maintaining aspect ratio
77-
var sourceAspect = (float)sourceImage.Width / sourceImage.Height;
78-
var targetAspect = (float)targetWidth / targetHeight;
79-
80-
int scaledWidth, scaledHeight;
81-
if (sourceAspect > targetAspect)
82-
{
83-
// Source is wider - fit to width
84-
scaledWidth = targetWidth;
85-
scaledHeight = (int)(targetWidth / sourceAspect);
86-
}
87-
else
85+
await Task.Run(() =>
8886
{
89-
// Source is taller - fit to height
90-
scaledHeight = targetHeight;
91-
scaledWidth = (int)(targetHeight * sourceAspect);
92-
}
87+
// Calculate scaling to fit target dimensions while maintaining aspect ratio
88+
var sourceAspect = (float)sourceImage.Width / sourceImage.Height;
89+
var targetAspect = (float)targetWidth / targetHeight;
9390

94-
// Create the target bitmap with the required dimensions
95-
using var targetBitmap = new SKBitmap(targetWidth, targetHeight);
96-
using var canvas = new SKCanvas(targetBitmap);
91+
int scaledWidth, scaledHeight;
92+
if (sourceAspect > targetAspect)
93+
{
94+
// Source is wider - fit to width
95+
scaledWidth = targetWidth;
96+
scaledHeight = (int)(targetWidth / sourceAspect);
97+
}
98+
else
99+
{
100+
// Source is taller - fit to height
101+
scaledHeight = targetHeight;
102+
scaledWidth = (int)(targetHeight * sourceAspect);
103+
}
97104

98-
// Fill with transparent background
99-
canvas.Clear(SKColors.Transparent);
105+
// Create the target bitmap with the required dimensions
106+
using var targetBitmap = new Bitmap(targetWidth, targetHeight, PixelFormat.Format32bppArgb);
107+
using var graphics = Graphics.FromImage(targetBitmap);
100108

101-
// Calculate position to center the scaled image
102-
var destRect = new SKRect(
103-
(targetWidth - scaledWidth) / 2f,
104-
(targetHeight - scaledHeight) / 2f,
105-
(targetWidth + scaledWidth) / 2f,
106-
(targetHeight + scaledHeight) / 2f
107-
);
109+
// Set high-quality rendering options
110+
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
111+
graphics.SmoothingMode = SmoothingMode.HighQuality;
112+
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
113+
graphics.CompositingQuality = CompositingQuality.HighQuality;
114+
graphics.CompositingMode = CompositingMode.SourceOver;
108115

109-
// Draw the scaled image
110-
var paint = new SKPaint
111-
{
112-
IsAntialias = true
113-
};
114-
canvas.DrawBitmap(sourceImage, destRect, paint);
115-
116-
// Encode and save as PNG
117-
using var image = SKImage.FromBitmap(targetBitmap);
118-
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
119-
120-
// Write to file asynchronously
121-
await using var stream = File.Create(outputPath);
122-
data.SaveTo(stream);
123-
await stream.FlushAsync(cancellationToken);
116+
// Fill with transparent background
117+
graphics.Clear(Color.Transparent);
118+
119+
// Calculate position to center the scaled image
120+
var x = (targetWidth - scaledWidth) / 2f;
121+
var y = (targetHeight - scaledHeight) / 2f;
122+
var destRect = new RectangleF(x, y, scaledWidth, scaledHeight);
123+
124+
// Draw the scaled image
125+
graphics.DrawImage(sourceImage, destRect);
126+
127+
// Save as PNG
128+
targetBitmap.Save(outputPath, ImageFormat.Png);
129+
}, cancellationToken);
124130
}
125131
}

src/winapp-CLI/WinApp.Cli/WinApp.Cli.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
5050
<PackageReference Include="System.CommandLine" />
5151
<PackageReference Include="System.Diagnostics.EventLog" />
52-
<PackageReference Include="SkiaSharp" />
52+
<PackageReference Include="System.Drawing.Common" />
5353
</ItemGroup>
5454

5555
<ItemGroup>

0 commit comments

Comments
 (0)