Skip to content

Commit 2733819

Browse files
Merge pull request #136 from iron-software/DW-34-lazy-load-anybitmap
[DW-34] lazy load AnyBitmap & improve Tiff processing
2 parents 42dfdf6 + 248e645 commit 2733819

File tree

6 files changed

+1696
-730
lines changed

6 files changed

+1696
-730
lines changed

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

Lines changed: 186 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,14 @@ public void Create_AnyBitmap_by_Filename()
2626
string imagePath = GetRelativeFilePath("Mona-Lisa-oil-wood-panel-Leonardo-da.webp");
2727

2828
var bitmap = AnyBitmap.FromFile(imagePath);
29+
bitmap.IsImageLoaded().Should().BeFalse();
30+
2931
bitmap.SaveAs("result.bmp");
32+
33+
bitmap.IsImageLoaded().Should().BeTrue();
34+
//should still be the original bytes
35+
bitmap.Length.Should().Be((int)new FileInfo(imagePath).Length);
36+
3037
Assert.Equal(671, bitmap.Width);
3138
Assert.Equal(1000, bitmap.Height);
3239
Assert.Equal(74684, bitmap.Length);
@@ -47,7 +54,14 @@ public void Create_AnyBitmap_by_Byte()
4754
byte[] bytes = File.ReadAllBytes(imagePath);
4855

4956
var bitmap = AnyBitmap.FromBytes(bytes);
57+
bitmap.IsImageLoaded().Should().BeFalse();
58+
5059
_ = bitmap.TrySaveAs("result.bmp");
60+
61+
bitmap.IsImageLoaded().Should().BeTrue();
62+
//should still be the original bytes
63+
bitmap.Length.Should().Be(bytes.Length);
64+
5165
AssertImageAreEqual(imagePath, "result.bmp");
5266

5367
bitmap = new AnyBitmap(bytes);
@@ -63,7 +77,14 @@ public void Create_AnyBitmap_by_Stream()
6377
Stream ms = new MemoryStream(bytes);
6478

6579
var bitmap = AnyBitmap.FromStream(ms);
80+
bitmap.IsImageLoaded().Should().BeFalse();
81+
6682
_ = bitmap.TrySaveAs("result.bmp");
83+
84+
bitmap.IsImageLoaded().Should().BeTrue();
85+
//should still be the original bytes
86+
bitmap.Length.Should().Be(bytes.Length);
87+
6788
AssertImageAreEqual(imagePath, "result.bmp");
6889

6990
ms.Position = 0;
@@ -80,12 +101,21 @@ public void Create_AnyBitmap_by_MemoryStream()
80101
var ms = new MemoryStream(bytes);
81102

82103
var bitmap = AnyBitmap.FromStream(ms);
104+
bitmap.IsImageLoaded().Should().BeFalse();
105+
83106
_ = bitmap.TrySaveAs("result.bmp");
107+
108+
bitmap.IsImageLoaded().Should().BeTrue();
109+
//should still be the original bytes
110+
bitmap.Length.Should().Be(bytes.Length);
111+
84112
AssertImageAreEqual(imagePath, "result.bmp");
85113

86114
bitmap = new AnyBitmap(ms);
87115
bitmap.SaveAs("result.bmp");
88116
AssertImageAreEqual(imagePath, "result.bmp");
117+
118+
89119
}
90120

91121
[FactWithAutomaticDisplayName]
@@ -245,6 +275,16 @@ public void AnyBitmap_should_set_Pixel()
245275

246276
// Check the pixel color has changed
247277
Assert.Equal(bitmap.GetPixel(0, 0), Color.Black);
278+
279+
#if NETFRAMEWORK
280+
//windows only
281+
// SetPixel makes the image dirty so it should update AnyBitmap.Binary value
282+
283+
System.Drawing.Bitmap temp1 = bitmap;
284+
AnyBitmap temp2 = (AnyBitmap)temp1;
285+
Assert.Equal(temp1.GetPixel(0, 0).ToArgb(), System.Drawing.Color.Black.ToArgb());
286+
Assert.Equal(temp2.GetPixel(0, 0), Color.Black);
287+
#endif
248288
}
249289
}
250290

@@ -427,10 +467,14 @@ public void CastSixLabors_to_AnyBitmap()
427467
AssertImageAreEqual("expected.bmp", "result.bmp", true);
428468
}
429469

