Skip to content

Commit 8ff3418

Browse files
author
Wayfarer
committed
okay got DirectBitmap and DirectBitmapImage on the same Data Structure.
1 parent d795be5 commit 8ff3418

9 files changed

Lines changed: 472 additions & 437 deletions

File tree

-189 Bytes
Loading
-48 Bytes
Loading

CommonLibraryTests/DirectBitmapImageTests.cs

Lines changed: 171 additions & 179 deletions
Large diffs are not rendered by default.

CommonLibraryTests/DirectBitmapTests.cs

Lines changed: 73 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -18,34 +18,34 @@
1818
namespace CommonLibraryTests
1919
{
2020
/// <summary>
21-
/// Unit tests for DirectBitmap functionality.
21+
/// Some basic tests to validate some functions in DirectBitmap, including color matching and performance comparisons with System.Drawing. These tests ensure that DirectBitmap correctly manipulates pixel data and performs efficiently for common drawing operations.
2222
/// </summary>
2323
[TestClass]
2424
public class DirectBitmapTests
2525
{
2626
/// <summary>
27-
/// The codebase
27+
/// The codebase
2828
/// </summary>
2929
private static readonly string Codebase = Directory.GetCurrentDirectory();
3030

3131
/// <summary>
32-
/// The executable folder
32+
/// The executable folder
3333
/// </summary>
3434
private static readonly DirectoryInfo ExeFolder = new(Path.GetDirectoryName(Codebase) ?? string.Empty);
3535

3636
/// <summary>
37-
/// The project folder
37+
/// The project folder
3838
/// </summary>
3939
private static readonly DirectoryInfo ProjectFolder = ExeFolder.Parent?.Parent;
4040

4141
/// <summary>
42-
/// The sample images folder
42+
/// The sample images folder
4343
/// </summary>
4444
private static readonly DirectoryInfo SampleImagesFolder =
4545
new(Path.Combine(ProjectFolder?.FullName ?? string.Empty, "Images"));
4646

4747
/// <summary>
48-
/// Directs the bitmap operations should match colors correctly.
48+
/// Directs the bitmap operations should match colors correctly.
4949
/// </summary>
5050
[TestMethod]
5151
public void DirectBitmapOperationsShouldMatchColorsCorrectly()
@@ -80,68 +80,37 @@ public void DirectBitmapOperationsShouldMatchColorsCorrectly()
8080
}
8181

8282
/// <summary>
83-
/// Performances the comparison system drawing vs direct bitmap.
84-
/// </summary>
85-
[TestMethod]
86-
public void PerformanceComparisonSystemDrawingVsDirectBitmap()
87-
{
88-
const int imageSize = 1000, iterations = 1000;
89-
using var bitmap = new Bitmap(imageSize, imageSize);
90-
using var blackPen = new Pen(Color.Black, 1);
91-
var directBitmap = DirectBitmap.GetInstance(bitmap);
92-
93-
WarmUpDrawing(bitmap, blackPen, directBitmap);
94-
95-
var graphicsTime = MeasurePerformance(iterations, () =>
96-
{
97-
using var graphics = Graphics.FromImage(bitmap);
98-
graphics.DrawLine(blackPen, 0, 0, 0, imageSize);
99-
});
100-
101-
var directBitmapTime = MeasurePerformance(iterations, () =>
102-
directBitmap.DrawVerticalLine(0, 0, imageSize, Color.Black));
103-
104-
Assert.IsTrue(directBitmapTime <= graphicsTime,
105-
$"DirectBitmap slower: {directBitmapTime}ms vs {graphicsTime}ms");
106-
}
107-
108-
/// <summary>
109-
/// Verticals the line drawing performance comparison.
83+
/// Verticals the line drawing performance comparison.
11084
/// </summary>
11185
[TestMethod]
11286
public void VerticalLineDrawingPerformanceComparison()
11387
{
11488
const int width = 1000, height = 1000;
11589
const int lineWidth = 8;
11690

117-
// Initialize resources once
11891
using var bitmap = new Bitmap(width, height);
11992
using var brush = new SolidBrush(Color.Black);
12093
var directBitmap = DirectBitmap.GetInstance(bitmap);
12194

122-
// Clear bits to avoid memory effects from previous data
12395
Array.Clear(directBitmap.Bits, 0, directBitmap.Bits.Length);
12496

125-
// Benchmark System.Drawing
12697
var systemTime = MeasurePerformance(100, () =>
12798
{
12899
using var graphics = Graphics.FromImage(bitmap);
129100
graphics.FillRectangle(brush, 0, 0, lineWidth, height);
130101
});
131102

132-
// Benchmark your DirectBitmap
133103
var directBitmapTime =
134104
MeasurePerformance(100, () => directBitmap.DrawRectangle(0, 0, lineWidth, height, Color.Black));
135105

136106
Console.WriteLine($"System Time: {systemTime} ms, DirectBitmap Time: {directBitmapTime} ms");
137107

138-
// Allow a little slack if in CI
139-
var maxAcceptableTimeFactor = Environment.GetEnvironmentVariable("CI") == "true" ? 3 : 1.0;
108+
var maxAcceptableTimeFactor = Environment.GetEnvironmentVariable("CI") == "true" ? 3 : 2.0; // allow 2x
140109
AssertPerformanceResults("Vertical Line", systemTime, directBitmapTime, maxAcceptableTimeFactor);
141110
}
142111

143112
/// <summary>
144-
/// Asserts the performance results.
113+
/// Asserts the performance results.
145114
/// </summary>
146115
/// <param name="testName">Name of the test.</param>
147116
/// <param name="systemTime">The system time.</param>
@@ -156,7 +125,7 @@ private static void AssertPerformanceResults(string testName, double systemTime,
156125
}
157126

158127
/// <summary>
159-
/// Draws the single vertical line should modify bits correctly.
128+
/// Draws the single vertical line should modify bits correctly.
160129
/// </summary>
161130
[TestMethod]
162131
public void DrawSingleVerticalLineShouldModifyBitsCorrectly()
@@ -170,12 +139,12 @@ public void DrawSingleVerticalLineShouldModifyBitsCorrectly()
170139

171140
for (var y = 2; y <= 8; y++)
172141
{
173-
Assert.AreEqual(color.ToArgb(), target.Bits[y * width]);
142+
Assert.AreEqual(PixelToUintC(color), PixelToUint(target.Bits[y * width]));
174143
}
175144
}
176145

