Skip to content

Commit 0995388

Browse files
markhazletonclaude
andcommitted
Migrate from System.Drawing to SkiaSharp for cross-platform image processing
- Replace System.Drawing.Common with SkiaSharp (v3.116.0) for MIT-licensed, cross-platform image support - Update ImageExtensions to use SKBitmap and SKSamplingOptions APIs - Update BaseController image upload to use SkiaSharp encoding - Update ImageExtensionsTests to use SkiaSharp types - Remove libgdiplus dependency from Azure workflow (no longer needed) - All 192 tests now pass on both Windows and Linux without native library dependencies Benefits: - No more libgdiplus dependency issues on Linux - Pure cross-platform solution with native library bundles - MIT license (no commercial restrictions) - Modern API using SKSamplingOptions instead of deprecated SKFilterQuality 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 4826d76 commit 0995388

File tree

5 files changed

+28
-32
lines changed

5 files changed

+28
-32
lines changed

.github/workflows/main_samplecrud.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,6 @@ jobs:
5050
restore-keys: |
5151
${{ runner.os }}-npm-
5252
53-
- name: Install libgdiplus (required for System.Drawing tests)
54-
run: |
55-
sudo apt-get update
56-
sudo apt-get install -y libgdiplus
57-
5853
- name: Restore dependencies
5954
run: dotnet restore
6055

Mwh.Sample.Domain.Tests/Extensions/ImageExtensionsTests.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Drawing;
1+
using SkiaSharp;
22

33
namespace Mwh.Sample.Domain.Tests.Extensions;
44