430-
[FactWithAutomaticDisplayName]
431-
public void CastSixLabors_from_AnyBitmap()
470+
[TheoryWithAutomaticDisplayName]
471+
[InlineData("mountainclimbers.jpg")]
472+
[InlineData("van-gogh-starry-night-vincent-van-gogh.jpg")]
473+
[InlineData("animated_qr.gif")]
474+
[InlineData("Sample-Tiff-File-download-for-Testing.tiff")]
475+
public void CastSixLabors_from_AnyBitmap(string filename)
432476
{
433-
var anyBitmap = AnyBitmap.FromFile(GetRelativeFilePath("mountainclimbers.jpg"));
477+
var anyBitmap = AnyBitmap.FromFile(GetRelativeFilePath(filename));
434478
Image imgSharp = anyBitmap;
435479

436480
anyBitmap.SaveAs("expected.bmp");
@@ -439,6 +483,38 @@ public void CastSixLabors_from_AnyBitmap()
439483
AssertImageAreEqual("expected.bmp", "result.bmp", true);
440484
}
441485

486+
[TheoryWithAutomaticDisplayName]
487+
[InlineData("mountainclimbers.jpg")]
488+
[InlineData("van-gogh-starry-night-vincent-van-gogh.jpg")]
489+
[InlineData("animated_qr.gif")]
490+
[InlineData("Sample-Tiff-File-download-for-Testing.tiff")]
491+
public void CastSixLabors_from_AnyBitmap_Rgb24(string filename)
492+
{
493+
var anyBitmap = AnyBitmap.FromFile(GetRelativeFilePath(filename));
494+
Image<Rgb24> imgSharp = anyBitmap;
495+
496+
anyBitmap.SaveAs("expected.bmp");
497+
imgSharp.Save("result.bmp");
498+
499+
AssertImageAreEqual("expected.bmp", "result.bmp", true);
500+
}
501+
502+
[TheoryWithAutomaticDisplayName]
503+
[InlineData("mountainclimbers.jpg")]
504+
[InlineData("van-gogh-starry-night-vincent-van-gogh.jpg")]
505+
[InlineData("animated_qr.gif")]
506+
[InlineData("Sample-Tiff-File-download-for-Testing.tiff")]
507+
public void CastSixLabors_from_AnyBitmap_Rgba32(string filename)
508+
{
509+
var anyBitmap = AnyBitmap.FromFile(GetRelativeFilePath(filename));
510+
Image<Rgba32> imgSharp = anyBitmap;
511+
512+
anyBitmap.SaveAs("expected.bmp");
513+
imgSharp.Save("result.bmp");
514+
515+
AssertImageAreEqual("expected.bmp", "result.bmp", true);
516+
}
517+
442518
[FactWithAutomaticDisplayName]
443519
public void CastBitmap_to_AnyBitmap_using_FromBitmap()
444520
{
@@ -758,6 +834,25 @@ public void TestGetRGBBuffer()
758834
Assert.Equal(firstPixel.B, buffer[2]);
759835
}
760836