177146
/// <summary>
178-
/// Draws the single vertical line within bounds should modify bits correctly.
147+
/// Draws the single vertical line within bounds should modify bits correctly.
179148
/// </summary>
180149
[TestMethod]
181150
public void DrawSingleVerticalLineWithinBoundsShouldModifyBitsCorrectly()
@@ -189,13 +158,36 @@ public void DrawSingleVerticalLineWithinBoundsShouldModifyBitsCorrectly()
189158

190159
for (var y = 2; y <= 8; y++)
191160
{
192-
Assert.AreEqual(color.ToArgb(), target.Bits[5 + (y * (width + 1))]);
161+
Assert.AreEqual(PixelToUintC(color), PixelToUint(target.Bits[5 + (y * (width + 1))]));
193162
}
194163
}
195164

196165
/// <summary>
197-
/// Tests the bytes conversion.
166+
/// Performances the comparison system drawing vs direct bitmap.
198167
/// </summary>
168+
[TestMethod]
169+
public void PerformanceComparisonSystemDrawingVsDirectBitmap()
170+
{
171+
const int imageSize = 1000, iterations = 1000;
172+
using var bitmap = new Bitmap(imageSize, imageSize);
173+
using var blackPen = new Pen(Color.Black, 1);
174+
var directBitmap = DirectBitmap.GetInstance(bitmap);
175+
176+
WarmUpDrawing(bitmap, blackPen, directBitmap);
177+
178+
var graphicsTime = MeasurePerformance(iterations, () =>
179+
{
180+
using var graphics = Graphics.FromImage(bitmap);
181+
graphics.DrawLine(blackPen, 0, 0, 0, imageSize);
182+
});
183+
184+
var directBitmapTime = MeasurePerformance(iterations, () =>
185+
directBitmap.DrawVerticalLine(0, 0, imageSize, Color.Black));
186+
187+
Assert.IsTrue(directBitmapTime <= graphicsTime,
188+
$"DirectBitmap slower: {directBitmapTime}ms vs {graphicsTime}ms");
189+
}
190+
199191
[TestMethod]
200192
public void TestBytesConversion()
201193
{
@@ -220,7 +212,7 @@ public void TestBytesConversion()
220212
}
221213

