Repository: iron-software/IronSoftware.System.Drawing
Pull request #132: DW-33 Add preserveOriginalFormat bool while loading image
Author: login: kannapat-ironsoftware
Created: 2025-05-13T08:32:35Z | Merged: 2025-05-20T09:43:15Z

### Title
Make sure the title of the PR is descriptive and summarizes the changes made.

### Description
Add an option to determine whether keeping original pixel format or load as `<Rgba32>` while loading image.
This PR aims eliminate the redundancy in IronOcr code base while converting `AnyBitmap` to `Leptonica.Pix`. Tesseract uses `Leptonica.Pix` as an input which require to convert from 32-bit image.

Fixes #(issue number)
[DW-33](https://ironsoftware.atlassian.net/browse/DW-33)
[DW-32](https://ironsoftware.atlassian.net/browse/DW-32)

### Type of change
Please select the relevant option by placing an 'x' inside the brackets, like this: [x].

- [ ] 🐛 Bug fix (non-breaking change which fixes an issue)
- [x] ✨ New feature (non-breaking change which adds functionality)
- [ ] 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [x] 🏗️ Internal/structural update (non-breaking change that improves code quality, organization, or performance)
- [x] 📚 This change requires a documentation update
- [ ] 🚀 DevOps build chain modification for release
- [ ] 🤖 DevOps build chain modification for CI

### How Has This Been Tested?
Add a new unit test and set `preserveOriginalFormat` to both true and false. Then verify the `AnyBitmap.BitsPerPixel`.

### Checklist:
Please run through the checklist as much as possible and mark the items completed by placing an 'x' inside the brackets, like this: [x].

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes
- [x] I have successfully run all unit tests on Windows
- [x] I have successfully run all unit tests on Linux

### Additional Context
Add any other context, screenshots, or information about the pull request here.


[DW-33]: https://ironsoftware.atlassian.net/browse/DW-33?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

[DW-32]: https://ironsoftware.atlassian.net/browse/DW-32?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ


Diff:
diff --git a/CI/job_templates/test_drawing_libraries.yml b/CI/job_templates/test_drawing_libraries.yml
index ac8c71e..d6a6b42 100644
--- a/CI/job_templates/test_drawing_libraries.yml
+++ b/CI/job_templates/test_drawing_libraries.yml
@@ -20,6 +20,14 @@ jobs:
         buildType: 'current'
         artifactName: 'IronDrawingDataTests'
         targetPath: '$(Agent.BuildDirectory)/Data'
+    - ${{ if or(eq(parameters.OSPlatform, 'Ubuntu'), eq(parameters.OSPlatform, 'Linux')) }}:
+      - task: Bash@3        
+        displayName: 'Install GDI+ dependencies'
+        inputs:
+          targetType: 'inline'
+          script: |
+            sudo apt-get update
+            sudo apt-get install -y libgdiplus libc6-dev
     - ${{ if eq(parameters.framework, 'netcoreapp3.1') }}:
       - task: UseDotNet@2
         displayName: 'Install .Netcoreapp3.1 Core sdk'
diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/AnyBitmapFunctionality.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/AnyBitmapFunctionality.cs
index b563d9b..83f30a5 100644
--- a/IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/AnyBitmapFunctionality.cs
+++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/AnyBitmapFunctionality.cs
@@ -942,6 +942,26 @@ public void LoadImage_TiffImage_ShouldLoadWithoutThumbnail()
             bitmap.FrameCount.Should().Be(1);
         }
 
+        [TheoryWithAutomaticDisplayName]
+        [InlineData("24_bit.png")]
+        [InlineData("checkmark.jpg")]
+        [InlineData("DW-26 Jpg72Input.jpg")]
+        [InlineData("DW-26 Jpg300Input.jpg")]
+        [InlineData("mountainclimbers.jpg")]
+        public void LoadImage_SetPreserveOriginalFormat_ShouldReturnCorrectBitPerPixel(string imageFileName)
+        {
+            // Arrange
+            string imagePath = GetRelativeFilePath(imageFileName);
+
+            // Act
+            var preserve = new AnyBitmap(imagePath, true);
+            var notPreserve = new AnyBitmap(imagePath, false);
+
+            // Assert
+            Assert.Equal(24, preserve.BitsPerPixel);
+            Assert.Equal(32, notPreserve.BitsPerPixel);
+        }
+
 #if !NET7_0
         [FactWithAutomaticDisplayName]
         public void CastAnyBitmap_from_SixLabors()
diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs
index 94503d4..5f3a22d 100644
--- a/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs
+++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs
@@ -52,6 +52,7 @@ public partial class AnyBitmap : IDisposable, IAnyImage
         private byte[] Binary { get; set; }
         private IImageFormat Format { get; set; }
         private TiffCompression TiffCompression { get; set; } = TiffCompression.Lzw;
+        private bool PreserveOriginalFormat { get; set; } = true;
 
         /// <summary>
         /// Width of the image.
@@ -138,7 +139,7 @@ public MemoryStream GetStream()
         /// <returns></returns>
         public AnyBitmap Clone()
         {
-            return new AnyBitmap(Binary);
+            return new AnyBitmap(Binary, PreserveOriginalFormat);
         }
 
         /// <summary>
@@ -462,87 +463,99 @@ public T ToBitmap<T>()
         /// Create a new Bitmap from a a Byte Span.
         /// </summary>
         /// <param name="span">A Byte Span of image data in any common format.</param>
-        public static AnyBitmap FromSpan(ReadOnlySpan<byte> span)
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
+        public static AnyBitmap FromSpan(ReadOnlySpan<byte> span, bool preserveOriginalFormat = true)
         {
-            return new AnyBitmap(span);
+            return new AnyBitmap(span, preserveOriginalFormat);
         }
 
         /// <summary>
         /// Create a new Bitmap from a a Byte Array.
         /// </summary>
         /// <param name="bytes">A ByteArray of image data in any common format.</param>
-        public static AnyBitmap FromBytes(byte[] bytes)
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
+        public static AnyBitmap FromBytes(byte[] bytes, bool preserveOriginalFormat = true)
         {
-            return new AnyBitmap(bytes);
+            return new AnyBitmap(bytes, preserveOriginalFormat);
         }
 
         /// <summary>
         /// Create a new Bitmap from a <see cref="Stream"/> (bytes).
         /// </summary>
-        /// <param name="stream">A <see cref="Stream"/> of image data in any 
-        /// common format.</param>
-        /// <seealso cref="FromStream(Stream)"/>
+        /// <param name="stream">A <see cref="Stream"/> of image data in any common format.</param> 
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
+        /// <seealso cref="FromStream(Stream, bool)"/>
         /// <seealso cref="AnyBitmap"/>
-        public static AnyBitmap FromStream(MemoryStream stream)
+        public static AnyBitmap FromStream(MemoryStream stream, bool preserveOriginalFormat = true)
         {
-            return new AnyBitmap(stream);
+            return new AnyBitmap(stream, preserveOriginalFormat);
         }
 
         /// <summary>
         /// Create a new Bitmap from a <see cref="Stream"/> (bytes).
         /// </summary>
-        /// <param name="stream">A <see cref="Stream"/> of image data in any 
-        /// common format.</param>
-        /// <seealso cref="FromStream(MemoryStream)"/>
+        /// <param name="stream">A <see cref="Stream"/> of image data in any common format.</param>
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
+        /// <seealso cref="FromStream(MemoryStream, bool)"/>
         /// <seealso cref="AnyBitmap"/>
-        public static AnyBitmap FromStream(Stream stream)
+        public static AnyBitmap FromStream(Stream stream, bool preserveOriginalFormat = true)
         {
-            return new AnyBitmap(stream);
+            return new AnyBitmap(stream, preserveOriginalFormat);
         }
 
         /// <summary>
         /// Construct a new Bitmap from binary data (byte span).
         /// </summary>
         /// <param name="span">A byte span of image data in any common format.</param>
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
         /// <seealso cref="AnyBitmap"/>
-        public AnyBitmap(ReadOnlySpan<byte> span)
+        public AnyBitmap(ReadOnlySpan<byte> span, bool preserveOriginalFormat = true)
         {
-            LoadImage(span);
+            LoadImage(span, preserveOriginalFormat);
         }
 
         /// <summary>
         /// Construct a new Bitmap from binary data (bytes).
         /// </summary>
         /// <param name="bytes">A ByteArray of image data in any common format.</param>
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
         /// <seealso cref="FromBytes"/>
         /// <seealso cref="AnyBitmap"/>
-        public AnyBitmap(byte[] bytes)
+        public AnyBitmap(byte[] bytes, bool preserveOriginalFormat = true)
         {
-            LoadImage(bytes);
+            LoadImage(bytes, preserveOriginalFormat);
         }
 
         /// <summary>
         /// Construct a new Bitmap from a <see cref="Stream"/> (bytes).
         /// </summary>
-        /// <param name="stream">A <see cref="Stream"/> of image data in any 
-        /// common format.</param>
-        /// <seealso cref="FromStream(Stream)"/>
+        /// <param name="stream">A <see cref="Stream"/> of image data in any common format.</param>
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
+        /// <seealso cref="FromStream(Stream, bool)"/>
         /// <seealso cref="AnyBitmap"/>
-        public AnyBitmap(MemoryStream stream)
+        public AnyBitmap(MemoryStream stream, bool preserveOriginalFormat = true)
         {
-            LoadImage(stream.ToArray());
+            LoadImage(stream.ToArray(), preserveOriginalFormat);
         }
 
         /// <summary>
         /// Construct a new Bitmap from a <see cref="Stream"/> (bytes).
         /// </summary>
-        /// <param name="stream">A <see cref="Stream"/> of image data in any 
-        /// common format.</param>
-        /// <seealso cref="FromStream(MemoryStream)"/>
+        /// <param name="stream">A <see cref="Stream"/> of image data in any common format.</param>
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
+        /// <seealso cref="FromStream(MemoryStream, bool)"/>
         /// <seealso cref="AnyBitmap"/>
-        public AnyBitmap(Stream stream)
+        public AnyBitmap(Stream stream, bool preserveOriginalFormat = true)
         {
-            LoadImage(stream);
+            LoadImage(stream, preserveOriginalFormat);
         }
 
         /// <summary>
@@ -561,25 +574,29 @@ public AnyBitmap(AnyBitmap original, int width, int height)
         /// Construct a new Bitmap from a file.
         /// </summary>
         /// <param name="file">A fully qualified file path./</param>
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
         /// <seealso cref="FromFile"/>
         /// <seealso cref="AnyBitmap"/>
-        public AnyBitmap(string file)
+        public AnyBitmap(string file, bool preserveOriginalFormat = true)
         {
-            LoadImage(File.ReadAllBytes(file));
+            LoadImage(File.ReadAllBytes(file), preserveOriginalFormat);
         }
 
         /// <summary>
         /// Construct a new Bitmap from a Uri
         /// </summary>
         /// <param name="uri">The uri of the image.</param>
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
         /// <seealso cref="FromUriAsync"/>
         /// <seealso cref="AnyBitmap"/>
-        public AnyBitmap(Uri uri)
+        public AnyBitmap(Uri uri, bool preserveOriginalFormat = true)
         {
             try
             {
                 using Stream stream = LoadUriAsync(uri).GetAwaiter().GetResult();
-                LoadImage(stream);
+                LoadImage(stream, preserveOriginalFormat);
             }
             catch (Exception e)
             {
@@ -602,17 +619,19 @@ public AnyBitmap(int width, int height, Color backgroundColor = null)
         /// Create a new Bitmap from a file.
         /// </summary>
         /// <param name="file">A fully qualified file path.</param>
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
         /// <seealso cref="FromFile"/>
         /// <seealso cref="AnyBitmap"/>
-        public static AnyBitmap FromFile(string file)
+        public static AnyBitmap FromFile(string file, bool preserveOriginalFormat = true)
         {
             if (file.ToLower().EndsWith(".svg"))
             {
-                return LoadSVGImage(file);
+                return LoadSVGImage(file, preserveOriginalFormat);
             }
             else
             {
-                return new AnyBitmap(file);
+                return new AnyBitmap(file, preserveOriginalFormat);
             }
         }
 
@@ -620,16 +639,18 @@ public static AnyBitmap FromFile(string file)
         /// Construct a new Bitmap from a Uri
         /// </summary>
         /// <param name="uri">The uri of the image.</param>
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
         /// <returns></returns>
         /// <seealso cref="AnyBitmap"/>
         /// <seealso cref="FromUri"/>
         /// <seealso cref="FromUriAsync"/>
-        public static async Task<AnyBitmap> FromUriAsync(Uri uri)
+        public static async Task<AnyBitmap> FromUriAsync(Uri uri, bool preserveOriginalFormat = true)
         {
             try
             {
                 using Stream stream = await LoadUriAsync(uri);
-                return new AnyBitmap(stream);
+                return new AnyBitmap(stream, preserveOriginalFormat);
             }
             catch (Exception e)
             {
@@ -641,13 +662,15 @@ public static async Task<AnyBitmap> FromUriAsync(Uri uri)
         /// Construct a new Bitmap from a Uri
         /// </summary>
         /// <param name="uri">The uri of the image.</param>
+        /// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
+        /// Default is true. Set to false to load as Rgba32.</param>
         /// <returns></returns>
         /// <seealso cref="AnyBitmap"/>
         /// <seealso cref="FromUriAsync"/>
 #if NET6_0_OR_GREATER
         [Obsolete("FromUri(Uri) is obsolete for net60 or greater because it uses WebClient which is obsolete. Consider using FromUriAsync(Uri) method.")]
 #endif
-        public static AnyBitmap FromUri(Uri uri)
+        public static AnyBitmap FromUri(Uri uri, bool preserveOriginalFormat = true)
         {
             try
             {
@@ -2017,19 +2040,33 @@ private void CreateNewImageInstance(int width, int height, Color backgroundColor
             Binary = stream.ToArray();
         }
         
-        private void LoadImage(ReadOnlySpan<byte> bytes)
+        private void LoadImage(ReadOnlySpan<byte> bytes, bool preserveOriginalFormat)
         {
             Format = Image.DetectFormat(bytes);
             try
             {
                 if (Format is TiffFormat)
                     OpenTiffToImageSharp(bytes);
-
                 else
                 {
                     Binary = bytes.ToArray();
-                    Image = Image.Load(bytes);
-                    
+
+                    if (preserveOriginalFormat)
+                        Image = Image.Load(bytes);
+                    else
+                    {
+                        PreserveOriginalFormat = preserveOriginalFormat;
+                        Image = Image.Load<Rgba32>(bytes);
+
+                        // .png image pre-processing
+                        if (Format.Name == "PNG")
+                            Image.Mutate(img => img.BackgroundColor(SixLabors.ImageSharp.Color.White));
+                    }
+
+                    // Fix if the input image is auto-rotated; this issue is acknowledged by SixLabors.ImageSharp community
+                    // ref: https://github.com/SixLabors/ImageSharp/discussions/2685
+                    Image.Mutate(x => x.AutoOrient());
+
                     var resolutionUnit = this.Image.Metadata.ResolutionUnits;
                     var horizontal = this.Image.Metadata.HorizontalResolution;
                     var vertical = this.Image.Metadata.VerticalResolution;
@@ -2067,7 +2104,7 @@ private void LoadImage(ReadOnlySpan<byte> bytes)
             }
         }
 
-        private void LoadImage(Stream stream)
+        private void LoadImage(Stream stream, bool preserveOriginalFormat)
         {
             byte[] buffer = new byte[16 * 1024];
             using MemoryStream ms = new();
@@ -2077,17 +2114,17 @@ private void LoadImage(Stream stream)
                 ms.Write(buffer, 0, read);
             }
 
-            LoadImage(ms.ToArray());
+            LoadImage(ms.ToArray(), preserveOriginalFormat);
         }
 
-        private static AnyBitmap LoadSVGImage(string file)
+        private static AnyBitmap LoadSVGImage(string file, bool preserveOriginalFormat)
         {
             try
 
             {
                 return new AnyBitmap(
                     DecodeSVG(file).Encode(SKEncodedImageFormat.Png, 100)
-                    .ToArray());
+                    .ToArray(), preserveOriginalFormat);
             }
             catch (DllNotFoundException e)
             {
@@ -2233,6 +2270,21 @@ private static SKBitmap OpenTiffToSKBitmap(AnyBitmap anyBitmap)
             }
         }
 
+        /// <summary>
+        /// Disable warning message written to console by BitMiracle.LibTiff.NET.
+        /// </summary>
+        private class DisableErrorHandler : TiffErrorHandler
+        {
+            public override void WarningHandler(Tiff tif, string method, string format, params object[] args)
+            {
+                // do nothing, ie, do not write warnings to console
+            }
+            public override void WarningHandlerExt(Tiff tif, object clientData, string method, string format, params object[] args)
+            {
+                // do nothing ie, do not write warnings to console
+            }
+        }
+
         private void OpenTiffToImageSharp(ReadOnlySpan<byte> bytes)
         {
             try
@@ -2246,6 +2298,9 @@ private void OpenTiffToImageSharp(ReadOnlySpan<byte> bytes)
                 // create a memory stream out of them
                 using MemoryStream tiffStream = new(bytes.ToArray());
 
+                // Disable warning messages
+                Tiff.SetErrorHandler(new DisableErrorHandler());
+
                 // open a TIFF stored in the stream
                 using (Tiff tiff = Tiff.ClientOpen("in-memory", "r", tiffStream, new TiffStream()))
                 {
diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/IronSoftware.Drawing.Common.csproj b/IronSoftware.Drawing/IronSoftware.Drawing.Common/IronSoftware.Drawing.Common.csproj
index af58cb4..ec774df 100644
--- a/IronSoftware.Drawing/IronSoftware.Drawing.Common/IronSoftware.Drawing.Common.csproj
+++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/IronSoftware.Drawing.Common.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+﻿<Project Sdk="Microsoft.NET.Sdk">
 
 	<PropertyGroup>
 		<AssemblyOriginatorKeyFile>IronSoftware.Drawing.Common.snk</AssemblyOriginatorKeyFile>
@@ -25,7 +25,7 @@
 		<PackageReference Include="BitMiracle.LibTiff.NET" Version="2.4.649" />
 		<PackageReference Include="Microsoft.Maui.Graphics" Version="7.0.92" />
         <PackageReference Include="SkiaSharp" Version="2.88.7" />
-        <PackageReference Include="IronSoftware.Drawing.Abstractions" Version="2025.2.6" />
+        <PackageReference Include="IronSoftware.Drawing.Abstractions" Version="2025.4.2" />
 		<PackageReference Include="SkiaSharp.Svg" Version="1.60.0" />
 		<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
 		<PackageReference Include="System.Memory" Version="4.5.5" />
diff --git a/NuGet/IronSoftware.Drawing.nuspec b/NuGet/IronSoftware.Drawing.nuspec
index 730882b..0946583 100644
--- a/NuGet/IronSoftware.Drawing.nuspec
+++ b/NuGet/IronSoftware.Drawing.nuspec
@@ -39,23 +39,23 @@ Supports:
 
 For general support and technical inquiries, please email us at: support@ironsoftware.com</description>
 		<summary>IronSoftware.System.Drawing is an open-source solution for .NET developers to replace System.Drawing.Common with a universal and flexible library.</summary>
-		<releaseNotes>- Fixes incorrect HorizontalResolution and VerticalResolution of AnyBitmap images.
-		- Improves library's internal functionality and performance.</releaseNotes>
+		<releaseNotes>- Updates internal dependencies.
+    - Disable warning messages from BitMiracle.LibTiff.NET.</releaseNotes>
 		<copyright>Copyright © Iron Software 2022-2025</copyright>
 		<tags>Images, Bitmap, SkiaSharp, SixLabors, BitMiracle, Maui, SVG, TIFF, TIF, GIF, JPEG, PNG, Color, Rectangle, Drawing, C#, VB.NET, ASPX, create, render, generate, standard, netstandard2.0, core, netcore</tags>
 		<repository type="git" url="https://github.com/iron-software/IronSoftware.Drawing.Common" commit="$commit$" />
 		<dependencies>
 			<group targetFramework="netstandard2.0">
-				<dependency id="IronSoftware.Drawing.Abstractions" version="2025.2.6" />
+				<dependency id="IronSoftware.Drawing.Abstractions" version="2025.4.2" />
 				<dependency id="SixLabors.ImageSharp" version="2.1.10" />
 				<dependency id="SixLabors.ImageSharp.Drawing" version="1.0.0" />
 				<dependency id="BitMiracle.LibTiff.NET" version="2.4.649" />
 				<dependency id="System.Memory" version="4.5.5" />
 			</group>
 			<group targetFramework="net60">
-				<dependency id="IronSoftware.Drawing.Abstractions" version="2025.2.6" />
-				<dependency id="SixLabors.ImageSharp" version="3.1.7" />
-				<dependency id="SixLabors.ImageSharp.Drawing" version="2.1.5" />
+				<dependency id="IronSoftware.Drawing.Abstractions" version="2025.4.2" />
+				<dependency id="SixLabors.ImageSharp" version="3.1.8" />
+				<dependency id="SixLabors.ImageSharp.Drawing" version="2.1.6" />
 				<dependency id="BitMiracle.LibTiff.NET" version="2.4.649" />
 				<dependency id="System.Memory" version="4.5.5" />
 			</group>


Reviews:
user: login: mee-ironsoftware
body: Please check my feedback.
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-05-13T08:56:13Z
user: login: kannapat-ironsoftware
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T09:08:19Z
user: login: jordi-ironsoftware
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T10:03:26Z
user: login: kannapat-ironsoftware
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-14T01:59:21Z
user: login: kannapat-ironsoftware
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-14T02:03:11Z
user: login: kannapat-ironsoftware
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-14T02:11:02Z
user: login: kannapat-ironsoftware
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-14T02:16:33Z
user: login: jordi-ironsoftware
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T05:27:22Z
user: login: mee-ironsoftware
body: Great work!

@kannapat-ironsoftware Approval with one note: Please update `SixLabors.ImageSharp` and `SixLabors.ImageSharp.Drawing` to latest version.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-16T06:52:44Z
user: login: jordi-ironsoftware
body: LGTM
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T03:00:08Z
user: login: first-ironsoftware
body: LGTM
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T09:43:02Z

Review comments:
diff_hunk: @@ -2017,19 +2039,28 @@ private void CreateNewImageInstance(int width, int height, Color backgroundColor
             Binary = stream.ToArray();
         }
         
-        private void LoadImage(ReadOnlySpan<byte> bytes)
+        private void LoadImage(ReadOnlySpan<byte> bytes, bool preserveOriginalFormat)
         {
             Format = Image.DetectFormat(bytes);
             try
             {
                 if (Format is TiffFormat)
                     OpenTiffToImageSharp(bytes);
-
                 else
                 {
                     Binary = bytes.ToArray();
                     Image = Image.Load(bytes);
-                    
+
+                    if (!preserveOriginalFormat)
+                    {
+                        if (Image is not Image<Rgba32>)
+                            Image = Image.CloneAs<Rgba32>();
+
+                        // .png image pre-processing
+                        if (Format.Name == "PNG")
+                            Image.Mutate(img => img.BackgroundColor(SixLabors.ImageSharp.Color.White));
+                    }
+
path: IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs
user: login: mee-ironsoftware
body: Consider optimizing the image loading process by using the generic Load method with Rgba32 type parameter directly:

```CSharp
// Instead of:
Image = Image.Load(bytes);
if (!preserveOriginalFormat)
{
    if (Image is not Image<Rgba32>)
        Image = Image.CloneAs<Rgba32>();
    // ...
}

// Consider:
if (preserveOriginalFormat)
{
    Image = Image.Load(bytes);
}
else
{
    Image = Image.Load<Rgba32>(bytes); // Load directly as Rgba32
    // ...
}
```

This would avoid unnecessary memory allocation and conversion when we know in advance that Rgba32 format will be needed. It improves performance by eliminating the need for runtime type checking and subsequent cloning operation.
created_at: 2025-05-13T08:55:51Z
author_association: MEMBER
diff_hunk: @@ -2017,19 +2039,28 @@ private void CreateNewImageInstance(int width, int height, Color backgroundColor
             Binary = stream.ToArray();
         }
         
-        private void LoadImage(ReadOnlySpan<byte> bytes)
+        private void LoadImage(ReadOnlySpan<byte> bytes, bool preserveOriginalFormat)
         {
             Format = Image.DetectFormat(bytes);
             try
             {
                 if (Format is TiffFormat)
                     OpenTiffToImageSharp(bytes);
-
                 else
                 {
                     Binary = bytes.ToArray();
                     Image = Image.Load(bytes);
-                    
+
+                    if (!preserveOriginalFormat)
+                    {
+                        if (Image is not Image<Rgba32>)
+                            Image = Image.CloneAs<Rgba32>();
+
+                        // .png image pre-processing
+                        if (Format.Name == "PNG")
+                            Image.Mutate(img => img.BackgroundColor(SixLabors.ImageSharp.Color.White));
+                    }
+
path: IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs
user: login: kannapat-ironsoftware
body: I already tried that and tested the pre-release package in IronOcr. There is an issues occur while [GetRGBBuffer()](https://github.com/iron-software/IronSoftware.System.Drawing/blob/06d836c8408190e0553489b16e3527457827a08a/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs#L1124) and [ExtractAlphaData()](https://github.com/iron-software/IronSoftware.System.Drawing/blob/06d836c8408190e0553489b16e3527457827a08a/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs#L828C23-L828C41) causing the corrupted Pix and become unreadable by Tesseract.
created_at: 2025-05-13T09:08:19Z
author_association: MEMBER
diff_hunk: @@ -2017,19 +2039,28 @@ private void CreateNewImageInstance(int width, int height, Color backgroundColor
             Binary = stream.ToArray();
         }
         
-        private void LoadImage(ReadOnlySpan<byte> bytes)
+        private void LoadImage(ReadOnlySpan<byte> bytes, bool preserveOriginalFormat)
         {
             Format = Image.DetectFormat(bytes);
             try
             {
                 if (Format is TiffFormat)
                     OpenTiffToImageSharp(bytes);
-
                 else
                 {
                     Binary = bytes.ToArray();
                     Image = Image.Load(bytes);
-                    
+
+                    if (!preserveOriginalFormat)
+                    {
+                        if (Image is not Image<Rgba32>)
+                            Image = Image.CloneAs<Rgba32>();
+
+                        // .png image pre-processing
+                        if (Format.Name == "PNG")
+                            Image.Mutate(img => img.BackgroundColor(SixLabors.ImageSharp.Color.White));
path: IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs
user: login: jordi-ironsoftware
body: What's the purpose of converting the background to white if an image is a PNG?
created_at: 2025-05-13T09:58:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -462,87 +462,99 @@ public T ToBitmap<T>()
         /// Create a new Bitmap from a a Byte Span.
         /// </summary>
         /// <param name="span">A Byte Span of image data in any common format.</param>
-        public static AnyBitmap FromSpan(ReadOnlySpan<byte> span)
+        /// <param name="preserveOriginalFormat">Determine wheter load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
path: IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs
user: login: jordi-ironsoftware
body: Typo. Should be `Determine whether to load...`
created_at: 2025-05-13T09:58:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2017,19 +2039,28 @@ private void CreateNewImageInstance(int width, int height, Color backgroundColor
             Binary = stream.ToArray();
         }
         
-        private void LoadImage(ReadOnlySpan<byte> bytes)
+        private void LoadImage(ReadOnlySpan<byte> bytes, bool preserveOriginalFormat)
         {
             Format = Image.DetectFormat(bytes);
             try
             {
                 if (Format is TiffFormat)
                     OpenTiffToImageSharp(bytes);
-
                 else
                 {
                     Binary = bytes.ToArray();
                     Image = Image.Load(bytes);
-                    
+
+                    if (!preserveOriginalFormat)
+                    {
+                        if (Image is not Image<Rgba32>)
+                            Image = Image.CloneAs<Rgba32>();
+
+                        // .png image pre-processing
+                        if (Format.Name == "PNG")
+                            Image.Mutate(img => img.BackgroundColor(SixLabors.ImageSharp.Color.White));
+                    }
+
path: IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs
user: login: kannapat-ironsoftware
body: Actually, let me try again with the pre-release package build upon Load<Rgba32> directly.
I might mis-calculate the RGBA buffer at that time.
created_at: 2025-05-14T01:59:21Z
author_association: MEMBER
diff_hunk: @@ -2017,19 +2039,28 @@ private void CreateNewImageInstance(int width, int height, Color backgroundColor
             Binary = stream.ToArray();
         }
         
-        private void LoadImage(ReadOnlySpan<byte> bytes)
+        private void LoadImage(ReadOnlySpan<byte> bytes, bool preserveOriginalFormat)
         {
             Format = Image.DetectFormat(bytes);
             try
             {
                 if (Format is TiffFormat)
                     OpenTiffToImageSharp(bytes);
-
                 else
                 {
                     Binary = bytes.ToArray();
                     Image = Image.Load(bytes);
-                    
+
+                    if (!preserveOriginalFormat)
+                    {
+                        if (Image is not Image<Rgba32>)
+                            Image = Image.CloneAs<Rgba32>();
+
+                        // .png image pre-processing
+                        if (Format.Name == "PNG")
+                            Image.Mutate(img => img.BackgroundColor(SixLabors.ImageSharp.Color.White));
path: IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs
user: login: kannapat-ironsoftware
body: It's pre-image processing we do for .PNG format in IronOcr ([ref](https://github.com/iron-software/IronOcr.Rebuild/blob/c32e001dd6f6f17d6ee1a01f032456a5e9afee1e/src/DynamicTesseract/Pix/ImageToPixConverter.cs#L66)). The input format argument pass [here](https://github.com/iron-software/IronOcr.Rebuild/blob/c32e001dd6f6f17d6ee1a01f032456a5e9afee1e/src/IronOcr/OcrInput/OcrInput.Load.cs#L651). 
created_at: 2025-05-14T02:03:11Z
author_association: MEMBER
diff_hunk: @@ -2017,19 +2039,28 @@ private void CreateNewImageInstance(int width, int height, Color backgroundColor
             Binary = stream.ToArray();
         }
         
-        private void LoadImage(ReadOnlySpan<byte> bytes)
+        private void LoadImage(ReadOnlySpan<byte> bytes, bool preserveOriginalFormat)
         {
             Format = Image.DetectFormat(bytes);
             try
             {
                 if (Format is TiffFormat)
                     OpenTiffToImageSharp(bytes);
-
                 else
                 {
                     Binary = bytes.ToArray();
                     Image = Image.Load(bytes);
-                    
+
+                    if (!preserveOriginalFormat)
+                    {
+                        if (Image is not Image<Rgba32>)
+                            Image = Image.CloneAs<Rgba32>();
+
+                        // .png image pre-processing
+                        if (Format.Name == "PNG")
+                            Image.Mutate(img => img.BackgroundColor(SixLabors.ImageSharp.Color.White));
+                    }
+
path: IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs
user: login: kannapat-ironsoftware
body: I was miscalculation of RGBA buffer at that time. I'll make the change as your suggestion.
created_at: 2025-05-14T02:11:02Z
author_association: MEMBER
diff_hunk: @@ -2017,19 +2039,28 @@ private void CreateNewImageInstance(int width, int height, Color backgroundColor
             Binary = stream.ToArray();
         }
         
-        private void LoadImage(ReadOnlySpan<byte> bytes)
+        private void LoadImage(ReadOnlySpan<byte> bytes, bool preserveOriginalFormat)
         {
             Format = Image.DetectFormat(bytes);
             try
             {
                 if (Format is TiffFormat)
                     OpenTiffToImageSharp(bytes);
-
                 else
                 {
                     Binary = bytes.ToArray();
                     Image = Image.Load(bytes);
-                    
+
+                    if (!preserveOriginalFormat)
+                    {
+                        if (Image is not Image<Rgba32>)
+                            Image = Image.CloneAs<Rgba32>();
+
+                        // .png image pre-processing
+                        if (Format.Name == "PNG")
+                            Image.Mutate(img => img.BackgroundColor(SixLabors.ImageSharp.Color.White));
+                    }
+
path: IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs
user: login: kannapat-ironsoftware
body: DONE. Please kindly re-review. 🙏
created_at: 2025-05-14T02:16:33Z
author_association: MEMBER
diff_hunk: @@ -462,87 +463,99 @@ public T ToBitmap<T>()
         /// Create a new Bitmap from a a Byte Span.
         /// </summary>
         /// <param name="span">A Byte Span of image data in any common format.</param>
-        public static AnyBitmap FromSpan(ReadOnlySpan<byte> span)
+        /// <param name="preserveOriginalFormat">Determine whether load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
path: IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs
user: login: jordi-ironsoftware
body: nit: `Determine whether load` -> `Determine whether to load`
created_at: 2025-05-16T05:27:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -39,21 +39,21 @@ Supports:
 
 For general support and technical inquiries, please email us at: support@ironsoftware.com</description>
 		<summary>IronSoftware.System.Drawing is an open-source solution for .NET developers to replace System.Drawing.Common with a universal and flexible library.</summary>
-		<releaseNotes>- Fixes incorrect HorizontalResolution and VerticalResolution of AnyBitmap images.
-		- Improves library's internal functionality and performance.</releaseNotes>
+		<releaseNotes>- Updates internal dependencies.
+    - Disable warning messages from BitMiracle.LibTiff.NET.</releaseNotes>
 		<copyright>Copyright © Iron Software 2022-2025</copyright>
 		<tags>Images, Bitmap, SkiaSharp, SixLabors, BitMiracle, Maui, SVG, TIFF, TIF, GIF, JPEG, PNG, Color, Rectangle, Drawing, C#, VB.NET, ASPX, create, render, generate, standard, netstandard2.0, core, netcore</tags>
 		<repository type="git" url="https://github.com/iron-software/IronSoftware.Drawing.Common" commit="$commit$" />
 		<dependencies>
 			<group targetFramework="netstandard2.0">
-				<dependency id="IronSoftware.Drawing.Abstractions" version="2025.2.6" />
+				<dependency id="IronSoftware.Drawing.Abstractions" version="2025.4.2" />
 				<dependency id="SixLabors.ImageSharp" version="2.1.10" />
 				<dependency id="SixLabors.ImageSharp.Drawing" version="1.0.0" />
 				<dependency id="BitMiracle.LibTiff.NET" version="2.4.649" />
 				<dependency id="System.Memory" version="4.5.5" />
 			</group>
 			<group targetFramework="net60">
-				<dependency id="IronSoftware.Drawing.Abstractions" version="2025.2.6" />
+				<dependency id="IronSoftware.Drawing.Abstractions" version="2025.4.2" />
 				<dependency id="SixLabors.ImageSharp" version="3.1.7" />
path: NuGet/IronSoftware.Drawing.nuspec
user: login: mee-ironsoftware
body: Please update `SixLabors.ImageSharp` to latest version "3.1.8" for net60 target. Please also change in .csproj as well.
created_at: 2025-05-16T06:49:44Z
author_association: MEMBER
diff_hunk: @@ -39,21 +39,21 @@ Supports:
 
 For general support and technical inquiries, please email us at: support@ironsoftware.com</description>
 		<summary>IronSoftware.System.Drawing is an open-source solution for .NET developers to replace System.Drawing.Common with a universal and flexible library.</summary>
-		<releaseNotes>- Fixes incorrect HorizontalResolution and VerticalResolution of AnyBitmap images.
-		- Improves library's internal functionality and performance.</releaseNotes>
+		<releaseNotes>- Updates internal dependencies.
+    - Disable warning messages from BitMiracle.LibTiff.NET.</releaseNotes>
 		<copyright>Copyright © Iron Software 2022-2025</copyright>
 		<tags>Images, Bitmap, SkiaSharp, SixLabors, BitMiracle, Maui, SVG, TIFF, TIF, GIF, JPEG, PNG, Color, Rectangle, Drawing, C#, VB.NET, ASPX, create, render, generate, standard, netstandard2.0, core, netcore</tags>
 		<repository type="git" url="https://github.com/iron-software/IronSoftware.Drawing.Common" commit="$commit$" />
 		<dependencies>
 			<group targetFramework="netstandard2.0">
-				<dependency id="IronSoftware.Drawing.Abstractions" version="2025.2.6" />
+				<dependency id="IronSoftware.Drawing.Abstractions" version="2025.4.2" />
 				<dependency id="SixLabors.ImageSharp" version="2.1.10" />
 				<dependency id="SixLabors.ImageSharp.Drawing" version="1.0.0" />
 				<dependency id="BitMiracle.LibTiff.NET" version="2.4.649" />
 				<dependency id="System.Memory" version="4.5.5" />
 			</group>
 			<group targetFramework="net60">
-				<dependency id="IronSoftware.Drawing.Abstractions" version="2025.2.6" />
+				<dependency id="IronSoftware.Drawing.Abstractions" version="2025.4.2" />
 				<dependency id="SixLabors.ImageSharp" version="3.1.7" />
 				<dependency id="SixLabors.ImageSharp.Drawing" version="2.1.5" />
path: NuGet/IronSoftware.Drawing.nuspec
user: login: mee-ironsoftware
body: Please update `SixLabors.ImageSharp.Drawing` to latest version "2.1.6" for net60 target. Please also change in .csproj as well.
created_at: 2025-05-16T06:52:20Z
author_association: MEMBER

PR comments:
user: login: kannapat-ironsoftware
created_at: 2025-05-15T05:44:27Z
body: Added the new Global bool called PreserveOriginalFormat to apply the same pixel format when Clone() is called by GetAllFrames ([ref](https://github.com/iron-software/IronSoftware.System.Drawing/blob/06d836c8408190e0553489b16e3527457827a08a/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs#L739))
author_association: MEMBER
user: login: first-ironsoftware
created_at: 2025-05-20T09:28:33Z
body: Confirmed fix in [DW-32](https://ironsoftware.atlassian.net/browse/DW-32)

[DW-32]: https://ironsoftware.atlassian.net/browse/DW-32?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
author_association: CONTRIBUTOR