837+
//[FactWithAutomaticDisplayName]
838+
public void TestGetRGBABuffer()
839+
{
840+
string imagePath = GetRelativeFilePath("checkmark.jpg");
841+
using var bitmap = new AnyBitmap(imagePath);
842+
var expectedSize = bitmap.Width * bitmap.Height * 4; // 4 bytes per pixel (RGB)
843+
844+
byte[] buffer = bitmap.GetRGBABuffer();
845+
846+
Assert.Equal(expectedSize, buffer.Length);
847+
848+
// Verify the first pixel's RGB values
849+
var firstPixel = bitmap.GetPixel(0, 0);
850+
Assert.Equal(firstPixel.R, buffer[0]);
851+
Assert.Equal(firstPixel.G, buffer[1]);
852+
Assert.Equal(firstPixel.B, buffer[2]);
853+
Assert.Equal(firstPixel.A, buffer[3]);
854+
}
855+
761856
[FactWithAutomaticDisplayName]
762857
public void Test_LoadFromRGBBuffer()
763858
{
@@ -822,10 +917,11 @@ public void AnyBitmapShouldReturnCorrectResolutions(string fileName, double expe
822917
{
823918
string imagePath = GetRelativeFilePath(fileName);
824919
var bitmap = AnyBitmap.FromFile(imagePath);
920+
var frames = bitmap.GetAllFrames;
825921
for (int i = 0; i < bitmap.FrameCount; i++)
826922
{
827-
Assert.Equal(expectedHorizontalResolution, bitmap.GetAllFrames.ElementAt(i).HorizontalResolution);
828-
Assert.Equal(expectedVerticalResolution, bitmap.GetAllFrames.ElementAt(i).VerticalResolution);
923+
Assert.Equal(expectedHorizontalResolution, frames.ElementAt(i).HorizontalResolution.Value, 1d);
924+
Assert.Equal(expectedVerticalResolution, frames.ElementAt(i).VerticalResolution.Value, 1d);
829925
}
830926
}
831927

@@ -980,30 +1076,95 @@ public void CastAnyBitmap_from_SixLabors()
9801076
#endif
9811077

9821078

983-
[IgnoreOnAzureDevopsX86Fact]
984-
public void Load_TiffImage_ShouldNotIncreaseFileSize()
1079+
[IgnoreOnAzureDevopsX86Fact]
1080+
public void Load_TiffImage_ShouldNotIncreaseFileSize()
1081+
{
1082+
// Arrange
1083+
#if NET6_0_OR_GREATER
1084+
double thresholdPercent = 0.15;
1085+
#else
1086+
double thresholdPercent = 1.5;
1087+
#endif
1088+
string imagePath = GetRelativeFilePath("test_dw_10.tif");
1089+
string outputImagePath = "output.tif";
1090+
1091+
// Act
1092+
var bitmap = new AnyBitmap(imagePath);
1093+
bitmap.SaveAs(outputImagePath);
1094+
var originalFileSize = new FileInfo(imagePath).Length;
1095+
var maxAllowedFileSize = (long)(originalFileSize * (1 + thresholdPercent));
1096+
var outputFileSize = new FileInfo(outputImagePath).Length;
1097+
1098+
// Assert
1099+
outputFileSize.Should().BeLessThanOrEqualTo(maxAllowedFileSize);
1100+
1101+
// Clean up
1102+
File.Delete(outputImagePath);
1103+
}
1104+
1105+
[Theory]
1106+
[InlineData("DW-26 MultiPageTif120Input.tiff")]
1107+
[InlineData("google_large_1500dpi.bmp")]
1108+
public void DW_34_ShouldNotThrowOutOfMemory(string filename)
9851109
{
986-
// Arrange
987-
#if NET6_0_OR_GREATER
988-
double thresholdPercent = 0.15;
989-
#else
990-
double thresholdPercent = 1.5;
991-
#endif
992-
string imagePath = GetRelativeFilePath("test_dw_10.tif");
993-
string outputImagePath = "output.tif";
1110+
string imagePath = GetRelativeFilePath(filename);
9941111

995-
// Act
996-
var bitmap = new AnyBitmap(imagePath);
997-
bitmap.SaveAs(outputImagePath);
998-
var originalFileSize = new FileInfo(imagePath).Length;
999-
var maxAllowedFileSize = (long)(originalFileSize * (1 + thresholdPercent));
1000-
var outputFileSize = new FileInfo(outputImagePath).Length;
1112+
List<AnyBitmap> images = new List<AnyBitmap>();
1113+
for (int i = 0; i < 25; i++)
1114+
{
1115+
var bitmap = new AnyBitmap(imagePath);
1116+
images.Add(bitmap);
1117+
bitmap.IsImageLoaded().Should().BeFalse();
1118+
}
10011119

1002-
// Assert
1003-
outputFileSize.Should().BeLessThanOrEqualTo(maxAllowedFileSize);
1120+
images.ForEach(bitmap => bitmap.Dispose());
1121+
}
10041122

1005-
// Clean up
1006-
File.Delete(outputImagePath);
1123+
//[Fact]
1124+
//public void LoadTiff()
1125+
//{
1126+
// Stopwatch stopWatch = new Stopwatch();
1127+
// stopWatch.Start();
1128+
// for (int i = 0; i < 25; i++)
1129+
// {
1130+
// var bitmap = new AnyBitmap("C:\\repo\\IronInternalBenchmarks\\IronOcrBenchmark\\Images\\001_20221121000002_S2123457_EL37.tiff");
1131+
// //var c = bitmap.GetPixel(10,10);
1132+
// foreach (var item in bitmap.GetAllFrames)
1133+
// {
1134+
// item.GetRGBBuffer();
1135+
// item.ExtractAlphaData();
1136+
// }
1137+
1138+
1139+
// }
1140+
// stopWatch.Stop();
1141+
// // Get the elapsed time as a TimeSpan value.
1142+
// TimeSpan ts = stopWatch.Elapsed;
1143+
// ts.Should().Be(TimeSpan.FromHours(1));
1144+
//}
1145+
1146+
// [FactWithAutomaticDisplayName]
1147+
public void AnyBitmap_ExportGif_Should_Works()
1148+
{
1149+
string imagePath = GetRelativeFilePath("van-gogh-starry-night-vincent-van-gogh.jpg");
1150+
var anyBitmap = AnyBitmap.FromFile(imagePath);
1151+
1152+
using var resultExport = new MemoryStream();
1153+
anyBitmap.ExportStream(resultExport, AnyBitmap.ImageFormat.Gif);
1154+
resultExport.Length.Should().NotBe(0);
1155+
Image.DetectFormat(resultExport.ToArray()).Should().Be(SixLabors.ImageSharp.Formats.Gif.GifFormat.Instance);
1156+
}
1157+
1158+
// [FactWithAutomaticDisplayName]
1159+
public void AnyBitmap_ExportTiff_Should_Works()
1160+
{
1161+
string imagePath = GetRelativeFilePath("van-gogh-starry-night-vincent-van-gogh.jpg");
1162+
var anyBitmap = AnyBitmap.FromFile(imagePath);
1163+
1164+
using var resultExport = new MemoryStream();
1165+
anyBitmap.ExportStream(resultExport, AnyBitmap.ImageFormat.Tiff);
1166+
resultExport.Length.Should().NotBe(0);
1167+
Image.DetectFormat(resultExport.ToArray()).Should().Be(SixLabors.ImageSharp.Formats.Tiff.TiffFormat.Instance);
10071168
}
10081169

10091170
}

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

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -418,20 +418,20 @@ public void Cast_ImageSharp_Rgb24_to_Color()
418418
[FactWithAutomaticDisplayName]
419419
public void Cast_ImageSharp_Rgb48_from_Color()
420420
{
421-
var imgColor = new SixLabors.ImageSharp.PixelFormats.Rgb48(255, 0, 0);
421+
var imgColor = new SixLabors.ImageSharp.PixelFormats.Rgb48(65535, 0, 0);
422422
Color red = imgColor;
423423
Assert.Equal(255, red.R);
424424
Assert.Equal(0, red.G);
425425
Assert.Equal(0, red.B);
426426

427-
imgColor = new SixLabors.ImageSharp.PixelFormats.Rgb48(0, 255, 0);
427+
imgColor = new SixLabors.ImageSharp.PixelFormats.Rgb48(0, 65535, 0);
428428
Color green = imgColor;
429429
Assert.Equal(255, green.A);
430430
Assert.Equal(0, green.R);
431431
Assert.Equal(255, green.G);
432432
Assert.Equal(0, green.B);
433433

434-
imgColor = new SixLabors.ImageSharp.PixelFormats.Rgb48(0, 0, 255);
434+
imgColor = new SixLabors.ImageSharp.PixelFormats.Rgb48(0, 0, 65535);
435435
Color blue = imgColor;
436436
Assert.Equal(0, blue.R);
437437
Assert.Equal(0, blue.G);
@@ -442,28 +442,29 @@ public void Cast_ImageSharp_Rgb48_from_Color()
442442
public void Cast_ImageSharp_Rgb48_to_Color()
443443
{
444444
Color color = Color.Red;
445+
//Rgb42 is 16-bit color (0-65535) not (0-255)
445446
SixLabors.ImageSharp.PixelFormats.Rgb48 red = color;
446-
Assert.Equal(255, red.R);
447+
Assert.Equal(65535, red.R);
447448
Assert.Equal(0, red.G);
448449
Assert.Equal(0, red.B);
449450

450451
color = new Color(0, 255, 0);
451452
SixLabors.ImageSharp.PixelFormats.Rgb48 green = color;
452453
Assert.Equal(0, green.R);
453-
Assert.Equal(255, green.G);
454+
Assert.Equal(65535, green.G);
454455
Assert.Equal(0, green.B);
455456

456457
color = new Color("#0000FF");
457458
SixLabors.ImageSharp.PixelFormats.Rgb48 blue = color;
458459
Assert.Equal(0, blue.R);
459460
Assert.Equal(0, blue.G);
460-
Assert.Equal(255, blue.B);
461+
Assert.Equal(65535, blue.B);
461462

462463
color = Color.FromArgb(Convert.ToInt32("1e81b0", 16));
463464
SixLabors.ImageSharp.PixelFormats.Rgb48 imgColor = color;
464-
Assert.Equal(30, imgColor.R);
465-
Assert.Equal(129, imgColor.G);
466-
Assert.Equal(176, imgColor.B);
465+
Assert.Equal(7710, imgColor.R);
466+
Assert.Equal(33153, imgColor.G);
467+
Assert.Equal(45232, imgColor.B);
467468
}
468469

469470
[FactWithAutomaticDisplayName]
@@ -475,14 +476,14 @@ public void Cast_ImageSharp_Rgba64_from_Color()
475476
Assert.Equal(0, red.G);
476477
Assert.Equal(0, red.B);
477478

478-
imgColor = new SixLabors.ImageSharp.PixelFormats.Rgba64(0, 255, 0, 255);
479+
imgColor = new SixLabors.ImageSharp.PixelFormats.Rgba64(0, 65535, 0, 65535);
479480
Color green = imgColor;
480481
Assert.Equal(255, green.A);
481482
Assert.Equal(0, green.R);
482483
Assert.Equal(255, green.G);
483484
Assert.Equal(0, green.B);
484485

485-
imgColor = new SixLabors.ImageSharp.PixelFormats.Rgba64(0, 0, 255, 255);
486+
imgColor = new SixLabors.ImageSharp.PixelFormats.Rgba64(0, 0, 65535, 65535);
486487
Color blue = imgColor;
487488
Assert.Equal(255, green.A);
488489
Assert.Equal(0, blue.R);

0 commit comments

Comments
 (0)