Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c3feb6c
fix some ImageSharp color casting
ikkyuland Jul 10, 2025
2d2f799
implement lazyload and overhaul Tiff
ikkyuland Jul 11, 2025
0e127c4
[DW-34] optimize OpenTiffToImageSharp
ikkyuland Jul 12, 2025
3653403
add DW_34_ShouldNotThrowOutOfMemory
ikkyuland Jul 12, 2025
7d6dbc2
[DW-34] add dynamic treshold (.net6+)
ikkyuland Jul 12, 2025
9b74625
reduce iteration of DW_34_ShouldNotThrowOutOfMemory
ikkyuland Jul 12, 2025
5d4086d
[DW-34] optimize GetRGBBuffer by not cast Pixel to Color
ikkyuland Jul 14, 2025
1604c4f
[DW-34] also lazy load Binary
ikkyuland Jul 14, 2025
fb2b8d2
[DW-34] add GetRGBABuffer
ikkyuland Jul 14, 2025
36a8617
[DW-34] use IEnumerable<Image>
ikkyuland Jul 15, 2025
aa9642e
[DW-34] fix GetRGBABuffer and add TestGetRGBABuffer
ikkyuland Jul 15, 2025
f4553a1
optimize RotateFlip, Redact and remove OpenGifToImageSharp
ikkyuland Jul 15, 2025
2a8617d
[DW-34] optimize InternalLoadTiff
ikkyuland Jul 16, 2025
ff49954
[DW-34] always use BmpEncoder
ikkyuland Jul 16, 2025
9e328e4
fix export gif and add tests
ikkyuland Jul 16, 2025
69c3279
catch Width Height BitsPerPixel value for faster operation
ikkyuland Aug 4, 2025
3b1e95e
disable LoadTest1
ikkyuland Aug 4, 2025
11dae53
cache frameCount
ikkyuland Aug 6, 2025
09e572f
[DW-34] optimize ImageSharp casting
ikkyuland Aug 6, 2025
44dcbb4
Binary Thread Safety
ikkyuland Aug 8, 2025
4c55ed7
use _lazyImage?
ikkyuland Aug 8, 2025
347fa9f
optimize (WIP)
ikkyuland Aug 8, 2025
a390fc6
make GetTiffFrameCountFast also count Thumbnail since ImageSharp cann…
ikkyuland Aug 11, 2025
9266321
remove unused LoadTest1()
ikkyuland Aug 11, 2025
7c823bf
fix tryWithLibTiff logic
ikkyuland Aug 11, 2025
b1e1340
improve readability
ikkyuland Aug 11, 2025
248e645
fixed image loaded while Disposing
ikkyuland Aug 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,14 @@ public void Create_AnyBitmap_by_Filename()
string imagePath = GetRelativeFilePath("Mona-Lisa-oil-wood-panel-Leonardo-da.webp");

var bitmap = AnyBitmap.FromFile(imagePath);
bitmap.IsImageLoaded().Should().BeFalse();

bitmap.SaveAs("result.bmp");

bitmap.IsImageLoaded().Should().BeTrue();
//should still be the original bytes
bitmap.Length.Should().Be((int)new FileInfo(imagePath).Length);

Assert.Equal(671, bitmap.Width);
Assert.Equal(1000, bitmap.Height);
Assert.Equal(74684, bitmap.Length);
Expand All @@ -47,7 +54,14 @@ public void Create_AnyBitmap_by_Byte()
byte[] bytes = File.ReadAllBytes(imagePath);

var bitmap = AnyBitmap.FromBytes(bytes);
bitmap.IsImageLoaded().Should().BeFalse();

_ = bitmap.TrySaveAs("result.bmp");

bitmap.IsImageLoaded().Should().BeTrue();
//should still be the original bytes
bitmap.Length.Should().Be(bytes.Length);

AssertImageAreEqual(imagePath, "result.bmp");

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

var bitmap = AnyBitmap.FromStream(ms);
bitmap.IsImageLoaded().Should().BeFalse();

_ = bitmap.TrySaveAs("result.bmp");

bitmap.IsImageLoaded().Should().BeTrue();
//should still be the original bytes
bitmap.Length.Should().Be(bytes.Length);

AssertImageAreEqual(imagePath, "result.bmp");

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

var bitmap = AnyBitmap.FromStream(ms);
bitmap.IsImageLoaded().Should().BeFalse();

_ = bitmap.TrySaveAs("result.bmp");

bitmap.IsImageLoaded().Should().BeTrue();
//should still be the original bytes
bitmap.Length.Should().Be(bytes.Length);

