Skip to content

Commit 77373a9

Browse files
AnyBitmap: Use stream to save image instead of byte[] to fix OutOfMemoryException
`OutOfMemoryException` is causing by the giant array of byte which memory on x86 can't hold it.
1 parent 0b1b8c9 commit 77373a9

3 files changed

Lines changed: 63 additions & 35 deletions

File tree

IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/AnyBitmapFunctionality.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ public void CastAnyBitmap_from_SixLabors()
879879
image.Save("expected.bmp");
880880
anyBitmap.SaveAs("result.bmp");
881881

882-
AssertImageAreEqual("expected.bmp", "result.bmp", true);
882+
AssertLargeImageAreEqual("expected.bmp", "result.bmp", true);
883883
}
884884

885885
}

IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/Compare.cs

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using SixLabors.ImageSharp.PixelFormats;
2+
using SixLabors.ImageSharp.Processing;
23
using System;
34
using System.IO;
45
using System.Linq;
@@ -14,43 +15,74 @@ protected Compare(ITestOutputHelper output) : base(output)
1415
{
1516
}
1617

17-
protected static void AssertImageAreEqual(string expectedImagePath, string resultImagePath, bool isCleanAll = false)
18+
protected static void AssertLargeImageAreEqual(string expectedImagePath, string resultImagePath, bool isCleanAll = false)
1819
{
19-
string assertName = "AssertImage.AreEqual";
20+
using SixLabors.ImageSharp.Image<Rgba32> expectedImageSharp = SixLabors.ImageSharp.Image.Load<Rgba32>(expectedImagePath);
21+
using SixLabors.ImageSharp.Image<Rgba32> actualImageSharp = SixLabors.ImageSharp.Image.Load<Rgba32>(resultImagePath);
2022

21-
var expected = AnyBitmap.FromFile(expectedImagePath);
22-
var actual = AnyBitmap.FromFile(resultImagePath);
23+
CleanCompareResultFile(expectedImagePath, resultImagePath, isCleanAll);
2324

24-
if (isCleanAll)
25-
{
26-
CleanResultFile(expectedImagePath);
27-
}
25+
expectedImageSharp.Mutate(x => x.Resize(100, 100));
26+
actualImageSharp.Mutate(x => x.Resize(100, 100));
2827

29-
CleanResultFile(resultImagePath);
28+
AssertImageAreEqual(expectedImageSharp, actualImageSharp);
29+
}
3030

31-
//Test to see if we have the same size of image
32-
if (expected.Width != actual.Width || expected.Height != actual.Height)
33-
{
34-
throw new AssertActualExpectedException($"Expected:<Height {expected.Height}, Width {expected.Width}>.", $"Actual:<Height {actual.Height},Width {actual.Width}>.", $"{assertName} failed.");
35-
}
31+
protected static void AssertImageAreEqual(string expectedImagePath, string resultImagePath, bool isCleanAll = false)
32+
{
33+
using var expected = AnyBitmap.FromFile(expectedImagePath);
34+
using var actual = AnyBitmap.FromFile(resultImagePath);
3635

37-
//Convert each image to a byte array
38-
byte[] btImageExpected = expected.ExportBytes();
39-
byte[] btImageActual = expected.ExportBytes();
36+
CleanCompareResultFile(expectedImagePath, resultImagePath, isCleanAll);
4037

41-
//Compute a hash for each image
42-
var shaM = SHA256.Create();
43-
byte[] hash1 = shaM.ComputeHash(btImageExpected);
44-
byte[] hash2 = shaM.ComputeHash(btImageActual);
38+
AssertImageAreEqual(expected, actual);
39+
}
4540

46-
//Compare the hash values
47-
for (int i = 0; i < hash1.Length && i < hash2.Length; i++)
41+
protected static void AssertImageAreEqual(AnyBitmap expected, AnyBitmap actual)
42+
{
43+
try
4844
{
49-
if (hash1[i] != hash2[i])
45+
string assertName = "AssertImage.AreEqual";
46+
47+
//Test to see if we have the same size of image
48+
if (expected.Width != actual.Width || expected.Height != actual.Height)
5049
{
51-
throw new AssertActualExpectedException($"Expected:<hash value {hash1[i]}>.", $"Actual:<hash value {hash2[i]}>.", $"{assertName} failed.");
50+
throw new AssertActualExpectedException($"Expected:<Height {expected.Height}, Width {expected.Width}>.", $"Actual:<Height {actual.Height},Width {actual.Width}>.", $"{assertName} failed.");
5251
}
52+
53+
//Convert each image to a byte array
54+
byte[] btImageExpected = expected.ExportBytes();
55+
byte[] btImageActual = expected.ExportBytes();
56+
57+
//Compute a hash for each image
58+
var shaM = SHA256.Create();
59+
byte[] hash1 = shaM.ComputeHash(btImageExpected);
60+
byte[] hash2 = shaM.ComputeHash(btImageActual);
61+
62+
//Compare the hash values
63+
for (int i = 0; i < hash1.Length && i < hash2.Length; i++)
64+
{
65+
if (hash1[i] != hash2[i])
66+
{
67+
throw new AssertActualExpectedException($"Expected:<hash value {hash1[i]}>.", $"Actual:<hash value {hash2[i]}>.", $"{assertName} failed.");
68+
}
69+
}
70+
}
71+
finally
72+
{
73+
expected?.Dispose();
74+
actual?.Dispose();
75+
}
76+
}
77+
78+
private static void CleanCompareResultFile(string expectedImagePath, string resultImagePath, bool isCleanAll)
79+
{
80+
if (isCleanAll)
81+
{
82+
CleanResultFile(expectedImagePath);
5383
}
84+
85+
CleanResultFile(resultImagePath);
5486
}
5587

5688
protected static void CleanResultFile(string filename)
@@ -60,6 +92,7 @@ protected static void CleanResultFile(string filename)
6092
File.Delete(filename);
6193
}
6294
}
95+
6396
protected static void AssertStreamAreEqual(MemoryStream expected, MemoryStream actual)
6497
{
6598
string assertName = "AssertStream.AreEqual";

IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ public AnyBitmap Clone(Rectangle rectangle)
174174
public byte[] ExportBytes(
175175
ImageFormat format = ImageFormat.Default, int lossy = 100)
176176
{
177-
MemoryStream mem = new();
177+
using MemoryStream mem = new();
178178
ExportStream(mem, format, lossy);
179179
byte[] byteArray = mem.ToArray();
180180

@@ -202,13 +202,7 @@ public void ExportFile(
202202
ImageFormat format = ImageFormat.Default,
203203
int lossy = 100)
204204
{
205-
using (MemoryStream mem = new())
206-
{
207-
ExportStream(mem, format, lossy);
208-
byte[] byteArray = mem.ToArray();
209-
210-
File.WriteAllBytes(file, byteArray);
211-
}
205+
SaveAs(file, format, lossy);
212206
}
213207

214208
/// <summary>
@@ -346,7 +340,8 @@ public void SaveAs(string file)
346340
/// <seealso cref="TrySaveAs(string)"/>
347341
public void SaveAs(string file, ImageFormat format, int lossy = 100)
348342
{
349-
File.WriteAllBytes(file, ExportBytes(format, lossy));
343+
using var fileStream = new FileStream(file, FileMode.Create);
344+
ExportStream(fileStream, format, lossy);
350345
}
351346

352347
/// <summary>

0 commit comments

Comments
 (0)