diff --git a/GarthImgLab.Benchmarks/ApplyPerPixel.cs b/GarthImgLab.Benchmarks/ApplyPerPixel.cs index 7d8ffa0..8b8e0e2 100644 --- a/GarthImgLab.Benchmarks/ApplyPerPixel.cs +++ b/GarthImgLab.Benchmarks/ApplyPerPixel.cs @@ -1,25 +1,25 @@ +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global + namespace GarthImgLab.Benchmarks; -using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using ImageMagick; +using static System.Collections.Concurrent.Partitioner; +using static Helper; +using static Parallel; [MemoryDiagnoser, SuppressMessage("ReSharper", "ClassCanBeSealed.Global")] -public class ApplyPerPixel: IDisposable { +public class ApplyPerPixel { private int _ch; - private MagickImage? _oriImg; - private IMagickImage? _testImg; + private MagickImage _oriImg = new(); + private IMagickImage _testImg = new MagickImage(); private uint _w, _h; - - public void Dispose() { - _oriImg?.Dispose(); - _testImg?.Dispose(); - GC.SuppressFinalize(this); - } + [Params("RGB8.tif", "RGB16.tif")] public string FileName { get; set; } = "RGB8.tif"; [GlobalSetup] public void GlobalSetup() { - _oriImg = new(Path.Combine(AppContext.BaseDirectory, "lena_std.tif")); + _oriImg = new(Path.Combine(AppContext.BaseDirectory, FileName)); _w = _oriImg.Width; _h = _oriImg.Height; _ch = (int)_oriImg.ChannelCount; @@ -27,63 +27,69 @@ public void GlobalSetup() { if (!Test()) throw new InvalidOperationException("结果不一致"); } + [GlobalCleanup] + public void Cleanup() { + _oriImg.Dispose(); + _testImg.Dispose(); + } + private bool Test() { GetValueSetPixel(); - var expected = _testImg!.Signature; - + var expected = _testImg.Signature; _testImg.Dispose(); - _testImg = _oriImg!.CloneArea(_w, _h); + _testImg = _oriImg.CloneArea(_w, _h); + ParGetValueSetPixel(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + GetValuesSetPixels(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + ParGetValuesSetPixels(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + GetAreaSetPixels(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + ParGetAreaSetPixels(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + ToArraySetPixels(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + ParToArraySetPixels(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + AreaPointerUnsafe(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + ParAreaPointerUnsafe(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + return true; } [Benchmark] public void GetValueSetPixel() { - using var px = _testImg!.GetPixels(); + using var px = _testImg.GetPixels(); for (var y = 0; y < _h; y++) for (var x = 0; x < _w; x++) { var v = px.GetValue(x, y)!; @@ -94,9 +100,9 @@ public void GetValueSetPixel() { [Benchmark] public void ParGetValueSetPixel() { - using var px = _testImg!.GetPixels(); - Parallel.ForEach( - Partitioner.Create(0, (int)_h), + using var px = _testImg.GetPixels(); + ForEach( + Create(0, (int)_h), range => { for (var (y, to) = range; y < to; y++) for (var x = 0; x < _w; x++) { @@ -109,7 +115,7 @@ public void ParGetValueSetPixel() { [Benchmark(Baseline = true)] public void GetValuesSetPixels() { - using var px = _testImg!.GetPixels(); + using var px = _testImg.GetPixels(); var v = px.GetValues()!; for (var i = 0; i < v.Length; i += _ch) MockMap(ref v[i], ref v[i + 1], ref v[i + 2]); px.SetPixels(v); @@ -117,10 +123,10 @@ public void GetValuesSetPixels() { [Benchmark] public void ParGetValuesSetPixels() { - using var px = _testImg!.GetPixels(); + using var px = _testImg.GetPixels(); var v = px.GetValues()!; - Parallel.ForEach( - Partitioner.Create(0, (int)(_w * _h)), + ForEach( + Create(0, (int)(_w * _h)), range => { for (var (i, to) = range; i < to; i++) { var j = i * _ch; @@ -132,7 +138,7 @@ public void ParGetValuesSetPixels() { [Benchmark] public void GetAreaSetPixels() { - using var px = _testImg!.GetPixels(); + using var px = _testImg.GetPixels(); var v = px.GetArea(0, 0, _w, _h)!; for (var i = 0; i < v.Length; i += _ch) MockMap(ref v[i], ref v[i + 1], ref v[i + 2]); px.SetPixels(v); @@ -140,10 +146,10 @@ public void GetAreaSetPixels() { [Benchmark] public void ParGetAreaSetPixels() { - using var px = _testImg!.GetPixels(); + using var px = _testImg.GetPixels(); var v = px.GetArea(0, 0, _w, _h)!; - Parallel.ForEach( - Partitioner.Create(0, (int)(_w * _h)), + ForEach( + Create(0, (int)(_w * _h)), range => { for (var (i, to) = range; i < to; i++) { var j = i * _ch; @@ -155,7 +161,7 @@ public void ParGetAreaSetPixels() { [Benchmark] public void ToArraySetPixels() { - using var px = _testImg!.GetPixels(); + using var px = _testImg.GetPixels(); var v = px.ToArray()!; for (var i = 0; i < v.Length; i += _ch) MockMap(ref v[i], ref v[i + 1], ref v[i + 2]); px.SetPixels(v); @@ -163,10 +169,10 @@ public void ToArraySetPixels() { [Benchmark] public void ParToArraySetPixels() { - using var px = _testImg!.GetPixels(); + using var px = _testImg.GetPixels(); var v = px.ToArray()!; - Parallel.ForEach( - Partitioner.Create(0, (int)(_w * _h)), + ForEach( + Create(0, (int)(_w * _h)), range => { for (var (i, to) = range; i < to; i++) { var j = i * _ch; @@ -178,7 +184,7 @@ public void ParToArraySetPixels() { [Benchmark] public unsafe void AreaPointerUnsafe() { - using var px = _testImg!.GetPixelsUnsafe(); + using var px = _testImg.GetPixelsUnsafe(); var ptr = (ushort*)px.GetAreaPointer(0, 0, _w, _h); var lim = ptr + _w * _h * _ch; for (var p = ptr; p < lim; p += _ch) MockMap(ref p[0], ref p[1], ref p[2]); @@ -186,10 +192,10 @@ public unsafe void AreaPointerUnsafe() { [Benchmark] public unsafe void ParAreaPointerUnsafe() { - using var px = _testImg!.GetPixelsUnsafe(); + using var px = _testImg.GetPixelsUnsafe(); var ptr = (ushort*)px.GetAreaPointer(0, 0, _w, _h); - Parallel.ForEach( - Partitioner.Create(0, (int)(_w * _h)), + ForEach( + Create(0, (int)(_w * _h)), range => { var (i, to) = range; var p = ptr + i * _ch; @@ -197,11 +203,4 @@ public unsafe void ParAreaPointerUnsafe() { for (; p < lim; p += _ch) MockMap(ref p[0], ref p[1], ref p[2]); }); } - - private static void MockMap(ref ushort r, ref ushort g, ref ushort b) { - double x = r / 65535d, y = g / 65535d, z = b / 65535d; - r = (ushort)Math.Round(Math.Pow(Math.Clamp(y + z - x, 0, 1), 1.5) * 65535); - g = (ushort)Math.Round(Math.Pow(Math.Clamp(x + z - y, 0, 1), 1.5) * 65535); - b = (ushort)Math.Round(Math.Pow(Math.Clamp(x + y - z, 0, 1), 1.5) * 65535); - } } diff --git a/GarthImgLab.Benchmarks/Data/RGB16.tif b/GarthImgLab.Benchmarks/Data/RGB16.tif new file mode 100644 index 0000000..eca4eb8 Binary files /dev/null and b/GarthImgLab.Benchmarks/Data/RGB16.tif differ diff --git a/GarthImgLab.Benchmarks/Data/lena_std.tif b/GarthImgLab.Benchmarks/Data/RGB8.tif similarity index 100% rename from GarthImgLab.Benchmarks/Data/lena_std.tif rename to GarthImgLab.Benchmarks/Data/RGB8.tif diff --git a/GarthImgLab.Benchmarks/GarthImgLab.Benchmarks.csproj b/GarthImgLab.Benchmarks/GarthImgLab.Benchmarks.csproj index 4479143..75f699a 100644 --- a/GarthImgLab.Benchmarks/GarthImgLab.Benchmarks.csproj +++ b/GarthImgLab.Benchmarks/GarthImgLab.Benchmarks.csproj @@ -11,7 +11,8 @@ - + + diff --git a/GarthImgLab.Benchmarks/Helper.cs b/GarthImgLab.Benchmarks/Helper.cs new file mode 100644 index 0000000..7d14c5c --- /dev/null +++ b/GarthImgLab.Benchmarks/Helper.cs @@ -0,0 +1,12 @@ +namespace GarthImgLab.Benchmarks; + +public static class Helper { + public static void MockMap(ref ushort r, ref ushort g, ref ushort b) { + ushort r0 = r, g0 = g, b0 = b; + unchecked { + r = (ushort)(g0 * 31 + 1); + g = (ushort)(b0 * 37 + 3); + b = (ushort)(r0 * 41 + 5); + } + } +} diff --git a/GarthImgLab.Benchmarks/PixelParallelTuning.cs b/GarthImgLab.Benchmarks/PixelParallelTuning.cs index a8aa19a..63d59aa 100644 --- a/GarthImgLab.Benchmarks/PixelParallelTuning.cs +++ b/GarthImgLab.Benchmarks/PixelParallelTuning.cs @@ -1,25 +1,25 @@ +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global + namespace GarthImgLab.Benchmarks; -using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using ImageMagick; +using static System.Collections.Concurrent.Partitioner; +using static Helper; +using static Parallel; [MemoryDiagnoser, SuppressMessage("ReSharper", "ClassCanBeSealed.Global")] -public class PixelParallelTuning: IDisposable { +public class PixelParallelTuning { private int _ch; - private MagickImage? _oriImg; - private IMagickImage? _testImg; + private MagickImage _oriImg = new(); + private IMagickImage _testImg = new MagickImage(); private uint _w, _h; - - public void Dispose() { - _oriImg?.Dispose(); - _testImg?.Dispose(); - GC.SuppressFinalize(this); - } + [Params("RGB8.tif", "RGB16.tif")] public string FileName { get; set; } = "RGB8.tif"; [GlobalSetup] public void GlobalSetup() { - _oriImg = new(Path.Combine(AppContext.BaseDirectory, "lena_std.tif")); + _oriImg = new(Path.Combine(AppContext.BaseDirectory, FileName)); _w = _oriImg.Width; _h = _oriImg.Height; _ch = (int)_oriImg.ChannelCount; @@ -27,38 +27,44 @@ public void GlobalSetup() { if (!Test()) throw new InvalidOperationException("结果不一致"); } + [GlobalCleanup] + public void Cleanup() { + _oriImg.Dispose(); + _testImg.Dispose(); + } + private bool Test() { Sequential(); - var expected = _testImg!.Signature; - + var expected = _testImg.Signature; _testImg.Dispose(); - _testImg = _oriImg!.CloneArea(_w, _h); + _testImg = _oriImg.CloneArea(_w, _h); + ForPixel(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + ForEachPixelPartition(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + ForLine(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + ForEachLinePartition(); if (_testImg.Signature != expected) return false; - _testImg.Dispose(); _testImg = _oriImg.CloneArea(_w, _h); + return true; } [Benchmark(Baseline = true)] public unsafe void Sequential() { - using var px = _testImg!.GetPixelsUnsafe(); + using var px = _testImg.GetPixelsUnsafe(); var ptr = (ushort*)px.GetAreaPointer(0, 0, _w, _h); var lim = ptr + _w * _h * _ch; for (var p = ptr; p < lim; p += _ch) MockMap(ref p[0], ref p[1], ref p[2]); @@ -66,9 +72,9 @@ public unsafe void Sequential() { [Benchmark] public unsafe void ForPixel() { - using var px = _testImg!.GetPixelsUnsafe(); + using var px = _testImg.GetPixelsUnsafe(); var ptr = (ushort*)px.GetAreaPointer(0, 0, _w, _h); - Parallel.For( + For( 0, (int)(_w * _h), i => { @@ -79,10 +85,10 @@ public unsafe void ForPixel() { [Benchmark] public unsafe void ForEachPixelPartition() { - using var px = _testImg!.GetPixelsUnsafe(); + using var px = _testImg.GetPixelsUnsafe(); var ptr = (ushort*)px.GetAreaPointer(0, 0, _w, _h); - Parallel.ForEach( - Partitioner.Create(0, (int)(_w * _h)), + ForEach( + Create(0, (int)(_w * _h)), range => { var (i, to) = range; var p = ptr + i * _ch; @@ -93,9 +99,9 @@ public unsafe void ForEachPixelPartition() { [Benchmark] public unsafe void ForLine() { - using var px = _testImg!.GetPixelsUnsafe(); + using var px = _testImg.GetPixelsUnsafe(); var ptr = (ushort*)px.GetAreaPointer(0, 0, _w, _h); - Parallel.For( + For( 0, (int)_h, y => { @@ -107,10 +113,10 @@ public unsafe void ForLine() { [Benchmark] public unsafe void ForEachLinePartition() { - using var px = _testImg!.GetPixelsUnsafe(); + using var px = _testImg.GetPixelsUnsafe(); var ptr = (ushort*)px.GetAreaPointer(0, 0, _w, _h); - Parallel.ForEach( - Partitioner.Create(0, (int)_h), + ForEach( + Create(0, (int)_h), range => { var (y, to) = range; var p = ptr + y * _w * _ch; @@ -118,11 +124,4 @@ public unsafe void ForEachLinePartition() { for (; p < lim; p += _ch) MockMap(ref p[0], ref p[1], ref p[2]); }); } - - private static void MockMap(ref ushort r, ref ushort g, ref ushort b) { - double x = r / 65535d, y = g / 65535d, z = b / 65535d; - r = (ushort)Math.Round(Math.Pow(Math.Clamp(y + z - x, 0, 1), 1.5) * 65535); - g = (ushort)Math.Round(Math.Pow(Math.Clamp(x + z - y, 0, 1), 1.5) * 65535); - b = (ushort)Math.Round(Math.Pow(Math.Clamp(x + y - z, 0, 1), 1.5) * 65535); - } } diff --git a/GarthImgLab.Benchmarks/Program.cs b/GarthImgLab.Benchmarks/Program.cs index 3f069ea..e5236df 100644 --- a/GarthImgLab.Benchmarks/Program.cs +++ b/GarthImgLab.Benchmarks/Program.cs @@ -1,4 +1,6 @@ using BenchmarkDotNet.Running; using GarthImgLab.Benchmarks; +BenchmarkRunner.Run(); +BenchmarkRunner.Run(); BenchmarkRunner.Run(); diff --git a/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.ApplyPerPixel-report-github.md b/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.ApplyPerPixel-report-github.md index e979196..4df4563 100644 --- a/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.ApplyPerPixel-report-github.md +++ b/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.ApplyPerPixel-report-github.md @@ -1,21 +1,32 @@ ``` BenchmarkDotNet v0.16.0-preview.1, Windows 11 (10.0.26200.8737/25H2/2025Update/HudsonValley2) 12th Gen Intel Core i5-12500H 2.50GHz, 1 CPU, 16 logical and 12 physical cores -Memory: 15.69 GB Total, 5.13 GB Available +Memory: 15.69 GB Total, 5.39 GB Available .NET SDK 10.0.301 [Host] : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3 DefaultJob : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3 ``` -| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio | -|-----------------------|-------------:|-------------:|-------------:|-------------:|------:|--------:|---------:|---------:|---------:|----------:|------------:| -| GetValueSetPixel | 112,044.9 μs | 395.94 μs | 370.37 μs | 112,040.6 μs | 28.20 | 0.21 | 800.0000 | - | - | 8388672 B | 5.332 | -| ParGetValueSetPixel | 332,991.2 μs | 11,863.09 μs | 34,978.60 μs | 330,806.3 μs | 83.80 | 8.78 | - | - | - | 8398496 B | 5.338 | -| GetValuesSetPixels | 3,973.7 μs | 30.56 μs | 27.09 μs | 3,972.5 μs | 1.00 | 0.00 | 492.1875 | 492.1875 | 492.1875 | 1573259 B | 1.000 | -| ParGetValuesSetPixels | 1,400.9 μs | 6.49 μs | 5.42 μs | 1,400.8 μs | 0.35 | 0.00 | 498.0469 | 498.0469 | 498.0469 | 1579222 B | 1.004 | -| GetAreaSetPixels | 4,052.5 μs | 12.36 μs | 10.96 μs | 4,051.2 μs | 1.02 | 0.01 | 492.1875 | 492.1875 | 492.1875 | 1573259 B | 1.000 | -| ParGetAreaSetPixels | 1,468.8 μs | 27.54 μs | 22.99 μs | 1,475.2 μs | 0.37 | 0.01 | 498.0469 | 498.0469 | 498.0469 | 1579129 B | 1.004 | -| ToArraySetPixels | 4,062.7 μs | 14.75 μs | 12.32 μs | 4,062.8 μs | 1.02 | 0.01 | 492.1875 | 492.1875 | 492.1875 | 1573259 B | 1.000 | -| ParToArraySetPixels | 1,609.3 μs | 31.73 μs | 71.63 μs | 1,634.4 μs | 0.40 | 0.02 | 498.0469 | 498.0469 | 498.0469 | 1578984 B | 1.004 | -| AreaPointerUnsafe | 3,454.9 μs | 23.35 μs | 21.84 μs | 3,459.1 μs | 0.87 | 0.01 | - | - | - | 64 B | 0.000 | -| ParAreaPointerUnsafe | 909.7 μs | 18.16 μs | 46.55 μs | 920.6 μs | 0.23 | 0.01 | - | - | - | 7509 B | 0.005 | +| Method | FileName | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio | +|-----------------------|---------------|------------------:|---------------:|---------------:|------------------:|-----------:|---------:|-------------:|---------:|---------:|--------------:|------------:| +| **GetValueSetPixel** | **RGB16.tif** | **111,417.29 μs** | **329.320 μs** | **308.047 μs** | **111,309.94 μs** | **127.28** | **1.26** | **800.0000** | **-** | **-** | **8388672 B** | **5.332** | +| ParGetValueSetPixel | RGB16.tif | 368,274.57 μs | 11,774.048 μs | 34,716.049 μs | 371,576.60 μs | 420.69 | 39.68 | - | - | - | 8399536 B | 5.339 | +| GetValuesSetPixels | RGB16.tif | 875.48 μs | 9.164 μs | 8.572 μs | 878.53 μs | 1.00 | 0.00 | 499.0234 | 499.0234 | 499.0234 | 1573263 B | 1.000 | +| ParGetValuesSetPixels | RGB16.tif | 680.78 μs | 4.161 μs | 3.893 μs | 680.61 μs | 0.78 | 0.01 | 499.0234 | 499.0234 | 499.0234 | 1577427 B | 1.003 | +| GetAreaSetPixels | RGB16.tif | 871.59 μs | 15.173 μs | 14.193 μs | 873.49 μs | 1.00 | 0.02 | 499.0234 | 499.0234 | 499.0234 | 1573263 B | 1.000 | +| ParGetAreaSetPixels | RGB16.tif | 754.39 μs | 14.980 μs | 30.261 μs | 763.08 μs | 0.86 | 0.04 | 499.0234 | 499.0234 | 499.0234 | 1577406 B | 1.003 | +| ToArraySetPixels | RGB16.tif | 863.14 μs | 10.088 μs | 9.437 μs | 862.81 μs | 0.99 | 0.01 | 499.0234 | 499.0234 | 499.0234 | 1573263 B | 1.000 | +| ParToArraySetPixels | RGB16.tif | 749.15 μs | 14.947 μs | 34.937 μs | 761.89 μs | 0.86 | 0.04 | 499.0234 | 499.0234 | 499.0234 | 1576986 B | 1.002 | +| AreaPointerUnsafe | RGB16.tif | 220.79 μs | 2.931 μs | 2.879 μs | 220.08 μs | 0.25 | 0.00 | - | - | - | 64 B | 0.000 | +| ParAreaPointerUnsafe | RGB16.tif | 79.13 μs | 1.565 μs | 3.751 μs | 79.46 μs | 0.09 | 0.00 | 0.7324 | - | - | 7286 B | 0.005 | +| | | | | | | | | | | | | | +| **GetValueSetPixel** | **RGB8.tif** | **112,361.46 μs** | **604.548 μs** | **565.495 μs** | **112,388.70 μs** | **130.17** | **1.32** | **800.0000** | **-** | **-** | **8388672 B** | **5.332** | +| ParGetValueSetPixel | RGB8.tif | 375,165.17 μs | 12,354.386 μs | 36,427.190 μs | 376,175.30 μs | 434.63 | 42.18 | - | - | - | 8399904 B | 5.339 | +| GetValuesSetPixels | RGB8.tif | 863.24 μs | 8.938 μs | 7.924 μs | 863.17 μs | 1.00 | 0.00 | 499.0234 | 499.0234 | 499.0234 | 1573263 B | 1.000 | +| ParGetValuesSetPixels | RGB8.tif | 672.06 μs | 2.407 μs | 2.010 μs | 671.69 μs | 0.78 | 0.01 | 499.0234 | 499.0234 | 499.0234 | 1577406 B | 1.003 | +| GetAreaSetPixels | RGB8.tif | 864.50 μs | 8.841 μs | 7.838 μs | 866.94 μs | 1.00 | 0.01 | 499.0234 | 499.0234 | 499.0234 | 1573263 B | 1.000 | +| ParGetAreaSetPixels | RGB8.tif | 674.87 μs | 3.249 μs | 3.039 μs | 674.96 μs | 0.78 | 0.01 | 499.0234 | 499.0234 | 499.0234 | 1577395 B | 1.003 | +| ToArraySetPixels | RGB8.tif | 868.39 μs | 11.107 μs | 10.389 μs | 866.47 μs | 1.01 | 0.01 | 499.0234 | 499.0234 | 499.0234 | 1573263 B | 1.000 | +| ParToArraySetPixels | RGB8.tif | 670.26 μs | 5.924 μs | 5.252 μs | 670.00 μs | 0.78 | 0.01 | 499.0234 | 499.0234 | 499.0234 | 1577406 B | 1.003 | +| AreaPointerUnsafe | RGB8.tif | 219.90 μs | 1.931 μs | 1.806 μs | 219.54 μs | 0.25 | 0.00 | - | - | - | 64 B | 0.000 | +| ParAreaPointerUnsafe | RGB8.tif | 76.09 μs | 1.496 μs | 3.056 μs | 76.71 μs | 0.09 | 0.00 | 0.7324 | - | - | 7152 B | 0.005 | diff --git a/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.ApplyPerPixel-report.html b/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.ApplyPerPixel-report.html new file mode 100644 index 0000000..ee953e9 --- /dev/null +++ b/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.ApplyPerPixel-report.html @@ -0,0 +1,347 @@ + + + + + GarthImgLab.Benchmarks.ApplyPerPixel-20260711-155028 + + + + +

+BenchmarkDotNet v0.16.0-preview.1, Windows 11 (10.0.26200.8737/25H2/2025Update/HudsonValley2)
+12th Gen Intel Core i5-12500H 2.50GHz, 1 CPU, 16 logical and 12 physical cores
+Memory: 15.69 GB Total, 5.39 GB Available
+.NET SDK 10.0.301
+  [Host]     : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3
+  DefaultJob : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodFileNameMeanErrorStdDevMedianRatioRatioSDGen0Gen1Gen2AllocatedAlloc Ratio
GetValueSetPixelRGB16.tif111,417.29 μs329.320 μs308.047 μs111,309.94 μs127.281.26800.0000--8388672 B5.332
ParGetValueSetPixelRGB16.tif368,274.57 μs11,774.048 μs34,716.049 μs371,576.60 μs420.6939.68---8399536 B5.339
GetValuesSetPixelsRGB16.tif875.48 μs9.164 μs8.572 μs878.53 μs1.000.00499.0234499.0234499.02341573263 B1.000
ParGetValuesSetPixelsRGB16.tif680.78 μs4.161 μs3.893 μs680.61 μs0.780.01499.0234499.0234499.02341577427 B1.003
GetAreaSetPixelsRGB16.tif871.59 μs15.173 μs14.193 μs873.49 μs1.000.02499.0234499.0234499.02341573263 B1.000
ParGetAreaSetPixelsRGB16.tif754.39 μs14.980 μs30.261 μs763.08 μs0.860.04499.0234499.0234499.02341577406 B1.003
ToArraySetPixelsRGB16.tif863.14 μs10.088 μs9.437 μs862.81 μs0.990.01499.0234499.0234499.02341573263 B1.000
ParToArraySetPixelsRGB16.tif749.15 μs14.947 μs34.937 μs761.89 μs0.860.04499.0234499.0234499.02341576986 B1.002
AreaPointerUnsafeRGB16.tif220.79 μs2.931 μs2.879 μs220.08 μs0.250.00---64 B0.000
ParAreaPointerUnsafeRGB16.tif79.13 μs1.565 μs3.751 μs79.46 μs0.090.000.7324--7286 B0.005
GetValueSetPixelRGB8.tif112,361.46 μs604.548 μs565.495 μs112,388.70 μs130.171.32800.0000--8388672 B5.332
ParGetValueSetPixelRGB8.tif375,165.17 μs12,354.386 μs36,427.190 μs376,175.30 μs434.6342.18---8399904 B5.339
GetValuesSetPixelsRGB8.tif863.24 μs8.938 μs7.924 μs863.17 μs1.000.00499.0234499.0234499.02341573263 B1.000
ParGetValuesSetPixelsRGB8.tif672.06 μs2.407 μs2.010 μs671.69 μs0.780.01499.0234499.0234499.02341577406 B1.003
GetAreaSetPixelsRGB8.tif864.50 μs8.841 μs7.838 μs866.94 μs1.000.01499.0234499.0234499.02341573263 B1.000
ParGetAreaSetPixelsRGB8.tif674.87 μs3.249 μs3.039 μs674.96 μs0.780.01499.0234499.0234499.02341577395 B1.003
ToArraySetPixelsRGB8.tif868.39 μs11.107 μs10.389 μs866.47 μs1.010.01499.0234499.0234499.02341573263 B1.000
ParToArraySetPixelsRGB8.tif670.26 μs5.924 μs5.252 μs670.00 μs0.780.01499.0234499.0234499.02341577406 B1.003
AreaPointerUnsafeRGB8.tif219.90 μs1.931 μs1.806 μs219.54 μs0.250.00---64 B0.000
ParAreaPointerUnsafeRGB8.tif76.09 μs1.496 μs3.056 μs76.71 μs0.090.000.7324--7152 B0.005
+ + diff --git a/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.PixelParallelTuning-report-github.md b/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.PixelParallelTuning-report-github.md index a5df309..74ec873 100644 --- a/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.PixelParallelTuning-report-github.md +++ b/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.PixelParallelTuning-report-github.md @@ -1,16 +1,22 @@ ``` BenchmarkDotNet v0.16.0-preview.1, Windows 11 (10.0.26200.8737/25H2/2025Update/HudsonValley2) 12th Gen Intel Core i5-12500H 2.50GHz, 1 CPU, 16 logical and 12 physical cores -Memory: 15.69 GB Total, 5.13 GB Available +Memory: 15.69 GB Total, 5.39 GB Available .NET SDK 10.0.301 [Host] : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3 DefaultJob : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3 ``` -| Method | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio | -|-----------------------|-----------:|---------:|---------:|------:|--------:|----------:|------------:| -| Sequential | 3,406.1 μs | 29.96 μs | 25.02 μs | 1.00 | 0.00 | 64 B | 1.00 | -| ForPixel | 828.3 μs | 22.41 μs | 65.39 μs | 0.24 | 0.02 | 4870 B | 76.09 | -| ForEachPixelPartition | 909.4 μs | 6.65 μs | 5.56 μs | 0.27 | 0.00 | 7282 B | 113.78 | -| ForLine | 957.9 μs | 5.67 μs | 5.03 μs | 0.28 | 0.00 | 4852 B | 75.81 | -| ForEachLinePartition | 904.1 μs | 9.11 μs | 8.53 μs | 0.27 | 0.00 | 7521 B | 117.52 | +| Method | FileName | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio | +|-----------------------|---------------|--------------:|-------------:|-------------:|--------------:|---------:|---------:|-------:|----------:|------------:| +| **Sequential** | **RGB16.tif** | **222.79 μs** | **2.880 μs** | **2.694 μs** | **223.22 μs** | **1.00** | **0.00** | **-** | **64 B** | **1.00** | +| ForPixel | RGB16.tif | 164.55 μs | 3.279 μs | 8.696 μs | 165.31 μs | 0.74 | 0.04 | 0.4883 | 4861 B | 75.95 | +| ForEachPixelPartition | RGB16.tif | 82.27 μs | 1.608 μs | 1.652 μs | 81.61 μs | 0.37 | 0.01 | 0.7324 | 7143 B | 111.61 | +| ForLine | RGB16.tif | 81.63 μs | 1.404 μs | 1.172 μs | 81.39 μs | 0.37 | 0.01 | 0.3662 | 3807 B | 59.48 | +| ForEachLinePartition | RGB16.tif | 82.29 μs | 1.280 μs | 1.069 μs | 82.59 μs | 0.37 | 0.01 | 0.7324 | 7528 B | 117.62 | +| | | | | | | | | | | | +| **Sequential** | **RGB8.tif** | **228.35 μs** | **1.631 μs** | **1.526 μs** | **228.56 μs** | **1.00** | **0.00** | **-** | **64 B** | **1.00** | +| ForPixel | RGB8.tif | 161.91 μs | 3.821 μs | 11.086 μs | 165.96 μs | 0.71 | 0.05 | 0.4883 | 4857 B | 75.89 | +| ForEachPixelPartition | RGB8.tif | 79.97 μs | 0.743 μs | 0.695 μs | 79.95 μs | 0.35 | 0.00 | 0.7324 | 7402 B | 115.66 | +| ForLine | RGB8.tif | 83.51 μs | 1.125 μs | 0.997 μs | 83.28 μs | 0.37 | 0.00 | 0.3662 | 3825 B | 59.77 | +| ForEachLinePartition | RGB8.tif | 79.16 μs | 1.133 μs | 0.946 μs | 78.93 μs | 0.35 | 0.00 | 0.7324 | 7258 B | 113.41 | diff --git a/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.PixelParallelTuning-report.html b/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.PixelParallelTuning-report.html new file mode 100644 index 0000000..2d05d2c --- /dev/null +++ b/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.PixelParallelTuning-report.html @@ -0,0 +1,175 @@ + + + + + GarthImgLab.Benchmarks.PixelParallelTuning-20260711-160351 + + + + +

+BenchmarkDotNet v0.16.0-preview.1, Windows 11 (10.0.26200.8737/25H2/2025Update/HudsonValley2)
+12th Gen Intel Core i5-12500H 2.50GHz, 1 CPU, 16 logical and 12 physical cores
+Memory: 15.69 GB Total, 5.39 GB Available
+.NET SDK 10.0.301
+  [Host]     : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3
+  DefaultJob : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodFileNameMeanErrorStdDevMedianRatioRatioSDGen0AllocatedAlloc Ratio
SequentialRGB16.tif222.79 μs2.880 μs2.694 μs223.22 μs1.000.00-64 B1.00
ForPixelRGB16.tif164.55 μs3.279 μs8.696 μs165.31 μs0.740.040.48834861 B75.95
ForEachPixelPartitionRGB16.tif82.27 μs1.608 μs1.652 μs81.61 μs0.370.010.73247143 B111.61
ForLineRGB16.tif81.63 μs1.404 μs1.172 μs81.39 μs0.370.010.36623807 B59.48
ForEachLinePartitionRGB16.tif82.29 μs1.280 μs1.069 μs82.59 μs0.370.010.73247528 B117.62
SequentialRGB8.tif228.35 μs1.631 μs1.526 μs228.56 μs1.000.00-64 B1.00
ForPixelRGB8.tif161.91 μs3.821 μs11.086 μs165.96 μs0.710.050.48834857 B75.89
ForEachPixelPartitionRGB8.tif79.97 μs0.743 μs0.695 μs79.95 μs0.350.000.73247402 B115.66
ForLineRGB8.tif83.51 μs1.125 μs0.997 μs83.28 μs0.370.000.36623825 B59.77
ForEachLinePartitionRGB8.tif79.16 μs1.133 μs0.946 μs78.93 μs0.350.000.73247258 B113.41
+ + diff --git a/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.RoundCorner-report-github.md b/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.RoundCorner-report-github.md index 46ecc1e..cae6d0b 100644 --- a/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.RoundCorner-report-github.md +++ b/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.RoundCorner-report-github.md @@ -1,73 +1,136 @@ ``` BenchmarkDotNet v0.16.0-preview.1, Windows 11 (10.0.26200.8737/25H2/2025Update/HudsonValley2) 12th Gen Intel Core i5-12500H 2.50GHz, 1 CPU, 16 logical and 12 physical cores -Memory: 15.69 GB Total, 5.14 GB Available +Memory: 15.69 GB Total, 5.39 GB Available .NET SDK 10.0.301 [Host] : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3 DefaultJob : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3 ``` -| Method | Hex | Radius | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio | -|------------------------|-----------|---------|--------------:|--------------:|--------------:|---------:|---------:|-------------:|------------:| -| **WriteMaskComposite** | **#0F00** | **0** | **13.059 ms** | **0.0488 ms** | **0.0433 ms** | **1.00** | **0.00** | **11.41 KB** | **1.00** | -| WriteMaskTexture1 | #0F00 | 0 | 1,134.226 ms | 8.9006 ms | 7.8902 ms | 86.85 | 0.65 | 11.35 KB | 0.99 | -| WriteMaskTexture64 | #0F00 | 0 | 13.514 ms | 0.0743 ms | 0.0695 ms | 1.03 | 0.01 | 11.28 KB | 0.99 | -| WriteMaskTextureFull | #0F00 | 0 | 12.959 ms | 0.0435 ms | 0.0386 ms | 0.99 | 0.00 | 11.35 KB | 0.99 | -| CompositeCorners1 | #0F00 | 0 | 18.814 ms | 0.0959 ms | 0.0749 ms | 1.44 | 0.01 | 11.48 KB | 1.01 | -| CompositeCorners2 | #0F00 | 0 | 8.046 ms | 0.0669 ms | 0.0593 ms | 0.62 | 0.00 | 6.04 KB | 0.53 | -| | | | | | | | | | | -| **WriteMaskComposite** | **#0F00** | **0.2** | **35.684 ms** | **0.1933 ms** | **0.1808 ms** | **1.00** | **0.00** | **11.41 KB** | **1.00** | -| WriteMaskTexture1 | #0F00 | 0.2 | 2,433.169 ms | 10.9918 ms | 9.7440 ms | 68.19 | 0.43 | 11.35 KB | 0.99 | -| WriteMaskTexture64 | #0F00 | 0.2 | 52.432 ms | 0.3662 ms | 0.3058 ms | 1.47 | 0.01 | 11.28 KB | 0.99 | -| WriteMaskTextureFull | #0F00 | 0.2 | 35.924 ms | 0.1400 ms | 0.1310 ms | 1.01 | 0.01 | 11.35 KB | 0.99 | -| CompositeCorners1 | #0F00 | 0.2 | 39.451 ms | 0.2025 ms | 0.1894 ms | 1.11 | 0.01 | 11.48 KB | 1.01 | -| CompositeCorners2 | #0F00 | 0.2 | 29.019 ms | 0.2316 ms | 0.2166 ms | 0.81 | 0.01 | 6.04 KB | 0.53 | -| | | | | | | | | | | -| **WriteMaskComposite** | **#0F00** | **0.4** | **46.168 ms** | **0.6442 ms** | **0.5711 ms** | **1.00** | **0.00** | **11.41 KB** | **1.00** | -| WriteMaskTexture1 | #0F00 | 0.4 | 2,332.989 ms | 20.0941 ms | 16.7795 ms | 50.54 | 0.70 | 11.35 KB | 0.99 | -| WriteMaskTexture64 | #0F00 | 0.4 | 60.794 ms | 0.7887 ms | 0.7377 ms | 1.32 | 0.02 | 11.28 KB | 0.99 | -| WriteMaskTextureFull | #0F00 | 0.4 | 44.919 ms | 0.1852 ms | 0.1642 ms | 0.97 | 0.01 | 11.35 KB | 0.99 | -| CompositeCorners1 | #0F00 | 0.4 | 48.343 ms | 0.3496 ms | 0.3270 ms | 1.05 | 0.01 | 11.48 KB | 1.01 | -| CompositeCorners2 | #0F00 | 0.4 | 37.874 ms | 0.2399 ms | 0.2127 ms | 0.82 | 0.01 | 6.04 KB | 0.53 | -| | | | | | | | | | | -| **WriteMaskComposite** | **#0F08** | **0** | **13.157 ms** | **0.0696 ms** | **0.0617 ms** | **1.00** | **0.00** | **11.41 KB** | **1.00** | -| WriteMaskTexture1 | #0F08 | 0 | 1,142.030 ms | 6.9185 ms | 6.4716 ms | 86.80 | 0.62 | 11.35 KB | 0.99 | -| WriteMaskTexture64 | #0F08 | 0 | 13.911 ms | 0.2751 ms | 0.2702 ms | 1.06 | 0.02 | 11.28 KB | 0.99 | -| WriteMaskTextureFull | #0F08 | 0 | 13.426 ms | 0.1073 ms | 0.1003 ms | 1.02 | 0.01 | 11.35 KB | 0.99 | -| CompositeCorners1 | #0F08 | 0 | 19.914 ms | 0.1242 ms | 0.1037 ms | 1.51 | 0.01 | 11.58 KB | 1.01 | -| CompositeCorners2 | #0F08 | 0 | 8.329 ms | 0.0829 ms | 0.0776 ms | 0.63 | 0.01 | 6.14 KB | 0.54 | -| | | | | | | | | | | -| **WriteMaskComposite** | **#0F08** | **0.2** | **35.642 ms** | **0.1709 ms** | **0.1515 ms** | **1.00** | **0.00** | **11.41 KB** | **1.00** | -| WriteMaskTexture1 | #0F08 | 0.2 | 2,445.420 ms | 14.5524 ms | 11.3616 ms | 68.61 | 0.42 | 11.35 KB | 0.99 | -| WriteMaskTexture64 | #0F08 | 0.2 | 52.562 ms | 0.1430 ms | 0.1268 ms | 1.47 | 0.01 | 11.28 KB | 0.99 | -| WriteMaskTextureFull | #0F08 | 0.2 | 35.816 ms | 0.1170 ms | 0.1037 ms | 1.00 | 0.01 | 11.35 KB | 0.99 | -| CompositeCorners1 | #0F08 | 0.2 | 39.709 ms | 0.2199 ms | 0.1836 ms | 1.11 | 0.01 | 11.58 KB | 1.01 | -| CompositeCorners2 | #0F08 | 0.2 | 29.069 ms | 0.1338 ms | 0.1186 ms | 0.82 | 0.00 | 6.14 KB | 0.54 | -| | | | | | | | | | | -| **WriteMaskComposite** | **#0F08** | **0.4** | **44.299 ms** | **0.1795 ms** | **0.1679 ms** | **1.00** | **0.00** | **11.41 KB** | **1.00** | -| WriteMaskTexture1 | #0F08 | 0.4 | 2,333.884 ms | 7.9638 ms | 6.2176 ms | 52.69 | 0.24 | 11.35 KB | 0.99 | -| WriteMaskTexture64 | #0F08 | 0.4 | 60.207 ms | 0.2528 ms | 0.2364 ms | 1.36 | 0.01 | 11.28 KB | 0.99 | -| WriteMaskTextureFull | #0F08 | 0.4 | 44.245 ms | 0.2405 ms | 0.2250 ms | 1.00 | 0.01 | 11.35 KB | 0.99 | -| CompositeCorners1 | #0F08 | 0.4 | 48.896 ms | 0.2736 ms | 0.2426 ms | 1.10 | 0.01 | 11.58 KB | 1.01 | -| CompositeCorners2 | #0F08 | 0.4 | 38.178 ms | 0.2657 ms | 0.2486 ms | 0.86 | 0.01 | 6.14 KB | 0.54 | -| | | | | | | | | | | -| **WriteMaskComposite** | **#0F0F** | **0** | **11.789 ms** | **0.0574 ms** | **0.0509 ms** | **1.00** | **0.00** | **11.31 KB** | **1.00** | -| WriteMaskTexture1 | #0F0F | 0 | 7.336 ms | 0.0437 ms | 0.0365 ms | 0.62 | 0.00 | 11.18 KB | 0.99 | -| WriteMaskTexture64 | #0F0F | 0 | 7.248 ms | 0.0205 ms | 0.0181 ms | 0.61 | 0.00 | 11.18 KB | 0.99 | -| WriteMaskTextureFull | #0F0F | 0 | 8.427 ms | 0.0982 ms | 0.0919 ms | 0.71 | 0.01 | 11.25 KB | 0.99 | -| CompositeCorners1 | #0F0F | 0 | 19.389 ms | 0.1229 ms | 0.1026 ms | 1.64 | 0.01 | 11.48 KB | 1.01 | -| CompositeCorners2 | #0F0F | 0 | 13.128 ms | 0.0567 ms | 0.0530 ms | 1.11 | 0.01 | 6.35 KB | 0.56 | -| | | | | | | | | | | -| **WriteMaskComposite** | **#0F0F** | **0.2** | **34.431 ms** | **0.1045 ms** | **0.0816 ms** | **1.00** | **0.00** | **11.31 KB** | **1.00** | -| WriteMaskTexture1 | #0F0F | 0.2 | 30.073 ms | 0.1451 ms | 0.1358 ms | 0.87 | 0.00 | 11.18 KB | 0.99 | -| WriteMaskTexture64 | #0F0F | 0.2 | 30.026 ms | 0.1351 ms | 0.1263 ms | 0.87 | 0.00 | 11.18 KB | 0.99 | -| WriteMaskTextureFull | #0F0F | 0.2 | 31.037 ms | 0.0938 ms | 0.0832 ms | 0.90 | 0.00 | 11.25 KB | 0.99 | -| CompositeCorners1 | #0F0F | 0.2 | 40.730 ms | 0.4890 ms | 0.4574 ms | 1.18 | 0.01 | 11.48 KB | 1.01 | -| CompositeCorners2 | #0F0F | 0.2 | 33.775 ms | 0.2646 ms | 0.2475 ms | 0.98 | 0.01 | 6.35 KB | 0.56 | -| | | | | | | | | | | -| **WriteMaskComposite** | **#0F0F** | **0.4** | **43.017 ms** | **0.2346 ms** | **0.2194 ms** | **1.00** | **0.00** | **11.31 KB** | **1.00** | -| WriteMaskTexture1 | #0F0F | 0.4 | 38.530 ms | 0.1250 ms | 0.0976 ms | 0.90 | 0.00 | 11.18 KB | 0.99 | -| WriteMaskTexture64 | #0F0F | 0.4 | 38.353 ms | 0.1392 ms | 0.1302 ms | 0.89 | 0.01 | 11.18 KB | 0.99 | -| WriteMaskTextureFull | #0F0F | 0.4 | 39.790 ms | 0.1720 ms | 0.1609 ms | 0.92 | 0.01 | 11.25 KB | 0.99 | -| CompositeCorners1 | #0F0F | 0.4 | 47.720 ms | 0.2891 ms | 0.2414 ms | 1.11 | 0.01 | 11.48 KB | 1.01 | -| CompositeCorners2 | #0F0F | 0.4 | 42.467 ms | 0.1665 ms | 0.1557 ms | 0.99 | 0.01 | 6.35 KB | 0.56 | +| Method | Hex | FileName | Radius | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio | +|------------------------|-----------|---------------|---------|--------------:|--------------:|--------------:|---------:|---------:|-------------:|------------:| +| **WriteMaskComposite** | **#0F00** | **RGB16.tif** | **0** | **13.106 ms** | **0.0679 ms** | **0.0602 ms** | **1.00** | **0.00** | **11.32 KB** | **1.00** | +| WriteMaskTexture1 | #0F00 | RGB16.tif | 0 | 1,166.905 ms | 17.3922 ms | 22.6148 ms | 89.04 | 1.74 | 11.19 KB | 0.99 | +| WriteMaskTexture64 | #0F00 | RGB16.tif | 0 | 13.576 ms | 0.0532 ms | 0.0498 ms | 1.04 | 0.01 | 11.19 KB | 0.99 | +| WriteMaskTextureFull | #0F00 | RGB16.tif | 0 | 13.080 ms | 0.0547 ms | 0.0511 ms | 1.00 | 0.01 | 11.26 KB | 0.99 | +| CompositeCorners1 | #0F00 | RGB16.tif | 0 | 19.055 ms | 0.1133 ms | 0.0946 ms | 1.45 | 0.01 | 11.38 KB | 1.01 | +| CompositeCorners2 | #0F00 | RGB16.tif | 0 | 8.162 ms | 0.0558 ms | 0.0522 ms | 0.62 | 0.00 | 5.95 KB | 0.53 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F00** | **RGB16.tif** | **0.2** | **35.975 ms** | **0.1903 ms** | **0.1589 ms** | **1.00** | **0.00** | **11.32 KB** | **1.00** | +| WriteMaskTexture1 | #0F00 | RGB16.tif | 0.2 | 2,442.011 ms | 12.3003 ms | 11.5057 ms | 67.88 | 0.42 | 11.23 KB | 0.99 | +| WriteMaskTexture64 | #0F00 | RGB16.tif | 0.2 | 52.345 ms | 0.1778 ms | 0.1663 ms | 1.46 | 0.01 | 11.19 KB | 0.99 | +| WriteMaskTextureFull | #0F00 | RGB16.tif | 0.2 | 35.703 ms | 0.1454 ms | 0.1360 ms | 0.99 | 0.01 | 11.26 KB | 0.99 | +| CompositeCorners1 | #0F00 | RGB16.tif | 0.2 | 39.480 ms | 0.3462 ms | 0.3238 ms | 1.10 | 0.01 | 11.38 KB | 1.01 | +| CompositeCorners2 | #0F00 | RGB16.tif | 0.2 | 29.183 ms | 0.1033 ms | 0.0967 ms | 0.81 | 0.00 | 5.95 KB | 0.53 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F00** | **RGB16.tif** | **0.4** | **44.773 ms** | **0.2196 ms** | **0.1834 ms** | **1.00** | **0.00** | **11.32 KB** | **1.00** | +| WriteMaskTexture1 | #0F00 | RGB16.tif | 0.4 | 2,355.335 ms | 30.1365 ms | 28.1897 ms | 52.61 | 0.64 | 11.23 KB | 0.99 | +| WriteMaskTexture64 | #0F00 | RGB16.tif | 0.4 | 59.543 ms | 0.2370 ms | 0.2101 ms | 1.33 | 0.01 | 11.19 KB | 0.99 | +| WriteMaskTextureFull | #0F00 | RGB16.tif | 0.4 | 44.542 ms | 0.3086 ms | 0.2887 ms | 0.99 | 0.01 | 11.26 KB | 0.99 | +| CompositeCorners1 | #0F00 | RGB16.tif | 0.4 | 48.192 ms | 0.2526 ms | 0.2362 ms | 1.08 | 0.01 | 11.38 KB | 1.01 | +| CompositeCorners2 | #0F00 | RGB16.tif | 0.4 | 38.189 ms | 0.2721 ms | 0.2545 ms | 0.85 | 0.01 | 5.95 KB | 0.53 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F00** | **RGB8.tif** | **0** | **12.912 ms** | **0.0402 ms** | **0.0336 ms** | **1.00** | **0.00** | **11.32 KB** | **1.00** | +| WriteMaskTexture1 | #0F00 | RGB8.tif | 0 | 1,152.021 ms | 9.2240 ms | 8.1768 ms | 89.22 | 0.65 | 11.23 KB | 0.99 | +| WriteMaskTexture64 | #0F00 | RGB8.tif | 0 | 13.569 ms | 0.0546 ms | 0.0511 ms | 1.05 | 0.00 | 11.19 KB | 0.99 | +| WriteMaskTextureFull | #0F00 | RGB8.tif | 0 | 13.175 ms | 0.2315 ms | 0.2166 ms | 1.02 | 0.02 | 11.26 KB | 0.99 | +| CompositeCorners1 | #0F00 | RGB8.tif | 0 | 19.002 ms | 0.1044 ms | 0.0925 ms | 1.47 | 0.01 | 11.38 KB | 1.01 | +| CompositeCorners2 | #0F00 | RGB8.tif | 0 | 8.094 ms | 0.0546 ms | 0.0511 ms | 0.63 | 0.00 | 5.95 KB | 0.53 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F00** | **RGB8.tif** | **0.2** | **35.984 ms** | **0.1656 ms** | **0.1468 ms** | **1.00** | **0.00** | **11.32 KB** | **1.00** | +| WriteMaskTexture1 | #0F00 | RGB8.tif | 0.2 | 2,429.569 ms | 18.5342 ms | 17.3369 ms | 67.52 | 0.54 | 11.23 KB | 0.99 | +| WriteMaskTexture64 | #0F00 | RGB8.tif | 0.2 | 52.331 ms | 0.1696 ms | 0.1587 ms | 1.45 | 0.01 | 11.19 KB | 0.99 | +| WriteMaskTextureFull | #0F00 | RGB8.tif | 0.2 | 35.678 ms | 0.1178 ms | 0.0983 ms | 0.99 | 0.00 | 11.26 KB | 0.99 | +| CompositeCorners1 | #0F00 | RGB8.tif | 0.2 | 39.353 ms | 0.1203 ms | 0.1125 ms | 1.09 | 0.01 | 11.38 KB | 1.01 | +| CompositeCorners2 | #0F00 | RGB8.tif | 0.2 | 28.872 ms | 0.1454 ms | 0.1360 ms | 0.80 | 0.00 | 5.95 KB | 0.53 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F00** | **RGB8.tif** | **0.4** | **44.704 ms** | **0.2225 ms** | **0.2081 ms** | **1.00** | **0.00** | **11.32 KB** | **1.00** | +| WriteMaskTexture1 | #0F00 | RGB8.tif | 0.4 | 2,310.413 ms | 10.2402 ms | 9.0777 ms | 51.68 | 0.30 | 11.23 KB | 0.99 | +| WriteMaskTexture64 | #0F00 | RGB8.tif | 0.4 | 59.670 ms | 0.2593 ms | 0.2165 ms | 1.33 | 0.01 | 11.19 KB | 0.99 | +| WriteMaskTextureFull | #0F00 | RGB8.tif | 0.4 | 44.725 ms | 0.1812 ms | 0.1694 ms | 1.00 | 0.01 | 11.26 KB | 0.99 | +| CompositeCorners1 | #0F00 | RGB8.tif | 0.4 | 48.079 ms | 0.1752 ms | 0.1639 ms | 1.08 | 0.01 | 11.38 KB | 1.01 | +| CompositeCorners2 | #0F00 | RGB8.tif | 0.4 | 37.991 ms | 0.4043 ms | 0.3781 ms | 0.85 | 0.01 | 5.95 KB | 0.53 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F08** | **RGB16.tif** | **0** | **13.222 ms** | **0.0859 ms** | **0.0761 ms** | **1.00** | **0.00** | **11.32 KB** | **1.00** | +| WriteMaskTexture1 | #0F08 | RGB16.tif | 0 | 1,158.652 ms | 14.5388 ms | 11.3509 ms | 87.63 | 0.96 | 11.23 KB | 0.99 | +| WriteMaskTexture64 | #0F08 | RGB16.tif | 0 | 13.936 ms | 0.1359 ms | 0.1271 ms | 1.05 | 0.01 | 11.19 KB | 0.99 | +| WriteMaskTextureFull | #0F08 | RGB16.tif | 0 | 13.580 ms | 0.1326 ms | 0.1175 ms | 1.03 | 0.01 | 11.26 KB | 0.99 | +| CompositeCorners1 | #0F08 | RGB16.tif | 0 | 20.354 ms | 0.1501 ms | 0.1254 ms | 1.54 | 0.01 | 11.48 KB | 1.01 | +| CompositeCorners2 | #0F08 | RGB16.tif | 0 | 8.601 ms | 0.0917 ms | 0.0858 ms | 0.65 | 0.01 | 6.05 KB | 0.53 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F08** | **RGB16.tif** | **0.2** | **36.348 ms** | **0.3001 ms** | **0.2661 ms** | **1.00** | **0.00** | **11.32 KB** | **1.00** | +| WriteMaskTexture1 | #0F08 | RGB16.tif | 0.2 | 2,433.761 ms | 9.9367 ms | 8.8086 ms | 66.96 | 0.53 | 11.23 KB | 0.99 | +| WriteMaskTexture64 | #0F08 | RGB16.tif | 0.2 | 52.454 ms | 0.2897 ms | 0.2710 ms | 1.44 | 0.01 | 11.19 KB | 0.99 | +| WriteMaskTextureFull | #0F08 | RGB16.tif | 0.2 | 35.717 ms | 0.1656 ms | 0.1468 ms | 0.98 | 0.01 | 11.26 KB | 0.99 | +| CompositeCorners1 | #0F08 | RGB16.tif | 0.2 | 39.982 ms | 0.3742 ms | 0.3500 ms | 1.10 | 0.01 | 11.48 KB | 1.01 | +| CompositeCorners2 | #0F08 | RGB16.tif | 0.2 | 29.227 ms | 0.1308 ms | 0.1159 ms | 0.80 | 0.01 | 6.05 KB | 0.53 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F08** | **RGB16.tif** | **0.4** | **44.409 ms** | **0.1794 ms** | **0.1590 ms** | **1.00** | **0.00** | **11.32 KB** | **1.00** | +| WriteMaskTexture1 | #0F08 | RGB16.tif | 0.4 | 2,342.014 ms | 13.0168 ms | 18.6683 ms | 52.74 | 0.45 | 11.19 KB | 0.99 | +| WriteMaskTexture64 | #0F08 | RGB16.tif | 0.4 | 59.904 ms | 0.3464 ms | 0.3071 ms | 1.35 | 0.01 | 11.19 KB | 0.99 | +| WriteMaskTextureFull | #0F08 | RGB16.tif | 0.4 | 44.482 ms | 0.2456 ms | 0.2298 ms | 1.00 | 0.01 | 11.26 KB | 0.99 | +| CompositeCorners1 | #0F08 | RGB16.tif | 0.4 | 48.571 ms | 0.2917 ms | 0.2586 ms | 1.09 | 0.01 | 11.48 KB | 1.01 | +| CompositeCorners2 | #0F08 | RGB16.tif | 0.4 | 37.915 ms | 0.2281 ms | 0.1781 ms | 0.85 | 0.00 | 6.05 KB | 0.53 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F08** | **RGB8.tif** | **0** | **13.151 ms** | **0.0796 ms** | **0.0745 ms** | **1.00** | **0.00** | **11.32 KB** | **1.00** | +| WriteMaskTexture1 | #0F08 | RGB8.tif | 0 | 1,126.188 ms | 4.9248 ms | 4.6067 ms | 85.64 | 0.58 | 11.23 KB | 0.99 | +| WriteMaskTexture64 | #0F08 | RGB8.tif | 0 | 13.658 ms | 0.0519 ms | 0.0460 ms | 1.04 | 0.01 | 11.19 KB | 0.99 | +| WriteMaskTextureFull | #0F08 | RGB8.tif | 0 | 13.124 ms | 0.0428 ms | 0.0400 ms | 1.00 | 0.01 | 11.26 KB | 0.99 | +| CompositeCorners1 | #0F08 | RGB8.tif | 0 | 19.992 ms | 0.1013 ms | 0.0846 ms | 1.52 | 0.01 | 11.48 KB | 1.01 | +| CompositeCorners2 | #0F08 | RGB8.tif | 0 | 8.304 ms | 0.0582 ms | 0.0516 ms | 0.63 | 0.01 | 6.05 KB | 0.53 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F08** | **RGB8.tif** | **0.2** | **35.640 ms** | **0.1632 ms** | **0.1363 ms** | **1.00** | **0.00** | **11.32 KB** | **1.00** | +| WriteMaskTexture1 | #0F08 | RGB8.tif | 0.2 | 2,457.115 ms | 34.9035 ms | 30.9410 ms | 68.94 | 0.88 | 11.23 KB | 0.99 | +| WriteMaskTexture64 | #0F08 | RGB8.tif | 0.2 | 52.640 ms | 0.2335 ms | 0.2184 ms | 1.48 | 0.01 | 11.19 KB | 0.99 | +| WriteMaskTextureFull | #0F08 | RGB8.tif | 0.2 | 35.762 ms | 0.2270 ms | 0.2123 ms | 1.00 | 0.01 | 11.26 KB | 0.99 | +| CompositeCorners1 | #0F08 | RGB8.tif | 0.2 | 39.941 ms | 0.2830 ms | 0.2509 ms | 1.12 | 0.01 | 11.48 KB | 1.01 | +| CompositeCorners2 | #0F08 | RGB8.tif | 0.2 | 29.140 ms | 0.1707 ms | 0.1513 ms | 0.82 | 0.01 | 6.05 KB | 0.53 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F08** | **RGB8.tif** | **0.4** | **44.133 ms** | **0.2383 ms** | **0.2229 ms** | **1.00** | **0.00** | **11.32 KB** | **1.00** | +| WriteMaskTexture1 | #0F08 | RGB8.tif | 0.4 | 2,301.307 ms | 13.8778 ms | 10.8349 ms | 52.15 | 0.35 | 11.23 KB | 0.99 | +| WriteMaskTexture64 | #0F08 | RGB8.tif | 0.4 | 59.378 ms | 0.1851 ms | 0.1731 ms | 1.35 | 0.01 | 11.19 KB | 0.99 | +| WriteMaskTextureFull | #0F08 | RGB8.tif | 0.4 | 44.171 ms | 0.1405 ms | 0.1246 ms | 1.00 | 0.01 | 11.26 KB | 0.99 | +| CompositeCorners1 | #0F08 | RGB8.tif | 0.4 | 48.529 ms | 0.1992 ms | 0.1766 ms | 1.10 | 0.01 | 11.48 KB | 1.01 | +| CompositeCorners2 | #0F08 | RGB8.tif | 0.4 | 37.856 ms | 0.2142 ms | 0.1899 ms | 0.86 | 0.01 | 6.05 KB | 0.53 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F0F** | **RGB16.tif** | **0** | **11.889 ms** | **0.0296 ms** | **0.0277 ms** | **1.00** | **0.00** | **11.22 KB** | **1.00** | +| WriteMaskTexture1 | #0F0F | RGB16.tif | 0 | 7.435 ms | 0.0288 ms | 0.0270 ms | 0.63 | 0.00 | 11.09 KB | 0.99 | +| WriteMaskTexture64 | #0F0F | RGB16.tif | 0 | 7.370 ms | 0.0149 ms | 0.0140 ms | 0.62 | 0.00 | 11.09 KB | 0.99 | +| WriteMaskTextureFull | #0F0F | RGB16.tif | 0 | 8.651 ms | 0.0945 ms | 0.0838 ms | 0.73 | 0.01 | 11.16 KB | 0.99 | +| CompositeCorners1 | #0F0F | RGB16.tif | 0 | 19.662 ms | 0.1863 ms | 0.1651 ms | 1.65 | 0.01 | 11.38 KB | 1.01 | +| CompositeCorners2 | #0F0F | RGB16.tif | 0 | 13.170 ms | 0.0766 ms | 0.0717 ms | 1.11 | 0.01 | 6.26 KB | 0.56 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F0F** | **RGB16.tif** | **0.2** | **34.398 ms** | **0.2007 ms** | **0.1567 ms** | **1.00** | **0.00** | **11.22 KB** | **1.00** | +| WriteMaskTexture1 | #0F0F | RGB16.tif | 0.2 | 30.002 ms | 0.1504 ms | 0.1334 ms | 0.87 | 0.01 | 11.09 KB | 0.99 | +| WriteMaskTexture64 | #0F0F | RGB16.tif | 0.2 | 30.076 ms | 0.2156 ms | 0.2017 ms | 0.87 | 0.01 | 11.09 KB | 0.99 | +| WriteMaskTextureFull | #0F0F | RGB16.tif | 0.2 | 31.164 ms | 0.1958 ms | 0.1736 ms | 0.91 | 0.01 | 11.16 KB | 0.99 | +| CompositeCorners1 | #0F0F | RGB16.tif | 0.2 | 39.460 ms | 0.2809 ms | 0.2490 ms | 1.15 | 0.01 | 11.38 KB | 1.01 | +| CompositeCorners2 | #0F0F | RGB16.tif | 0.2 | 34.042 ms | 0.1561 ms | 0.1460 ms | 0.99 | 0.01 | 6.26 KB | 0.56 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F0F** | **RGB16.tif** | **0.4** | **43.542 ms** | **0.1759 ms** | **0.1645 ms** | **1.00** | **0.00** | **11.22 KB** | **1.00** | +| WriteMaskTexture1 | #0F0F | RGB16.tif | 0.4 | 40.048 ms | 0.3809 ms | 0.3376 ms | 0.92 | 0.01 | 11.09 KB | 0.99 | +| WriteMaskTexture64 | #0F0F | RGB16.tif | 0.4 | 38.587 ms | 0.2709 ms | 0.2402 ms | 0.89 | 0.01 | 11.09 KB | 0.99 | +| WriteMaskTextureFull | #0F0F | RGB16.tif | 0.4 | 39.910 ms | 0.3408 ms | 0.3188 ms | 0.92 | 0.01 | 11.16 KB | 0.99 | +| CompositeCorners1 | #0F0F | RGB16.tif | 0.4 | 48.201 ms | 0.3872 ms | 0.3233 ms | 1.11 | 0.01 | 11.38 KB | 1.01 | +| CompositeCorners2 | #0F0F | RGB16.tif | 0.4 | 42.595 ms | 0.3105 ms | 0.2753 ms | 0.98 | 0.01 | 6.26 KB | 0.56 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F0F** | **RGB8.tif** | **0** | **11.929 ms** | **0.0804 ms** | **0.0713 ms** | **1.00** | **0.00** | **11.22 KB** | **1.00** | +| WriteMaskTexture1 | #0F0F | RGB8.tif | 0 | 7.405 ms | 0.0983 ms | 0.0919 ms | 0.62 | 0.01 | 11.09 KB | 0.99 | +| WriteMaskTexture64 | #0F0F | RGB8.tif | 0 | 7.399 ms | 0.0261 ms | 0.0244 ms | 0.62 | 0.00 | 11.09 KB | 0.99 | +| WriteMaskTextureFull | #0F0F | RGB8.tif | 0 | 8.536 ms | 0.1661 ms | 0.1472 ms | 0.72 | 0.01 | 11.16 KB | 0.99 | +| CompositeCorners1 | #0F0F | RGB8.tif | 0 | 19.613 ms | 0.0766 ms | 0.0639 ms | 1.64 | 0.01 | 11.38 KB | 1.01 | +| CompositeCorners2 | #0F0F | RGB8.tif | 0 | 13.280 ms | 0.0901 ms | 0.0843 ms | 1.11 | 0.01 | 6.26 KB | 0.56 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F0F** | **RGB8.tif** | **0.2** | **34.597 ms** | **0.2190 ms** | **0.1941 ms** | **1.00** | **0.00** | **11.22 KB** | **1.00** | +| WriteMaskTexture1 | #0F0F | RGB8.tif | 0.2 | 30.058 ms | 0.1444 ms | 0.1280 ms | 0.87 | 0.01 | 11.09 KB | 0.99 | +| WriteMaskTexture64 | #0F0F | RGB8.tif | 0.2 | 29.875 ms | 0.1148 ms | 0.1018 ms | 0.86 | 0.01 | 11.09 KB | 0.99 | +| WriteMaskTextureFull | #0F0F | RGB8.tif | 0.2 | 31.104 ms | 0.1066 ms | 0.0890 ms | 0.90 | 0.01 | 11.16 KB | 0.99 | +| CompositeCorners1 | #0F0F | RGB8.tif | 0.2 | 39.135 ms | 0.2918 ms | 0.2729 ms | 1.13 | 0.01 | 11.38 KB | 1.01 | +| CompositeCorners2 | #0F0F | RGB8.tif | 0.2 | 33.805 ms | 0.1647 ms | 0.1540 ms | 0.98 | 0.01 | 6.26 KB | 0.56 | +| | | | | | | | | | | | +| **WriteMaskComposite** | **#0F0F** | **RGB8.tif** | **0.4** | **43.553 ms** | **0.4904 ms** | **0.4587 ms** | **1.00** | **0.00** | **11.22 KB** | **1.00** | +| WriteMaskTexture1 | #0F0F | RGB8.tif | 0.4 | 38.614 ms | 0.1566 ms | 0.1464 ms | 0.89 | 0.01 | 11.09 KB | 0.99 | +| WriteMaskTexture64 | #0F0F | RGB8.tif | 0.4 | 38.807 ms | 0.1860 ms | 0.1649 ms | 0.89 | 0.01 | 11.09 KB | 0.99 | +| WriteMaskTextureFull | #0F0F | RGB8.tif | 0.4 | 40.049 ms | 0.2257 ms | 0.2001 ms | 0.92 | 0.01 | 11.16 KB | 0.99 | +| CompositeCorners1 | #0F0F | RGB8.tif | 0.4 | 48.036 ms | 0.2988 ms | 0.2795 ms | 1.10 | 0.01 | 11.38 KB | 1.01 | +| CompositeCorners2 | #0F0F | RGB8.tif | 0.4 | 42.553 ms | 0.1750 ms | 0.1552 ms | 0.98 | 0.01 | 6.26 KB | 0.56 | diff --git a/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.RoundCorner-report.html b/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.RoundCorner-report.html new file mode 100644 index 0000000..75ad19f --- /dev/null +++ b/GarthImgLab.Benchmarks/Results/GarthImgLab.Benchmarks.RoundCorner-report.html @@ -0,0 +1,1449 @@ + + + + + GarthImgLab.Benchmarks.RoundCorner-20260711-160932 + + + + +

+BenchmarkDotNet v0.16.0-preview.1, Windows 11 (10.0.26200.8737/25H2/2025Update/HudsonValley2)
+12th Gen Intel Core i5-12500H 2.50GHz, 1 CPU, 16 logical and 12 physical cores
+Memory: 15.69 GB Total, 5.39 GB Available
+.NET SDK 10.0.301
+  [Host]     : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3
+  DefaultJob : .NET 10.0.9 (10.0.9, 10.0.926.27113), X64 RyuJIT x86-64-v3
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodHexFileNameRadiusMeanErrorStdDevRatioRatioSDAllocatedAlloc Ratio
WriteMaskComposite#0F00RGB16.tif013.106 ms0.0679 ms0.0602 ms1.000.0011.32 KB1.00
WriteMaskTexture1#0F00RGB16.tif01,166.905 ms17.3922 ms22.6148 ms89.041.7411.19 KB0.99
WriteMaskTexture64#0F00RGB16.tif013.576 ms0.0532 ms0.0498 ms1.040.0111.19 KB0.99
WriteMaskTextureFull#0F00RGB16.tif013.080 ms0.0547 ms0.0511 ms1.000.0111.26 KB0.99
CompositeCorners1#0F00RGB16.tif019.055 ms0.1133 ms0.0946 ms1.450.0111.38 KB1.01
CompositeCorners2#0F00RGB16.tif08.162 ms0.0558 ms0.0522 ms0.620.005.95 KB0.53
WriteMaskComposite#0F00RGB16.tif0.235.975 ms0.1903 ms0.1589 ms1.000.0011.32 KB1.00
WriteMaskTexture1#0F00RGB16.tif0.22,442.011 ms12.3003 ms11.5057 ms67.880.4211.23 KB0.99
WriteMaskTexture64#0F00RGB16.tif0.252.345 ms0.1778 ms0.1663 ms1.460.0111.19 KB0.99
WriteMaskTextureFull#0F00RGB16.tif0.235.703 ms0.1454 ms0.1360 ms0.990.0111.26 KB0.99
CompositeCorners1#0F00RGB16.tif0.239.480 ms0.3462 ms0.3238 ms1.100.0111.38 KB1.01
CompositeCorners2#0F00RGB16.tif0.229.183 ms0.1033 ms0.0967 ms0.810.005.95 KB0.53
WriteMaskComposite#0F00RGB16.tif0.444.773 ms0.2196 ms0.1834 ms1.000.0011.32 KB1.00
WriteMaskTexture1#0F00RGB16.tif0.42,355.335 ms30.1365 ms28.1897 ms52.610.6411.23 KB0.99
WriteMaskTexture64#0F00RGB16.tif0.459.543 ms0.2370 ms0.2101 ms1.330.0111.19 KB0.99
WriteMaskTextureFull#0F00RGB16.tif0.444.542 ms0.3086 ms0.2887 ms0.990.0111.26 KB0.99
CompositeCorners1#0F00RGB16.tif0.448.192 ms0.2526 ms0.2362 ms1.080.0111.38 KB1.01
CompositeCorners2#0F00RGB16.tif0.438.189 ms0.2721 ms0.2545 ms0.850.015.95 KB0.53
WriteMaskComposite#0F00RGB8.tif012.912 ms0.0402 ms0.0336 ms1.000.0011.32 KB1.00
WriteMaskTexture1#0F00RGB8.tif01,152.021 ms9.2240 ms8.1768 ms89.220.6511.23 KB0.99
WriteMaskTexture64#0F00RGB8.tif013.569 ms0.0546 ms0.0511 ms1.050.0011.19 KB0.99
WriteMaskTextureFull#0F00RGB8.tif013.175 ms0.2315 ms0.2166 ms1.020.0211.26 KB0.99
CompositeCorners1#0F00RGB8.tif019.002 ms0.1044 ms0.0925 ms1.470.0111.38 KB1.01
CompositeCorners2#0F00RGB8.tif08.094 ms0.0546 ms0.0511 ms0.630.005.95 KB0.53
WriteMaskComposite#0F00RGB8.tif0.235.984 ms0.1656 ms0.1468 ms1.000.0011.32 KB1.00
WriteMaskTexture1#0F00RGB8.tif0.22,429.569 ms18.5342 ms17.3369 ms67.520.5411.23 KB0.99
WriteMaskTexture64#0F00RGB8.tif0.252.331 ms0.1696 ms0.1587 ms1.450.0111.19 KB0.99
WriteMaskTextureFull#0F00RGB8.tif0.235.678 ms0.1178 ms0.0983 ms0.990.0011.26 KB0.99
CompositeCorners1#0F00RGB8.tif0.239.353 ms0.1203 ms0.1125 ms1.090.0111.38 KB1.01
CompositeCorners2#0F00RGB8.tif0.228.872 ms0.1454 ms0.1360 ms0.800.005.95 KB0.53
WriteMaskComposite#0F00RGB8.tif0.444.704 ms0.2225 ms0.2081 ms1.000.0011.32 KB1.00
WriteMaskTexture1#0F00RGB8.tif0.42,310.413 ms10.2402 ms9.0777 ms51.680.3011.23 KB0.99
WriteMaskTexture64#0F00RGB8.tif0.459.670 ms0.2593 ms0.2165 ms1.330.0111.19 KB0.99
WriteMaskTextureFull#0F00RGB8.tif0.444.725 ms0.1812 ms0.1694 ms1.000.0111.26 KB0.99
CompositeCorners1#0F00RGB8.tif0.448.079 ms0.1752 ms0.1639 ms1.080.0111.38 KB1.01
CompositeCorners2#0F00RGB8.tif0.437.991 ms0.4043 ms0.3781 ms0.850.015.95 KB0.53
WriteMaskComposite#0F08RGB16.tif013.222 ms0.0859 ms0.0761 ms1.000.0011.32 KB1.00
WriteMaskTexture1#0F08RGB16.tif01,158.652 ms14.5388 ms11.3509 ms87.630.9611.23 KB0.99
WriteMaskTexture64#0F08RGB16.tif013.936 ms0.1359 ms0.1271 ms1.050.0111.19 KB0.99
WriteMaskTextureFull#0F08RGB16.tif013.580 ms0.1326 ms0.1175 ms1.030.0111.26 KB0.99
CompositeCorners1#0F08RGB16.tif020.354 ms0.1501 ms0.1254 ms1.540.0111.48 KB1.01
CompositeCorners2#0F08RGB16.tif08.601 ms0.0917 ms0.0858 ms0.650.016.05 KB0.53
WriteMaskComposite#0F08RGB16.tif0.236.348 ms0.3001 ms0.2661 ms1.000.0011.32 KB1.00
WriteMaskTexture1#0F08RGB16.tif0.22,433.761 ms9.9367 ms8.8086 ms66.960.5311.23 KB0.99
WriteMaskTexture64#0F08RGB16.tif0.252.454 ms0.2897 ms0.2710 ms1.440.0111.19 KB0.99
WriteMaskTextureFull#0F08RGB16.tif0.235.717 ms0.1656 ms0.1468 ms0.980.0111.26 KB0.99
CompositeCorners1#0F08RGB16.tif0.239.982 ms0.3742 ms0.3500 ms1.100.0111.48 KB1.01
CompositeCorners2#0F08RGB16.tif0.229.227 ms0.1308 ms0.1159 ms0.800.016.05 KB0.53
WriteMaskComposite#0F08RGB16.tif0.444.409 ms0.1794 ms0.1590 ms1.000.0011.32 KB1.00
WriteMaskTexture1#0F08RGB16.tif0.42,342.014 ms13.0168 ms18.6683 ms52.740.4511.19 KB0.99
WriteMaskTexture64#0F08RGB16.tif0.459.904 ms0.3464 ms0.3071 ms1.350.0111.19 KB0.99
WriteMaskTextureFull#0F08RGB16.tif0.444.482 ms0.2456 ms0.2298 ms1.000.0111.26 KB0.99
CompositeCorners1#0F08RGB16.tif0.448.571 ms0.2917 ms0.2586 ms1.090.0111.48 KB1.01
CompositeCorners2#0F08RGB16.tif0.437.915 ms0.2281 ms0.1781 ms0.850.006.05 KB0.53
WriteMaskComposite#0F08RGB8.tif013.151 ms0.0796 ms0.0745 ms1.000.0011.32 KB1.00
WriteMaskTexture1#0F08RGB8.tif01,126.188 ms4.9248 ms4.6067 ms85.640.5811.23 KB0.99
WriteMaskTexture64#0F08RGB8.tif013.658 ms0.0519 ms0.0460 ms1.040.0111.19 KB0.99
WriteMaskTextureFull#0F08RGB8.tif013.124 ms0.0428 ms0.0400 ms1.000.0111.26 KB0.99
CompositeCorners1#0F08RGB8.tif019.992 ms0.1013 ms0.0846 ms1.520.0111.48 KB1.01
CompositeCorners2#0F08RGB8.tif08.304 ms0.0582 ms0.0516 ms0.630.016.05 KB0.53
WriteMaskComposite#0F08RGB8.tif0.235.640 ms0.1632 ms0.1363 ms1.000.0011.32 KB1.00
WriteMaskTexture1#0F08RGB8.tif0.22,457.115 ms34.9035 ms30.9410 ms68.940.8811.23 KB0.99
WriteMaskTexture64#0F08RGB8.tif0.252.640 ms0.2335 ms0.2184 ms1.480.0111.19 KB0.99
WriteMaskTextureFull#0F08RGB8.tif0.235.762 ms0.2270 ms0.2123 ms1.000.0111.26 KB0.99
CompositeCorners1#0F08RGB8.tif0.239.941 ms0.2830 ms0.2509 ms1.120.0111.48 KB1.01
CompositeCorners2#0F08RGB8.tif0.229.140 ms0.1707 ms0.1513 ms0.820.016.05 KB0.53
WriteMaskComposite#0F08RGB8.tif0.444.133 ms0.2383 ms0.2229 ms1.000.0011.32 KB1.00
WriteMaskTexture1#0F08RGB8.tif0.42,301.307 ms13.8778 ms10.8349 ms52.150.3511.23 KB0.99
WriteMaskTexture64#0F08RGB8.tif0.459.378 ms0.1851 ms0.1731 ms1.350.0111.19 KB0.99
WriteMaskTextureFull#0F08RGB8.tif0.444.171 ms0.1405 ms0.1246 ms1.000.0111.26 KB0.99
CompositeCorners1#0F08RGB8.tif0.448.529 ms0.1992 ms0.1766 ms1.100.0111.48 KB1.01
CompositeCorners2#0F08RGB8.tif0.437.856 ms0.2142 ms0.1899 ms0.860.016.05 KB0.53
WriteMaskComposite#0F0FRGB16.tif011.889 ms0.0296 ms0.0277 ms1.000.0011.22 KB1.00
WriteMaskTexture1#0F0FRGB16.tif07.435 ms0.0288 ms0.0270 ms0.630.0011.09 KB0.99
WriteMaskTexture64#0F0FRGB16.tif07.370 ms0.0149 ms0.0140 ms0.620.0011.09 KB0.99
WriteMaskTextureFull#0F0FRGB16.tif08.651 ms0.0945 ms0.0838 ms0.730.0111.16 KB0.99
CompositeCorners1#0F0FRGB16.tif019.662 ms0.1863 ms0.1651 ms1.650.0111.38 KB1.01
CompositeCorners2#0F0FRGB16.tif013.170 ms0.0766 ms0.0717 ms1.110.016.26 KB0.56
WriteMaskComposite#0F0FRGB16.tif0.234.398 ms0.2007 ms0.1567 ms1.000.0011.22 KB1.00
WriteMaskTexture1#0F0FRGB16.tif0.230.002 ms0.1504 ms0.1334 ms0.870.0111.09 KB0.99
WriteMaskTexture64#0F0FRGB16.tif0.230.076 ms0.2156 ms0.2017 ms0.870.0111.09 KB0.99
WriteMaskTextureFull#0F0FRGB16.tif0.231.164 ms0.1958 ms0.1736 ms0.910.0111.16 KB0.99
CompositeCorners1#0F0FRGB16.tif0.239.460 ms0.2809 ms0.2490 ms1.150.0111.38 KB1.01
CompositeCorners2#0F0FRGB16.tif0.234.042 ms0.1561 ms0.1460 ms0.990.016.26 KB0.56
WriteMaskComposite#0F0FRGB16.tif0.443.542 ms0.1759 ms0.1645 ms1.000.0011.22 KB1.00
WriteMaskTexture1#0F0FRGB16.tif0.440.048 ms0.3809 ms0.3376 ms0.920.0111.09 KB0.99
WriteMaskTexture64#0F0FRGB16.tif0.438.587 ms0.2709 ms0.2402 ms0.890.0111.09 KB0.99
WriteMaskTextureFull#0F0FRGB16.tif0.439.910 ms0.3408 ms0.3188 ms0.920.0111.16 KB0.99
CompositeCorners1#0F0FRGB16.tif0.448.201 ms0.3872 ms0.3233 ms1.110.0111.38 KB1.01
CompositeCorners2#0F0FRGB16.tif0.442.595 ms0.3105 ms0.2753 ms0.980.016.26 KB0.56
WriteMaskComposite#0F0FRGB8.tif011.929 ms0.0804 ms0.0713 ms1.000.0011.22 KB1.00
WriteMaskTexture1#0F0FRGB8.tif07.405 ms0.0983 ms0.0919 ms0.620.0111.09 KB0.99
WriteMaskTexture64#0F0FRGB8.tif07.399 ms0.0261 ms0.0244 ms0.620.0011.09 KB0.99
WriteMaskTextureFull#0F0FRGB8.tif08.536 ms0.1661 ms0.1472 ms0.720.0111.16 KB0.99
CompositeCorners1#0F0FRGB8.tif019.613 ms0.0766 ms0.0639 ms1.640.0111.38 KB1.01
CompositeCorners2#0F0FRGB8.tif013.280 ms0.0901 ms0.0843 ms1.110.016.26 KB0.56
WriteMaskComposite#0F0FRGB8.tif0.234.597 ms0.2190 ms0.1941 ms1.000.0011.22 KB1.00
WriteMaskTexture1#0F0FRGB8.tif0.230.058 ms0.1444 ms0.1280 ms0.870.0111.09 KB0.99
WriteMaskTexture64#0F0FRGB8.tif0.229.875 ms0.1148 ms0.1018 ms0.860.0111.09 KB0.99
WriteMaskTextureFull#0F0FRGB8.tif0.231.104 ms0.1066 ms0.0890 ms0.900.0111.16 KB0.99
CompositeCorners1#0F0FRGB8.tif0.239.135 ms0.2918 ms0.2729 ms1.130.0111.38 KB1.01
CompositeCorners2#0F0FRGB8.tif0.233.805 ms0.1647 ms0.1540 ms0.980.016.26 KB0.56
WriteMaskComposite#0F0FRGB8.tif0.443.553 ms0.4904 ms0.4587 ms1.000.0011.22 KB1.00
WriteMaskTexture1#0F0FRGB8.tif0.438.614 ms0.1566 ms0.1464 ms0.890.0111.09 KB0.99
WriteMaskTexture64#0F0FRGB8.tif0.438.807 ms0.1860 ms0.1649 ms0.890.0111.09 KB0.99
WriteMaskTextureFull#0F0FRGB8.tif0.440.049 ms0.2257 ms0.2001 ms0.920.0111.16 KB0.99
CompositeCorners1#0F0FRGB8.tif0.448.036 ms0.2988 ms0.2795 ms1.100.0111.38 KB1.01
CompositeCorners2#0F0FRGB8.tif0.442.553 ms0.1750 ms0.1552 ms0.980.016.26 KB0.56
+ + diff --git a/GarthImgLab.Benchmarks/RoundCorner.cs b/GarthImgLab.Benchmarks/RoundCorner.cs index 8deb1f1..faf3a3f 100644 --- a/GarthImgLab.Benchmarks/RoundCorner.cs +++ b/GarthImgLab.Benchmarks/RoundCorner.cs @@ -1,6 +1,7 @@ // ReSharper disable MemberCanBePrivate.Global // ReSharper disable PropertyCanBeMadeInitOnly.Global // ReSharper disable UnusedMember.Global +// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global namespace GarthImgLab.Benchmarks; @@ -9,28 +10,30 @@ namespace GarthImgLab.Benchmarks; using ImageMagick.Drawing; [MemoryDiagnoser, SuppressMessage("ReSharper", "ClassCanBeSealed.Global")] -public class RoundCorner: IDisposable { - private MagickImage? _oriImg; - private IMagickImage? _testImg; +public class RoundCorner { + private MagickColor _c = new(); + private MagickImage _oriImg = new(); + private IMagickImage _testImg = new MagickImage(); private uint _w, _h; - [Params("#0F0F", "#0F08", "#0F00")] public string Hex = "#0F08"; - private MagickColor Color => new(Hex); + [Params("#0F0F", "#0F08", "#0F00")] public string Hex { get; set; } = "#0F08"; + [Params("RGB8.tif", "RGB16.tif")] public string FileName { get; set; } = "RGB8.tif"; [Params(0, .2, .4)] public double Radius { get => field * Math.Min(_w, _h); set; } = .2; - public void Dispose() { - _oriImg?.Dispose(); - _testImg?.Dispose(); - GC.SuppressFinalize(this); - } - [GlobalSetup] public void GlobalSetup() { - _oriImg = new(Path.Combine(AppContext.BaseDirectory, "lena_std.tif")); + _c = new(Hex); + _oriImg = new(Path.Combine(AppContext.BaseDirectory, FileName)); _w = _oriImg.Width; _h = _oriImg.Height; _testImg = _oriImg.CloneArea(_w, _h); } + [GlobalCleanup] + public void Cleanup() { + _oriImg.Dispose(); + _testImg.Dispose(); + } + public void Test() { GlobalSetup(); string[] hexes = ["#0F0F", "#0F08", "#0F00"]; @@ -38,9 +41,9 @@ public void Test() { Hex = hex; WriteMaskComposite(); - _testImg!.Write($"WriteMaskComposite_{hex}.tif"); + _testImg.Write($"WriteMaskComposite_{hex}.tif"); _testImg.Dispose(); - _testImg = _oriImg!.CloneArea(_w, _h); + _testImg = _oriImg.CloneArea(_w, _h); WriteMaskDraw(); _testImg.Write($"WriteMaskDraw_{hex}.tif"); @@ -99,9 +102,9 @@ public void WriteMaskComposite() { var r = Radius; using MagickImage mask = new(MagickColors.Black, _w, _h); new Drawables().FillColor(MagickColors.White).RoundRectangle(0, 0, _w, _h, r, r).Draw(mask); - _testImg!.SetWriteMask(mask); + _testImg.SetWriteMask(mask); try { - using MagickImage tmp = new(Color, _w, _h); + using MagickImage tmp = new(_c, _w, _h); _testImg.Composite(tmp, CompositeOperator.Over); } finally { _testImg.RemoveWriteMask(); } } @@ -111,8 +114,8 @@ public void WriteMaskDraw() { var r = Radius; using MagickImage mask = new(MagickColors.Black, _w, _h); new Drawables().FillColor(MagickColors.White).RoundRectangle(0, 0, _w, _h, r, r).Draw(mask); - _testImg!.SetWriteMask(mask); - try { new Drawables().FillColor(Color).Rectangle(0, 0, _w, _h).Draw(_testImg); } finally { + _testImg.SetWriteMask(mask); + try { new Drawables().FillColor(_c).Rectangle(0, 0, _w, _h).Draw(_testImg); } finally { _testImg.RemoveWriteMask(); } } @@ -120,26 +123,26 @@ public void WriteMaskDraw() { // 有黑边,效果错误 public void WriteMaskCopyAlpha() { var r = Radius; - using MagickImage corners = new(Color, _w, _h); + using MagickImage corners = new(_c, _w, _h); corners.Alpha(AlphaOption.Set); using MagickImage mask = new(MagickColors.White, _w, _h); new Drawables().FillColor(MagickColors.Black).RoundRectangle(0, 0, _w, _h, r, r).Draw(mask); corners.SetWriteMask(mask); using MagickImage a = new(MagickColors.Transparent, _w, _h); corners.Composite(a, CompositeOperator.CopyAlpha); - _testImg!.Composite(corners, CompositeOperator.Over); + _testImg.Composite(corners, CompositeOperator.Over); } // 过渡生硬 public void WriteMaskEvaluate() { var r = Radius; - using MagickImage corners = new(Color, _w, _h); + using MagickImage corners = new(_c, _w, _h); corners.Alpha(AlphaOption.Set); using MagickImage mask = new(MagickColors.White, _w, _h); new Drawables().FillColor(MagickColors.Black).RoundRectangle(0, 0, _w, _h, r, r).Draw(mask); corners.SetWriteMask(mask); corners.Evaluate(Channels.Alpha, EvaluateOperator.Set, 0); - _testImg!.Composite(corners, CompositeOperator.Over); + _testImg.Composite(corners, CompositeOperator.Over); } [Benchmark] @@ -147,9 +150,9 @@ public void WriteMaskTexture1() { var r = Radius; using MagickImage mask = new(MagickColors.Black, _w, _h); new Drawables().FillColor(MagickColors.White).RoundRectangle(0, 0, _w, _h, r, r).Draw(mask); - _testImg!.SetWriteMask(mask); + _testImg.SetWriteMask(mask); try { - using MagickImage tmp = new(Color, 1, 1); + using MagickImage tmp = new(_c, 1, 1); _testImg.Texture(tmp); } finally { _testImg.RemoveWriteMask(); } } @@ -159,9 +162,9 @@ public void WriteMaskTexture64() { var r = Radius; using MagickImage mask = new(MagickColors.Black, _w, _h); new Drawables().FillColor(MagickColors.White).RoundRectangle(0, 0, _w, _h, r, r).Draw(mask); - _testImg!.SetWriteMask(mask); + _testImg.SetWriteMask(mask); try { - using MagickImage tmp = new(Color, 64, 64); + using MagickImage tmp = new(_c, 64, 64); _testImg.Texture(tmp); } finally { _testImg.RemoveWriteMask(); } } @@ -171,9 +174,9 @@ public void WriteMaskTextureFull() { var r = Radius; using MagickImage mask = new(MagickColors.Black, _w, _h); new Drawables().FillColor(MagickColors.White).RoundRectangle(0, 0, _w, _h, r, r).Draw(mask); - _testImg!.SetWriteMask(mask); + _testImg.SetWriteMask(mask); try { - using MagickImage tmp = new(Color, _w, _h); + using MagickImage tmp = new(_c, _w, _h); _testImg.Texture(tmp); } finally { _testImg.RemoveWriteMask(); } } @@ -183,14 +186,14 @@ public void CompositeCorners0() { var r = Radius; using MagickImage a = new(MagickColors.None, _w, _h); new Drawables().FillColor(MagickColors.White).RoundRectangle(0, 0, _w, _h, r, r).Draw(a); - using MagickImage corners = new(Color, _w, _h); + using MagickImage corners = new(_c, _w, _h); corners.Composite(a, CompositeOperator.DstOut); - _testImg!.Composite(corners, CompositeOperator.Over); + _testImg.Composite(corners, CompositeOperator.Over); } [Benchmark] public void CompositeCorners1() { - var c = Color; + var c = _c; var r = Radius; using MagickImage a = new(new MagickColor { A = (ushort)~c.A }, _w, _h); new Drawables().FillColor(MagickColors.Black) @@ -199,12 +202,12 @@ public void CompositeCorners1() { a.Negate(Channels.Alpha); // 中间透明,四角 Alpha 还原 using MagickImage corners = new(c, _w, _h); corners.Composite(a, CompositeOperator.CopyAlpha); - _testImg!.Composite(corners, CompositeOperator.Over); + _testImg.Composite(corners, CompositeOperator.Over); } [Benchmark] public void CompositeCorners2() { - var c = Color; + var c = _c; var r = Radius; var notA = (ushort)~c.A; using MagickImage corners = new(new MagickColor(c) { A = notA }, _w, _h); @@ -213,7 +216,7 @@ public void CompositeCorners2() { .Draw(corners); // 中间不透明,四角 Alpha 反相 corners.Negate(Channels.Alpha); // 中间透明,四角 Alpha 还原 if (notA == 0) corners.Colorize(c, new(100)); // 若A为0,RGB会被置0,需重新上色 - _testImg!.Composite(corners, CompositeOperator.Over); + _testImg.Composite(corners, CompositeOperator.Over); } // 有透明度时效果错误 @@ -221,7 +224,7 @@ public void WriteMaskColorize() { var r = Radius; using MagickImage mask = new(MagickColors.Black, _w, _h); new Drawables().FillColor(MagickColors.White).RoundRectangle(0, 0, _w, _h, r, r).Draw(mask); - _testImg!.SetWriteMask(mask); - try { _testImg.Colorize(Color, new(100)); } finally { _testImg.RemoveWriteMask(); } + _testImg.SetWriteMask(mask); + try { _testImg.Colorize(_c, new(100)); } finally { _testImg.RemoveWriteMask(); } } } diff --git a/GarthImgLab/GarthImgLab.csproj b/GarthImgLab/GarthImgLab.csproj index bec40dd..1ceb249 100644 --- a/GarthImgLab/GarthImgLab.csproj +++ b/GarthImgLab/GarthImgLab.csproj @@ -31,6 +31,6 @@ - +
diff --git a/GarthImgLab/GlobalUsings.cs b/GarthImgLab/GlobalUsings.cs new file mode 100644 index 0000000..a48d10e --- /dev/null +++ b/GarthImgLab/GlobalUsings.cs @@ -0,0 +1,6 @@ +global using CT = System.Threading.CancellationToken; +global using CTS = System.Threading.CancellationTokenSource; +global using Img = ImageMagick.MagickImage; +global using Never = System.Diagnostics.UnreachableException; +global using OCEx = System.OperationCanceledException; +global using OpEx = System.InvalidOperationException; diff --git a/GarthImgLab/Models/Annotator.cs b/GarthImgLab/Models/Annotator.cs index 6c9a7f8..4a03d1f 100644 --- a/GarthImgLab/Models/Annotator.cs +++ b/GarthImgLab/Models/Annotator.cs @@ -6,12 +6,13 @@ namespace GarthImgLab.Models; public sealed class Annotator: IFx { private readonly double _bRatio, _textRatio, _margin; - private readonly Func _getInfo; - private readonly MagickImage? _icon; - private readonly IDrawables _pen; + private readonly MagickColor _c; + private readonly string _font; + private readonly Func _getInfo; + private readonly Img? _icon; public Annotator( - MagickImage? icon, + Img? icon, double margin, double ltrRatio, double bRatio, @@ -20,19 +21,19 @@ public Annotator( string font, string separator, IEnumerable tagInfoUnions) { - _pen = new Drawables().Font(font).FillColor(c).StrokeColor(c).StrokeOpacity(new(37)); - var funcs = tagInfoUnions.Select(ExifExtractor.GetExtractor).ToArray(); - _getInfo = img => { - var parts = funcs.Select(x => x(img)).Where(static x => !string.IsNullOrWhiteSpace(x)); - return string.Join(separator, parts); - }; - _bRatio = bRatio / (ltrRatio + 1 + bRatio); - _textRatio = textRatio; _icon = icon; _margin = margin; + _bRatio = bRatio / (ltrRatio + 1 + bRatio); + _textRatio = textRatio; + _c = c; + _font = font; + var funcs = tagInfoUnions.Select(ExifExtractor.GetExtractor).ToArray(); + _getInfo = img => string.Join( + separator, + funcs.Select(x => x(img)).Where(static x => !string.IsNullOrWhiteSpace(x))); } - public void Apply(MagickImage img, CancellationToken ct) { + public void Apply(Img img, CT ct) { uint w = img.Width, h = img.Height; var bPx = (uint)Round(_bRatio * Min(w, h)); if (bPx == 0) return; @@ -40,9 +41,10 @@ public void Apply(MagickImage img, CancellationToken ct) { var info = _getInfo(img); var tgtH = _textRatio * bPx; + IDrawables? pen = null; var (textW, textH, ascent) = string.IsNullOrWhiteSpace(info) ? (0, tgtH, 0) - : MeasureText(info, tgtH); + : MeasureText(info, tgtH, out pen); var y = (int)Round(h - (bPx + textH) / 2); var textX = (w - textW) / 2; var iconH = (uint)Round(textH); @@ -59,16 +61,20 @@ public void Apply(MagickImage img, CancellationToken ct) { if (textW < 1) return; ct.ThrowIfCancellationRequested(); - _pen.Text(textX, y + ascent, info).Draw(img); + pen!.Text(textX, y + ascent, info).Draw(img); } - private (double, double, double) MeasureText(string text, double tgtH) { + private (double, double, double) MeasureText( + string text, + double tgtH, + out IDrawables pen) { + pen = new Drawables().Font(_font).FillColor(_c).StrokeColor(_c).StrokeOpacity(new(37)); for (var (i, size) = (0, 14d); i < 3; i++) { - var m = _pen.FontPointSize(size).StrokeWidth(.03 * size).FontTypeMetrics(text) - ?? throw new InvalidOperationException("无法测量文字尺寸"); + var m = pen.FontPointSize(size).StrokeWidth(.03 * size).FontTypeMetrics(text) + ?? throw new OpEx("无法测量文字尺寸"); if (Abs(m.TextHeight - tgtH) < .1 * tgtH) return (m.TextWidth, m.TextHeight, m.Ascent); size *= tgtH / m.TextHeight; } - throw new InvalidOperationException("无法自动调整字号"); + throw new OpEx("无法自动调整字号"); } } diff --git a/GarthImgLab/Models/ExifExtractor.cs b/GarthImgLab/Models/ExifExtractor.cs index 287b3d5..0b72398 100644 --- a/GarthImgLab/Models/ExifExtractor.cs +++ b/GarthImgLab/Models/ExifExtractor.cs @@ -2,7 +2,6 @@ namespace GarthImgLab.Models; -using System.Diagnostics; using ImageMagick; using static ImageMagick.ExifTag; using static AvailableExifTag; @@ -28,12 +27,12 @@ public enum AvailableExifTag: byte { public static class ExifExtractor { private const string PlaceHolder = "????"; - public static Func GetExtractor(string s) => + public static Func GetExtractor(string s) => Enum.TryParse(s, out AvailableExifTag tag) ? img => img.ExtractExif(tag) : _ => s; - private static string ExtractExif(this MagickImage img, AvailableExifTag tag) => + private static string ExtractExif(this Img img, AvailableExifTag tag) => tag switch { 快门 => GetExposureTime(img), 焦距 => GetFocalLength(img), @@ -50,10 +49,10 @@ private static string ExtractExif(this MagickImage img, AvailableExifTag tag) => 镜头型号 => GetStr(img, LensModel, "exif:LensModel"), 镜头序号 => GetStr(img, LensSerialNumber, "exif:LensSerialNumber"), 软件 => GetStr(img, Software, "tiff:software"), - _ => throw new UnreachableException() + _ => throw new Never() }; - private static string GetExposureTime(MagickImage img) { + private static string GetExposureTime(Img img) { var v = img.GetExifProfile()?.GetValue(ExposureTime)?.Value.ToDouble(); if (v is null) { var s = img.GetAttribute("exif:ExposureTime"); @@ -67,7 +66,7 @@ private static string GetExposureTime(MagickImage img) { return v switch { 0 => "0 s", < .3 => $"1/{1 / v:0} s", _ => $"{v:0.#} s" }; } - private static string GetFocalLength(MagickImage img) { + private static string GetFocalLength(Img img) { var v = img.GetExifProfile()?.GetValue(FocalLength)?.Value.ToDouble(); if (v is null) { var s = img.GetAttribute("exif:FocalLength"); @@ -81,7 +80,7 @@ private static string GetFocalLength(MagickImage img) { return $"{v:0.##} mm"; } - private static string GetFocalLengthIn35MMFilm(MagickImage img) { + private static string GetFocalLengthIn35MMFilm(Img img) { var v = img.GetExifProfile()?.GetValue(FocalLengthIn35mmFilm)?.Value; if (v is null) { var s = img.GetAttribute("exif:FocalLengthIn35mmFilm"); @@ -95,7 +94,7 @@ private static string GetFocalLengthIn35MMFilm(MagickImage img) { return $"{v} mm"; } - private static string GetFNumber(MagickImage img) { + private static string GetFNumber(Img img) { var v = img.GetExifProfile()?.GetValue(FNumber)?.Value.ToDouble(); if (v is null) { var s = img.GetAttribute("exif:FNumber"); @@ -109,7 +108,7 @@ private static string GetFNumber(MagickImage img) { return $"f/{v:0.##}"; } - private static string GetIsoSpeedRatings(MagickImage img) { + private static string GetIsoSpeedRatings(Img img) { var v = img.GetExifProfile()?.GetValue(ISOSpeedRatings)?.Value.FirstOrDefault(); if (v is null or 0) { var s = img.GetAttribute("exif:ISOSpeedRatings"); @@ -123,7 +122,7 @@ private static string GetIsoSpeedRatings(MagickImage img) { return $"ISO {v}"; } - private static string GetDateTimeOriginal(MagickImage img) { + private static string GetDateTimeOriginal(Img img) { var v = img.GetExifProfile()?.GetValue(DateTimeOriginal)?.Value; if (string.IsNullOrWhiteSpace(v)) { var s = img.GetAttribute("exif:DateTimeOriginal"); @@ -135,7 +134,7 @@ private static string GetDateTimeOriginal(MagickImage img) { : v; } - private static string GetStr(MagickImage img, ExifTag tag, string attribute) { + private static string GetStr(Img img, ExifTag tag, string attribute) { var v = img.GetExifProfile()?.GetValue(tag)?.Value; if (!string.IsNullOrWhiteSpace(v)) return v; var s = img.GetAttribute(attribute); diff --git a/GarthImgLab/Models/FrameMaker.cs b/GarthImgLab/Models/FrameMaker.cs index 315392d..297b8be 100644 --- a/GarthImgLab/Models/FrameMaker.cs +++ b/GarthImgLab/Models/FrameMaker.cs @@ -4,33 +4,36 @@ namespace GarthImgLab.Models; using ImageMagick.Drawing; public sealed class FrameMaker(double ltrRatio, double bRatio, double rcRatio, MagickColor c): IFx { - public void Apply(MagickImage img, CancellationToken ct) { + public void Apply(Img img, CT ct) { RoundCorner(img, ct); AddFrame(img, ct); } - private void RoundCorner(MagickImage img, CancellationToken ct) { + private void RoundCorner(Img img, CT ct) { uint w = img.Width, h = img.Height; var r = rcRatio * Math.Min(w, h); if (r == 0 || c.A == 0) return; ct.ThrowIfCancellationRequested(); + var notA = (ushort)~c.A; - using MagickImage corners = new(new MagickColor(c) { A = notA }, w, h); + using Img corners = new(new MagickColor(c) { A = notA }, w, h); ct.ThrowIfCancellationRequested(); new Drawables().FillColor(new MagickColor(c) { A = 65535 }) .RoundRectangle(0, 0, w, h, r, r) .Draw(corners); // 中间不透明,四角 Alpha 反相 ct.ThrowIfCancellationRequested(); corners.Negate(Channels.Alpha); // 中间透明,四角 Alpha 还原 + if (notA == 0) { // 若A为0,RGB会被置0,需重新上色 ct.ThrowIfCancellationRequested(); corners.Colorize(c, new(100)); } + ct.ThrowIfCancellationRequested(); img.Composite(corners, CompositeOperator.Over); } - private void AddFrame(MagickImage img, CancellationToken ct) { + private void AddFrame(Img img, CT ct) { uint w = img.Width, h = img.Height; var minSide = Math.Min(w, h); var ltrPx = (uint)Math.Round(ltrRatio * minSide); diff --git a/GarthImgLab/Models/IFx.cs b/GarthImgLab/Models/IFx.cs index 795dfe0..92885ec 100644 --- a/GarthImgLab/Models/IFx.cs +++ b/GarthImgLab/Models/IFx.cs @@ -1,7 +1,5 @@ namespace GarthImgLab.Models; -using ImageMagick; - public interface IFx { - void Apply(MagickImage img, CancellationToken ct); + void Apply(Img img, CT ct); } diff --git a/GarthImgLab/Models/ImgExt.cs b/GarthImgLab/Models/ImgExt.cs index 574e9f7..245d37b 100644 --- a/GarthImgLab/Models/ImgExt.cs +++ b/GarthImgLab/Models/ImgExt.cs @@ -1,10 +1,11 @@ namespace GarthImgLab.Models; +using System.Collections.Concurrent; using ImageMagick; public static class ImgExt { - extension(MagickImage img) { - public void ToThumb(double maxPx, CancellationToken ct) { + extension(Img img) { + public void ToThumb(double maxPx, CT ct) { var w = img.Width; var w2 = (uint)Math.Round(Math.Sqrt(maxPx / w / img.Height) * w); if (w2 >= w) return; @@ -13,19 +14,24 @@ public void ToThumb(double maxPx, CancellationToken ct) { img.Resize(w2, 0); } - public void MapPixel(Action f, CancellationToken ct) { - if (img.ColorSpace != ColorSpace.sRGB) throw new InvalidOperationException("不支持此色空间"); + public void MapPixel(Action f, CT ct) { + if (img.ColorSpace != ColorSpace.sRGB) throw new OpEx("不支持此色空间"); ct.ThrowIfCancellationRequested(); uint w = img.Width, h = img.Height; - var bpp = (nint)img.ChannelCount * sizeof(ushort); + nint bpp = (nint)img.ChannelCount * sizeof(ushort), bpr = (nint)w * bpp; using var px = img.GetPixelsUnsafe(); - var p = px.GetAreaPointer(0, 0, w, h); - Parallel.For(0, (int)(w * h), new() { CancellationToken = ct }, Proc); + var ptr = px.GetAreaPointer(0, 0, w, h); + Parallel.ForEach(Partitioner.Create(0, (int)h), new() { CancellationToken = ct }, Proc); - void Proc(int i) { - if ((i & 0xFFFF) == 0) ct.ThrowIfCancellationRequested(); - f(p + i * bpp); + void Proc(Tuple range) { + var (y, yTo) = range; + var ypTo = ptr + yTo * bpr; + for (var yp = ptr + y * bpr; yp < ypTo; yp += bpr, y++) { + if ((y & 0x0F) == 0) ct.ThrowIfCancellationRequested(); + var pTo = yp + bpr; + for (var p = yp; p < pTo; p += bpp) f(p); + } } } } diff --git a/GarthImgLab/Models/Saturator.cs b/GarthImgLab/Models/Saturator.cs index 524af34..e9e9262 100644 --- a/GarthImgLab/Models/Saturator.cs +++ b/GarthImgLab/Models/Saturator.cs @@ -1,9 +1,7 @@ namespace GarthImgLab.Models; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using ColorConverters; -using ImageMagick; using SM = SaturateMode; [SuppressMessage("ReSharper", "InconsistentNaming")] @@ -31,7 +29,7 @@ public Saturator(SM mode, double strength) { SM.JzCzhz => Boost, SM.OkLCh => Boost, SM.OkLrCh => Boost, - _ => throw new UnreachableException() + _ => throw new Never() }, < 0 => mode switch { SM.HSV => Reduce, @@ -40,13 +38,13 @@ public Saturator(SM mode, double strength) { SM.JzCzhz => Reduce, SM.OkLCh => Reduce, SM.OkLrCh => Reduce, - _ => throw new UnreachableException() + _ => throw new Never() }, _ => null }; } - public void Apply(MagickImage img, CancellationToken ct) { + public void Apply(Img img, CT ct) { if (_proc is {}) img.MapPixel(_proc, ct); } diff --git a/GarthImgLab/Models/Saver.cs b/GarthImgLab/Models/Saver.cs index 9d3f270..e94c206 100644 --- a/GarthImgLab/Models/Saver.cs +++ b/GarthImgLab/Models/Saver.cs @@ -1,8 +1,8 @@ namespace GarthImgLab.Models; using System.Collections.Frozen; -using System.Diagnostics; using ImageMagick; +using Fmt = ImageMagick.MagickFormat; public sealed class Saver(string fmt, string option, byte q) { public static readonly FrozenDictionary Map @@ -13,45 +13,43 @@ public static readonly FrozenDictionary Map ["WebP"] = ["Lossless", "Lossy"] }.ToFrozenDictionary(); - public Task SaveAsync(MagickImage img, string iPath, CancellationToken ct) { + public Task SaveAsync(Img img, string iPath, CT ct) { img.Quality = q; return fmt switch { "JPEG" => SaveJpeg(img, iPath, ct), "PNG" => SavePng(img, iPath, ct), "TIFF" => SaveTiff(img, iPath, ct), "WebP" => SaveWebP(img, iPath, ct), - _ => throw new UnreachableException() + _ => throw new Never() }; } - private Task SaveJpeg(MagickImage img, string iPath, CancellationToken ct) { + private Task SaveJpeg(Img img, string iPath, CT ct) { var oPath = GetOutPath(iPath, "jpg"); - img.Settings.SetDefine(MagickFormat.Jpeg, "sampling-factor", option); - return img.WriteAsync(oPath, MagickFormat.Pjpeg, ct); + img.Settings.SetDefine(Fmt.Jpeg, "sampling-factor", option); + return img.WriteAsync(oPath, Fmt.Pjpeg, ct); } - private Task SavePng(MagickImage img, string iPath, CancellationToken ct) { + private Task SavePng(Img img, string iPath, CT ct) { var oPath = GetOutPath(iPath, "png"); - if (!Enum.TryParse(option, out MagickFormat png)) - throw new InvalidOperationException("PNG 格式名称无效"); + if (!Enum.TryParse(option, out Fmt png)) throw new OpEx("PNG 格式名称无效"); return img.WriteAsync(oPath, png, ct); } - private Task SaveTiff(MagickImage img, string iPath, CancellationToken ct) { + private Task SaveTiff(Img img, string iPath, CT ct) { var oPath = GetOutPath(iPath, "tif"); - if (!Enum.TryParse(option, out CompressionMethod cmp)) - throw new InvalidOperationException("TIFF 压缩算法无效"); + if (!Enum.TryParse(option, out CompressionMethod cmp)) throw new OpEx("TIFF 压缩算法无效"); img.Settings.Compression = cmp; - return img.WriteAsync(oPath, MagickFormat.Tiff, ct); + return img.WriteAsync(oPath, Fmt.Tiff, ct); } - private Task SaveWebP(MagickImage img, string iPath, CancellationToken ct) { + private Task SaveWebP(Img img, string iPath, CT ct) { var oPath = GetOutPath(iPath, "webp"); var v = option == "Lossless" ? "true" : "false"; - img.Settings.SetDefine(MagickFormat.WebP, "lossless", v); - return img.WriteAsync(oPath, MagickFormat.WebP, ct); + img.Settings.SetDefine(Fmt.WebP, "lossless", v); + return img.WriteAsync(oPath, Fmt.WebP, ct); } private static string GetOutPath(string iPath, string ext) { diff --git a/GarthImgLab/ViewModels/Contexts/PreviewCtx.cs b/GarthImgLab/ViewModels/Contexts/PreviewCtx.cs index 541d665..ec5e91e 100644 --- a/GarthImgLab/ViewModels/Contexts/PreviewCtx.cs +++ b/GarthImgLab/ViewModels/Contexts/PreviewCtx.cs @@ -10,9 +10,9 @@ namespace GarthImgLab.ViewModels.Contexts; public sealed class PreviewCtx: ObservableObject, IPreviewCtx { private const int ThumbSize = 1024 * 1024, DebounceMs = 150; private bool _active, _enabled; - private MagickImage? _bef, _aft; + private Img? _bef, _aft; private Bitmap? _befBmp, _aftBmp; - private CancellationTokenSource _befCts = new(), _aftCts = new(); + private CTS _befCts = new(), _aftCts = new(); public IImage? DisplayImg => _enabled @@ -43,7 +43,7 @@ public async Task LoadBefAsync(string path) { if (!_active) return; var ct = CancelAndGetNewCt(ref _befCts); CancelAndGetNewCt(ref _aftCts); - MagickImage? bef = null; + Img? bef = null; Bitmap? bmp = null; try { bef = new(); @@ -61,7 +61,7 @@ await Dispatcher.UIThread.InvokeAsync(() => { } catch (Exception ex) { bef?.Dispose(); bmp?.Dispose(); - if (ex is not OperationCanceledException) Clear(); + if (ex is not OCEx) Clear(); } } @@ -69,13 +69,13 @@ public async Task UpdateAftAsync(IReadOnlyList fxs) { if (!_active) return; var ct = CancelAndGetNewCt(ref _aftCts); if (_bef is null) return; - MagickImage? aft = null; + Img? aft = null; Bitmap? bmp = null; try { await Task.Delay(DebounceMs, ct); aft = await Task.Run( () => { - var img = (MagickImage)_bef.CloneArea(_bef.Width, _bef.Height); + var img = (Img)_bef.CloneArea(_bef.Width, _bef.Height); try { foreach (var fx in fxs) fx.Apply(img, ct); return img; @@ -99,20 +99,20 @@ await Dispatcher.UIThread.InvokeAsync(() => { } } - private static CancellationToken CancelAndGetNewCt(ref CancellationTokenSource cts) { + private static CT CancelAndGetNewCt(ref CTS cts) { cts.Cancel(); cts.Dispose(); return (cts = new()).Token; } - private static void DisposeImg(ref MagickImage? img, ref Bitmap? bmp) { + private static void DisposeImg(ref Img? img, ref Bitmap? bmp) { img?.Dispose(); img = null; bmp?.Dispose(); bmp = null; } - private static async Task ToBmpAsync(MagickImage img, CancellationToken ct) { + private static async Task ToBmpAsync(Img img, CT ct) { using MemoryStream ms = new(); await img.WriteAsync(ms, MagickFormat.Bmp, ct); ms.Seek(0, SeekOrigin.Begin); diff --git a/GarthImgLab/ViewModels/MsgBox.cs b/GarthImgLab/ViewModels/MsgBox.cs index 7aa27e0..b3b485c 100644 --- a/GarthImgLab/ViewModels/MsgBox.cs +++ b/GarthImgLab/ViewModels/MsgBox.cs @@ -17,7 +17,7 @@ public static Task AlertAsync(this Exception ex, string op, Window? owner = null private static Window GetTopWindow() { if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime { MainWindow: {} w }) - throw new InvalidOperationException("无法获取主窗口"); + throw new OpEx("无法获取主窗口"); while (w.OwnedWindows is [.., var last]) w = last; return w; } diff --git a/GarthImgLab/ViewModels/Tabs/FrameTabVm.cs b/GarthImgLab/ViewModels/Tabs/FrameTabVm.cs index ba03c0e..484f44a 100644 --- a/GarthImgLab/ViewModels/Tabs/FrameTabVm.cs +++ b/GarthImgLab/ViewModels/Tabs/FrameTabVm.cs @@ -27,7 +27,7 @@ public sealed partial class FrameTabVm(IPipelineBuilder pb, IPreviewCtx pc): FxT #region 图标 // ReSharper disable once MemberCanBeMadeStatic.Local - [ObservableProperty] private partial MagickImage? Icon { get; set; } + [ObservableProperty] private partial Img? Icon { get; set; } [ObservableProperty] public partial bool UseIcon { get; set; } [ObservableProperty] public partial double Margin { get; set; } = 1; [ObservableProperty] public partial string IconPath { get; set; } = ""; diff --git a/GarthImgLab/ViewModels/Tabs/HomeTabVm.cs b/GarthImgLab/ViewModels/Tabs/HomeTabVm.cs index b0bc148..a49e8d1 100644 --- a/GarthImgLab/ViewModels/Tabs/HomeTabVm.cs +++ b/GarthImgLab/ViewModels/Tabs/HomeTabVm.cs @@ -4,8 +4,6 @@ namespace GarthImgLab.ViewModels.Tabs; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Contexts; -using ImageMagick; -using OpEx = InvalidOperationException; public sealed partial class HomeTabVm: TabVm { private readonly IPipelineBuilder _pb; @@ -53,14 +51,14 @@ private async Task RemPathAsync() { [ObservableProperty] public partial bool AutoRem { get; set; } [RelayCommand(CanExecute = nameof(HasPaths), IncludeCancelCommand = true)] - private async Task StartBatchAsync(CancellationToken ct) { + private async Task StartBatchAsync(CT ct) { try { var pipeline = _pb.Build(); var saver = _pb.Saver ?? throw new OpEx("未配置保存参数"); List done = new(Paths.Count); foreach (var path in Paths) { ct.ThrowIfCancellationRequested(); - using MagickImage img = new(); + using Img img = new(); await img.ReadAsync(path, ct); foreach (var fx in pipeline) fx.Apply(img, ct); await saver.SaveAsync(img, path, ct); @@ -71,7 +69,7 @@ private async Task StartBatchAsync(CancellationToken ct) { throw new OpEx("UI 移除图像失败"); await MsgBox.InfoAsync($"批处理完成,共{done.Count}张图像"); } catch (Exception ex) { - if (ex is not OperationCanceledException) await ex.AlertAsync("批处理"); + if (ex is not OCEx) await ex.AlertAsync("批处理"); } } diff --git a/GarthImgLab/Views/Tabs/HomeTabView.axaml.cs b/GarthImgLab/Views/Tabs/HomeTabView.axaml.cs index e2b303a..7ca4890 100644 --- a/GarthImgLab/Views/Tabs/HomeTabView.axaml.cs +++ b/GarthImgLab/Views/Tabs/HomeTabView.axaml.cs @@ -23,7 +23,6 @@ private async void AddImg(object? _, RoutedEventArgs e) { if (DataContext is not HomeTabVm vm || sp is null) return; var files = await sp.OpenFilePickerAsync(_openOptions); if (files.Count == 0) return; - foreach (var file in files) using (file) vm.AddPathAsync(file.TryGetLocalPath() ?? file.Path.LocalPath);