AssertImageAreEqual(imagePath, "result.bmp");

bitmap = new AnyBitmap(ms);
bitmap.SaveAs("result.bmp");
AssertImageAreEqual(imagePath, "result.bmp");


}

[FactWithAutomaticDisplayName]
Expand Down Expand Up @@ -245,6 +275,16 @@ public void AnyBitmap_should_set_Pixel()

// Check the pixel color has changed
Assert.Equal(bitmap.GetPixel(0, 0), Color.Black);

#if NETFRAMEWORK
//windows only
// SetPixel makes the image dirty so it should update AnyBitmap.Binary value

System.Drawing.Bitmap temp1 = bitmap;
AnyBitmap temp2 = (AnyBitmap)temp1;
Assert.Equal(temp1.GetPixel(0, 0).ToArgb(), System.Drawing.Color.Black.ToArgb());
Assert.Equal(temp2.GetPixel(0, 0), Color.Black);
#endif
}
}

Expand Down Expand Up @@ -427,10 +467,14 @@ public void CastSixLabors_to_AnyBitmap()
AssertImageAreEqual("expected.bmp", "result.bmp", true);
}

[FactWithAutomaticDisplayName]
public void CastSixLabors_from_AnyBitmap()
[TheoryWithAutomaticDisplayName]
[InlineData("mountainclimbers.jpg")]
[InlineData("van-gogh-starry-night-vincent-van-gogh.jpg")]
[InlineData("animated_qr.gif")]
[InlineData("Sample-Tiff-File-download-for-Testing.tiff")]
public void CastSixLabors_from_AnyBitmap(string filename)
{
var anyBitmap = AnyBitmap.FromFile(GetRelativeFilePath("mountainclimbers.jpg"));
var anyBitmap = AnyBitmap.FromFile(GetRelativeFilePath(filename));
Image imgSharp = anyBitmap;

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

[TheoryWithAutomaticDisplayName]
[InlineData("mountainclimbers.jpg")]
[InlineData("van-gogh-starry-night-vincent-van-gogh.jpg")]
[InlineData("animated_qr.gif")]
[InlineData("Sample-Tiff-File-download-for-Testing.tiff")]
public void CastSixLabors_from_AnyBitmap_Rgb24(string filename)
{
var anyBitmap = AnyBitmap.FromFile(GetRelativeFilePath(filename));
Image<Rgb24> imgSharp = anyBitmap;

anyBitmap.SaveAs("expected.bmp");
imgSharp.Save("result.bmp");

AssertImageAreEqual("expected.bmp", "result.bmp", true);
}

[TheoryWithAutomaticDisplayName]
[InlineData("mountainclimbers.jpg")]
[InlineData("van-gogh-starry-night-vincent-van-gogh.jpg")]
[InlineData("animated_qr.gif")]
[InlineData("Sample-Tiff-File-download-for-Testing.tiff")]
public void CastSixLabors_from_AnyBitmap_Rgba32(string filename)
{
var anyBitmap = AnyBitmap.FromFile(GetRelativeFilePath(filename));
Image<Rgba32> imgSharp = anyBitmap;

anyBitmap.SaveAs("expected.bmp");
imgSharp.Save("result.bmp");

AssertImageAreEqual("expected.bmp", "result.bmp", true);
}

[FactWithAutomaticDisplayName]
public void CastBitmap_to_AnyBitmap_using_FromBitmap()
{
Expand Down Expand Up @@ -758,6 +834,25 @@ public void TestGetRGBBuffer()
Assert.Equal(firstPixel.B, buffer[2]);
}

//[FactWithAutomaticDisplayName]
public void TestGetRGBABuffer()
{
string imagePath = GetRelativeFilePath("checkmark.jpg");
using var bitmap = new AnyBitmap(imagePath);
var expectedSize = bitmap.Width * bitmap.Height * 4; // 4 bytes per pixel (RGB)

byte[] buffer = bitmap.GetRGBABuffer();

Assert.Equal(expectedSize, buffer.Length);

// Verify the first pixel's RGB values
var firstPixel = bitmap.GetPixel(0, 0);
Assert.Equal(firstPixel.R, buffer[0]);
Assert.Equal(firstPixel.G, buffer[1]);
Assert.Equal(firstPixel.B, buffer[2]);
Assert.Equal(firstPixel.A, buffer[3]);
}

[FactWithAutomaticDisplayName]
public void Test_LoadFromRGBBuffer()
{
Expand Down Expand Up @@ -822,10 +917,11 @@ public void AnyBitmapShouldReturnCorrectResolutions(string fileName, double expe
{
string imagePath = GetRelativeFilePath(fileName);
var bitmap = AnyBitmap.FromFile(imagePath);
var frames = bitmap.GetAllFrames;
for (int i = 0; i < bitmap.FrameCount; i++)
{
Assert.Equal(expectedHorizontalResolution, bitmap.GetAllFrames.ElementAt(i).HorizontalResolution);
Assert.Equal(expectedVerticalResolution, bitmap.GetAllFrames.ElementAt(i).VerticalResolution);
Assert.Equal(expectedHorizontalResolution, frames.ElementAt(i).HorizontalResolution.Value, 1d);
Assert.Equal(expectedVerticalResolution, frames.ElementAt(i).VerticalResolution.Value, 1d);
}
}

Expand Down Expand Up @@ -980,30 +1076,95 @@ public void CastAnyBitmap_from_SixLabors()
#endif


[IgnoreOnAzureDevopsX86Fact]
public void Load_TiffImage_ShouldNotIncreaseFileSize()
[IgnoreOnAzureDevopsX86Fact]
public void Load_TiffImage_ShouldNotIncreaseFileSize()
{
// Arrange
#if NET6_0_OR_GREATER
double thresholdPercent = 0.15;
#else
double thresholdPercent = 1.5;
#endif
string imagePath = GetRelativeFilePath("test_dw_10.tif");
string outputImagePath = "output.tif";

// Act
var bitmap = new AnyBitmap(imagePath);
bitmap.SaveAs(outputImagePath);
var originalFileSize = new FileInfo(imagePath).Length;
var maxAllowedFileSize = (long)(originalFileSize * (1 + thresholdPercent));
var outputFileSize = new FileInfo(outputImagePath).Length;

// Assert
outputFileSize.Should().BeLessThanOrEqualTo(maxAllowedFileSize);

// Clean up
File.Delete(outputImagePath);
}

[Theory]
[InlineData("DW-26 MultiPageTif120Input.tiff")]
[InlineData("google_large_1500dpi.bmp")]
public void DW_34_ShouldNotThrowOutOfMemory(string filename)
{
// Arrange
#if NET6_0_OR_GREATER
double thresholdPercent = 0.15;
#else
double thresholdPercent = 1.5;
#endif
string imagePath = GetRelativeFilePath("test_dw_10.tif");
string outputImagePath = "output.tif";
string imagePath = GetRelativeFilePath(filename);

// Act
var bitmap = new AnyBitmap(imagePath);
bitmap.SaveAs(outputImagePath);
var originalFileSize = new FileInfo(imagePath).Length;
var maxAllowedFileSize = (long)(originalFileSize * (1 + thresholdPercent));
var outputFileSize = new FileInfo(outputImagePath).Length;
List<AnyBitmap> images = new List<AnyBitmap>();
for (int i = 0; i < 25; i++)
{
var bitmap = new AnyBitmap(imagePath);
images.Add(bitmap);
bitmap.IsImageLoaded().Should().BeFalse();
}

// Assert
outputFileSize.Should().BeLessThanOrEqualTo(maxAllowedFileSize);
images.ForEach(bitmap => bitmap.Dispose());
}

// Clean up
File.Delete(outputImagePath);
//[Fact]
//public void LoadTiff()
//{
// Stopwatch stopWatch = new Stopwatch();
// stopWatch.Start();
// for (int i = 0; i < 25; i++)
// {
// var bitmap = new AnyBitmap("C:\\repo\\IronInternalBenchmarks\\IronOcrBenchmark\\Images\\001_20221121000002_S2123457_EL37.tiff");
// //var c = bitmap.GetPixel(10,10);
// foreach (var item in bitmap.GetAllFrames)
// {
// item.GetRGBBuffer();
// item.ExtractAlphaData();
// }


// }
// stopWatch.Stop();
// // Get the elapsed time as a TimeSpan value.
// TimeSpan ts = stopWatch.Elapsed;
// ts.Should().Be(TimeSpan.FromHours(1));
//}

// [FactWithAutomaticDisplayName]
public void AnyBitmap_ExportGif_Should_Works()
{
string imagePath = GetRelativeFilePath("van-gogh-starry-night-vincent-van-gogh.jpg");
var anyBitmap = AnyBitmap.FromFile(imagePath);

using var resultExport = new MemoryStream();
anyBitmap.ExportStream(resultExport, AnyBitmap.ImageFormat.Gif);
resultExport.Length.Should().NotBe(0);
Image.DetectFormat(resultExport.ToArray()).Should().Be(SixLabors.ImageSharp.Formats.Gif.GifFormat.Instance);
}

// [FactWithAutomaticDisplayName]
public void AnyBitmap_ExportTiff_Should_Works()
{
string imagePath = GetRelativeFilePath("van-gogh-starry-night-vincent-van-gogh.jpg");
var anyBitmap = AnyBitmap.FromFile(imagePath);

using var resultExport = new MemoryStream();
anyBitmap.ExportStream(resultExport, AnyBitmap.ImageFormat.Tiff);
resultExport.Length.Should().NotBe(0);
Image.DetectFormat(resultExport.ToArray()).Should().Be(SixLabors.ImageSharp.Formats.Tiff.TiffFormat.Instance);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,20 +399,20 @@ public void Cast_ImageSharp_Rgb24_to_Color()
[FactWithAutomaticDisplayName]
public void Cast_ImageSharp_Rgb48_from_Color()
{
var imgColor = new SixLabors.ImageSharp.PixelFormats.Rgb48(255, 0, 0);
var imgColor = new SixLabors.ImageSharp.PixelFormats.Rgb48(65535, 0, 0);
Color red = imgColor;
Assert.Equal(255, red.R);
Assert.Equal(0, red.G);
Assert.Equal(0, red.B);

imgColor = new SixLabors.ImageSharp.PixelFormats.Rgb48(0, 255, 0);
imgColor = new SixLabors.ImageSharp.PixelFormats.Rgb48(0, 65535, 0);
Color green = imgColor;
Assert.Equal(255, green.A);
Assert.Equal(0, green.R);
Assert.Equal(255, green.G);
Assert.Equal(0, green.B);

imgColor = new SixLabors.ImageSharp.PixelFormats.Rgb48(0, 0, 255);
imgColor = new SixLabors.ImageSharp.PixelFormats.Rgb48(0, 0, 65535);
Color blue = imgColor;
Assert.Equal(0, blue.R);
Assert.Equal(0, blue.G);
Expand All @@ -423,28 +423,29 @@ public void Cast_ImageSharp_Rgb48_from_Color()
public void Cast_ImageSharp_Rgb48_to_Color()
{
Color color = Color.Red;
//Rgb42 is 16-bit color (0-65535) not (0-255)
SixLabors.ImageSharp.PixelFormats.Rgb48 red = color;
Assert.Equal(255, red.R);
Assert.Equal(65535, red.R);
Assert.Equal(0, red.G);
Assert.Equal(0, red.B);

color = new Color(0, 255, 0);
SixLabors.ImageSharp.PixelFormats.Rgb48 green = color;
Assert.Equal(0, green.R);
Assert.Equal(255, green.G);
Assert.Equal(65535, green.G);
Assert.Equal(0, green.B);

color = new Color("#0000FF");
SixLabors.ImageSharp.PixelFormats.Rgb48 blue = color;
Assert.Equal(0, blue.R);
Assert.Equal(0, blue.G);
Assert.Equal(255, blue.B);
Assert.Equal(65535, blue.B);

color = Color.FromArgb(Convert.ToInt32("1e81b0", 16));
SixLabors.ImageSharp.PixelFormats.Rgb48 imgColor = color;
Assert.Equal(30, imgColor.R);
Assert.Equal(129, imgColor.G);
Assert.Equal(176, imgColor.B);
Assert.Equal(7710, imgColor.R);
Assert.Equal(33153, imgColor.G);
Assert.Equal(45232, imgColor.B);
}

[FactWithAutomaticDisplayName]
Expand All @@ -456,14 +457,14 @@ public void Cast_ImageSharp_Rgba64_from_Color()
Assert.Equal(0, red.G);
Assert.Equal(0, red.B);

imgColor = new SixLabors.ImageSharp.PixelFormats.Rgba64(0, 255, 0, 255);
imgColor = new SixLabors.ImageSharp.PixelFormats.Rgba64(0, 65535, 0, 65535);
Color green = imgColor;
Assert.Equal(255, green.A);
Assert.Equal(0, green.R);
Assert.Equal(255, green.G);
Assert.Equal(0, green.B);

imgColor = new SixLabors.ImageSharp.PixelFormats.Rgba64(0, 0, 255, 255);
imgColor = new SixLabors.ImageSharp.PixelFormats.Rgba64(0, 0, 65535, 65535);
Color blue = imgColor;
Assert.Equal(255, green.A);
Assert.Equal(0, blue.R);
Expand Down
Loading