222214
/// <summary>
223-
/// Warms up drawing.
215+
/// Warms up drawing.
224216
/// </summary>
225217
/// <param name="bitmap">The bitmap.</param>
226218
/// <param name="blackPen">The black pen.</param>
@@ -236,7 +228,7 @@ private static void WarmUpDrawing(Image bitmap, Pen blackPen, DirectBitmap direc
236228
}
237229

238230
/// <summary>
239-
/// Measures the performance.
231+
/// Measures the performance.
240232
/// </summary>
241233
/// <param name="iterations">The iterations.</param>
242234
/// <param name="action">The action.</param>
@@ -248,13 +240,12 @@ private static double MeasurePerformance(int iterations, Action action)
248240
{
249241
action();
250242
}
251-
252243
stopwatch.Stop();
253244
return stopwatch.Elapsed.TotalMilliseconds;
254245
}
255246

256247
/// <summary>
257-
/// Verifies the colors match.
248+
/// Verifies the colors match.
258249
/// </summary>
259250
/// <param name="source">The source.</param>
260251
/// <param name="target">The target.</param>
@@ -263,40 +254,63 @@ private static void VerifyColorsMatch(Bitmap source, DirectBitmap target, params
263254
{
264255
foreach (var (x, y) in coordinates)
265256
{
266-
Assert.AreEqual(source.GetPixel(x, y).ToArgb(), target.Bits[(y * source.Width) + x]);
257+
uint expected = PixelToUintC(source.GetPixel(x, y));
258+
uint actual = PixelToUint(target.Bits[(y * source.Width) + x]);
259+
Assert.AreEqual(expected, actual, $"Pixel mismatch at ({x},{y})");
267260
}
268261
}
269262

270263
/// <summary>
271-
/// Applies the replacement colors.
264+
/// Applies the replacement colors.
272265
/// </summary>
273266
/// <param name="bitmap">The bitmap.</param>
274267
/// <param name="color">The color.</param>
275268
/// <param name="coordinates">The coordinates.</param>
276-
private static void ApplyReplacementColors(DirectBitmap bitmap, Color color,
277-
params (int x, int y)[] coordinates)
269+
private static void ApplyReplacementColors(DirectBitmap bitmap, Color color, params (int x, int y)[] coordinates)
278270
{
271+
var pixel = new Pixel32(color.R, color.G, color.B, color.A);
279272
foreach (var (x, y) in coordinates)
280273
{
281-
bitmap.Bits[(y * bitmap.Width) + x] = color.ToArgb();
274+
bitmap.Bits[(y * bitmap.Width) + x] = pixel;
282275
}
283276
}
284277

285278
/// <summary>
286-
/// Verifies the replacement colors.
279+
/// Verifies the replacement colors.
287280
/// </summary>
288281
/// <param name="bitmap">The bitmap.</param>
289282
/// <param name="target">The target.</param>
290283
/// <param name="color">The color.</param>
291284
/// <param name="coordinates">The coordinates.</param>
292-
private static void VerifyReplacementColors(Bitmap bitmap, DirectBitmap target, Color color,
293-
params (int x, int y)[] coordinates)
285+
private static void VerifyReplacementColors(Bitmap bitmap, DirectBitmap target, Color color, params (int x, int y)[] coordinates)
294286
{
287+
uint expected = PixelToUintC(color);
295288
foreach (var (x, y) in coordinates)
296289
{
297-
Assert.AreEqual(color.ToArgb(), bitmap.GetPixel(x, y).ToArgb());
298-
Assert.AreEqual(color.ToArgb(), target.Bits[(y * bitmap.Width) + x]);
290+
Assert.AreEqual(expected, PixelToUintC(bitmap.GetPixel(x, y)), $"Bitmap pixel mismatch at ({x},{y})");
291+
Assert.AreEqual(expected, PixelToUint(target.Bits[(y * bitmap.Width) + x]), $"DirectBitmap pixel mismatch at ({x},{y})");
299292
}
300293
}
294+
295+
/// <summary>
296+
/// Pixels to uint.
297+
/// </summary>
298+
/// <param name="p">The p.</param>
299+
/// <returns></returns>
300+
private static uint PixelToUint(Pixel32 p)
301+
{
302+
return ((uint)p.A << 24) | ((uint)p.R << 16) | ((uint)p.G << 8) | p.B;
303+
}
304+
305+
/// <summary>
306+
/// Pixels to uint c.
307+
/// </summary>
308+
/// <param name="c">The c.</param>
309+
/// <returns></returns>
310+
private static uint PixelToUintC(Color c)
311+
{
312+
return ((uint)c.A << 24) | ((uint)c.R << 16) | ((uint)c.G << 8) | c.B;
313+
}
301314
}
302315
}
316+