@@ -10,10 +10,10 @@ public class ImageExtensionsTests
1010
public void Resize_WhenMaxWidthAndMaxHeightAreZero_ReturnsOriginalImage()
1111
{
1212
// Arrange
13-
Bitmap originalImage = new Bitmap(100, 200);
13+
using var originalImage = new SKBitmap(100, 200);
1414

1515
// Act
16-
Image resizedImage = originalImage.Resize();
16+
using var resizedImage = originalImage.Resize();
1717

1818
// Assert
1919
Assert.AreEqual(originalImage.Width, resizedImage.Width);
@@ -24,11 +24,11 @@ public void Resize_WhenMaxWidthAndMaxHeightAreZero_ReturnsOriginalImage()
2424
public void Resize_WhenMaxWidthIsZero_ReturnsImageWithProportionalHeight()
2525
{
2626
// Arrange
27-
Bitmap originalImage = new Bitmap(100, 200);
27+
using var originalImage = new SKBitmap(100, 200);
2828
int maxHeight = 150;
2929

3030
// Act
31-
Image resizedImage = originalImage.Resize(maxHeight: maxHeight);
31+
using var resizedImage = originalImage.Resize(maxHeight: maxHeight);
3232

3333
// Assert
3434
Assert.AreEqual(maxHeight, resizedImage.Height);
@@ -39,11 +39,11 @@ public void Resize_WhenMaxWidthIsZero_ReturnsImageWithProportionalHeight()
3939
public void Resize_WhenMaxHeightIsZero_ReturnsImageWithProportionalWidth()
4040
{
4141
// Arrange
42-
Bitmap originalImage = new Bitmap(500, 500);
42+
using var originalImage = new SKBitmap(500, 500);
4343
int maxWidth = 120;
4444

4545
// Act
46-
Image resizedImage = originalImage.Resize(maxWidth: maxWidth);
46+
using var resizedImage = originalImage.Resize(maxWidth: maxWidth);
4747

4848
// Assert
4949
Assert.AreEqual(maxWidth, resizedImage.Width);
@@ -54,11 +54,11 @@ public void Resize_WhenMaxHeightIsZero_ReturnsImageWithProportionalWidth()
5454
public void ScaleImage_WhenMaxHeightIsGreaterThanOriginalHeight_ReturnsImageWithProportionalWidth()
5555
{
5656
// Arrange
57-
Bitmap originalImage = new Bitmap(100, 200);
57+
using var originalImage = new SKBitmap(100, 200);
5858
int maxHeight = 300;
5959

6060
// Act
61-
Image scaledImage = originalImage.ScaleImage(maxHeight);
61+
using var scaledImage = originalImage.ScaleImage(maxHeight);
6262

6363
// Assert
6464
Assert.AreEqual(maxHeight, scaledImage.Height);
Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
using System.Drawing;
1+
using SkiaSharp;
22

33
namespace Mwh.Sample.Domain.Extensions
44
{
55
public static class ImageExtensions
66
{
7-
public static Image Resize(this Image image, int maxWidth = 0, int maxHeight = 0)
7+
public static SKBitmap Resize(this SKBitmap image, int maxWidth = 0, int maxHeight = 0)
88
{
99
if (maxWidth == 0)
1010
maxWidth = image.Width;
@@ -18,23 +18,19 @@ public static Image Resize(this Image image, int maxWidth = 0, int maxHeight = 0
1818
int newWidth = (int)(image.Width * ratio);
1919
int newHeight = (int)(image.Height * ratio);
2020

21-
Bitmap newImage = new Bitmap(newWidth, newHeight);
22-
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
23-
return newImage;
21+
var resizedImage = image.Resize(new SKImageInfo(newWidth, newHeight), SKSamplingOptions.Default);
22+
return resizedImage ?? image;
2423
}
25-
public static Image ScaleImage(this Image image, int maxHeight)
24+
25+
public static SKBitmap ScaleImage(this SKBitmap image, int maxHeight)
2626
{
2727
double ratio = (double)maxHeight / image.Height;
2828

2929
int newWidth = (int)(image.Width * ratio);
3030
int newHeight = (int)(image.Height * ratio);
3131

32-
Bitmap newImage = new Bitmap(newWidth, newHeight);
33-
using (Graphics g = Graphics.FromImage(newImage))
34-
{
35-
g.DrawImage(image, 0, 0, newWidth, newHeight);
36-
}
37-
return newImage;
32+
var scaledImage = image.Resize(new SKImageInfo(newWidth, newHeight), SKSamplingOptions.Default);
33+
return scaledImage ?? image;
3834
}
3935
}
4036
}

Mwh.Sample.Domain/Mwh.Sample.Domain.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
<FrameworkReference Include="Microsoft.AspNetCore.App" />
2828
</ItemGroup>
2929
<ItemGroup>
30-
<PackageReference Include="System.Drawing.Common" Version="10.0.0" />
30+
<PackageReference Include="SkiaSharp" Version="3.116.0" />
3131
</ItemGroup>
3232
</Project>

Mwh.Sample.Web/Controllers/BaseController.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11

22
using Mwh.Sample.Domain.Extensions;
3-
using System.Drawing;
4-
using System.Drawing.Imaging;
3+
using SkiaSharp;
54

65
namespace Mwh.Sample.Web.Controllers;
76

@@ -44,9 +43,15 @@ protected BaseController(IConfiguration configuration,
4443
Directory.CreateDirectory(folderPath);
4544
}
4645
string filePath = Path.Combine(folderPath, $"{Guid.NewGuid()}_{$"{Path.GetFileNameWithoutExtension(ProfileImage.FileName)}.png"}");
47-
using Bitmap bmpPostedImage = new(ProfileImage.OpenReadStream());
48-
using Image objImage = bmpPostedImage.ScaleImage(81);
49-
objImage.Save(filePath, ImageFormat.Png);
46+
47+
using var stream = ProfileImage.OpenReadStream();
48+
using var original = SKBitmap.Decode(stream);
49+
using var scaled = original.ScaleImage(81);
50+
using var image = SKImage.FromBitmap(scaled);
51+
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
52+
using var fileStream = System.IO.File.OpenWrite(filePath);
53+
data.SaveTo(fileStream);
54+
5055
return $"{EmployeeId}/{Path.GetFileName(filePath)}";
5156
}
5257

0 commit comments

Comments
 (0)