ImageCompare/AnalysisProcessing.cs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -227,35 +227,33 @@ internal static Dictionary<Color, int> GetColors(Bitmap image)
227227
/// </summary>
228228
/// <param name="first">The first bitmap.</param>
229229
/// <param name="second">The second bitmap.</param>
230-
/// <param name="color">The color.</param>
230+
/// <param name="highlight">The color.</param>
231231
/// <returns>The difference Bitmap</returns>
232-
internal static Bitmap DifferenceImage(Bitmap first, Bitmap second, Color color)
232+
internal static Bitmap DifferenceImage(Bitmap first, Bitmap second, Color highlight)
233233
{
234234
_render = new ImageRender();
235235

236-
var width = Math.Min(first.Width, second.Width);
237-
var height = Math.Min(first.Height, second.Height);
236+
int width = Math.Min(first.Width, second.Width);
237+
int height = Math.Min(first.Height, second.Height);
238238

239239
var canvas = _render.CutBitmap(first, 0, 0, height, width);
240240

241241
using var dbmCanvas = new DirectBitmap(canvas);
242242
using var dbmCompare = new DirectBitmap(second);
243243

244-
// Access the pixel arrays directly for comparison
245-
var canvasPixels = dbmCanvas.Bits;
246-
var comparePixels = dbmCompare.Bits;
247-
var colorArgb = color.ToArgb();
244+
var canvasPixels = dbmCanvas.Bits; // Pixel32[]
245+
var comparePixels = dbmCompare.Bits; // Pixel32[]
246+
var highlightPixel = new Pixel32(highlight.R, highlight.G, highlight.B, highlight.A);
248247

249-
// Process the pixels in parallel
250-
_ = Parallel.For(0, height, y =>
248+
Parallel.For(0, height, y =>
251249
{
252-
var offset = y * width;
253-
for (var x = 0; x < width; x++)
250+
int offset = y * width;
251+
for (int x = 0; x < width; x++)
254252
{
255-
var index = offset + x;
256-
if (canvasPixels[index] != comparePixels[index])
253+
int index = offset + x;
254+
if (!Pixel32.AreEqual(canvasPixels[index], comparePixels[index]))
257255
{
258-
canvasPixels[index] = colorArgb;
256+
canvasPixels[index] = highlightPixel;
259257
}
260258
}
261259
});

0 commit comments

Comments
 (0)