Skip to content

Commit 419155e

Browse files
Merge pull request #132 from iron-software/DW-33-add-load-input-image-as-Rgba32
DW-33 Add preserveOriginalFormat bool while loading image
2 parents 30b3e45 + 2f3184e commit 419155e

File tree

3 files changed

+106
-49
lines changed

3 files changed

+106
-49
lines changed

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,26 @@ public void LoadImage_TiffImage_ShouldLoadWithoutThumbnail()
942942
bitmap.FrameCount.Should().Be(1);
943943
}
944944

945+
[TheoryWithAutomaticDisplayName]
946+
[InlineData("24_bit.png")]
947+
[InlineData("checkmark.jpg")]
948+
[InlineData("DW-26 Jpg72Input.jpg")]
949+
[InlineData("DW-26 Jpg300Input.jpg")]
950+
[InlineData("mountainclimbers.jpg")]
951+
public void LoadImage_SetPreserveOriginalFormat_ShouldReturnCorrectBitPerPixel(string imageFileName)
952+
{
953+
// Arrange
954+
string imagePath = GetRelativeFilePath(imageFileName);
955+
956+
// Act
957+
var preserve = new AnyBitmap(imagePath, true);
958+
var notPreserve = new AnyBitmap(imagePath, false);
959+
960+
// Assert
961+
Assert.Equal(24, preserve.BitsPerPixel);
962+
Assert.Equal(32, notPreserve.BitsPerPixel);
963+
}
964+
945965
#if !NET7_0
946966
[FactWithAutomaticDisplayName]
947967
public void CastAnyBitmap_from_SixLabors()

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

Lines changed: 84 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public partial class AnyBitmap : IDisposable, IAnyImage
5252
private byte[] Binary { get; set; }
5353
private IImageFormat Format { get; set; }
5454
private TiffCompression TiffCompression { get; set; } = TiffCompression.Lzw;
55+
private bool PreserveOriginalFormat { get; set; } = true;
5556

5657
/// <summary>
5758
/// Width of the image.
@@ -138,7 +139,7 @@ public MemoryStream GetStream()
138139
/// <returns></returns>
139140
public AnyBitmap Clone()
140141
{
141-
return new AnyBitmap(Binary);
142+
return new AnyBitmap(Binary, PreserveOriginalFormat);
142143
}
143144

144145
/// <summary>
@@ -462,87 +463,99 @@ public T ToBitmap<T>()
462463
/// Create a new Bitmap from a a Byte Span.
463464
/// </summary>
464465
/// <param name="span">A Byte Span of image data in any common format.</param>
465-
public static AnyBitmap FromSpan(ReadOnlySpan<byte> span)
466+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
467+
/// Default is true. Set to false to load as Rgba32.</param>
468+
public static AnyBitmap FromSpan(ReadOnlySpan<byte> span, bool preserveOriginalFormat = true)
466469
{
467-
return new AnyBitmap(span);
470+
return new AnyBitmap(span, preserveOriginalFormat);
468471
}
469472

470473
/// <summary>
471474
/// Create a new Bitmap from a a Byte Array.
472475
/// </summary>
473476
/// <param name="bytes">A ByteArray of image data in any common format.</param>
474-
public static AnyBitmap FromBytes(byte[] bytes)
477+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
478+
/// Default is true. Set to false to load as Rgba32.</param>
479+
public static AnyBitmap FromBytes(byte[] bytes, bool preserveOriginalFormat = true)
475480
{
476-
return new AnyBitmap(bytes);
481+
return new AnyBitmap(bytes, preserveOriginalFormat);
477482
}
478483

479484
/// <summary>
480485
/// Create a new Bitmap from a <see cref="Stream"/> (bytes).
481486
/// </summary>
482-
/// <param name="stream">A <see cref="Stream"/> of image data in any
483-
/// common format.</param>
484-
/// <seealso cref="FromStream(Stream)"/>
487+
/// <param name="stream">A <see cref="Stream"/> of image data in any common format.</param>
488+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
489+
/// Default is true. Set to false to load as Rgba32.</param>
490+
/// <seealso cref="FromStream(Stream, bool)"/>
485491
/// <seealso cref="AnyBitmap"/>
486-
public static AnyBitmap FromStream(MemoryStream stream)
492+
public static AnyBitmap FromStream(MemoryStream stream, bool preserveOriginalFormat = true)
487493
{
488-
return new AnyBitmap(stream);
494+
return new AnyBitmap(stream, preserveOriginalFormat);
489495
}
490496

491497
/// <summary>
492498
/// Create a new Bitmap from a <see cref="Stream"/> (bytes).
493499
/// </summary>
494-
/// <param name="stream">A <see cref="Stream"/> of image data in any
495-
/// common format.</param>
496-
/// <seealso cref="FromStream(MemoryStream)"/>
500+
/// <param name="stream">A <see cref="Stream"/> of image data in any common format.</param>
501+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
502+
/// Default is true. Set to false to load as Rgba32.</param>
503+
/// <seealso cref="FromStream(MemoryStream, bool)"/>
497504
/// <seealso cref="AnyBitmap"/>
498-
public static AnyBitmap FromStream(Stream stream)
505+
public static AnyBitmap FromStream(Stream stream, bool preserveOriginalFormat = true)
499506
{
500-
return new AnyBitmap(stream);
507+
return new AnyBitmap(stream, preserveOriginalFormat);
501508
}
502509

503510
/// <summary>
504511
/// Construct a new Bitmap from binary data (byte span).
505512
/// </summary>
506513
/// <param name="span">A byte span of image data in any common format.</param>
514+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
515+
/// Default is true. Set to false to load as Rgba32.</param>
507516
/// <seealso cref="AnyBitmap"/>
508-
public AnyBitmap(ReadOnlySpan<byte> span)
517+
public AnyBitmap(ReadOnlySpan<byte> span, bool preserveOriginalFormat = true)
509518
{
510-
LoadImage(span);
519+
LoadImage(span, preserveOriginalFormat);
511520
}
512521

513522
/// <summary>
514523
/// Construct a new Bitmap from binary data (bytes).
515524
/// </summary>
516525
/// <param name="bytes">A ByteArray of image data in any common format.</param>
526+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
527+
/// Default is true. Set to false to load as Rgba32.</param>
517528
/// <seealso cref="FromBytes"/>
518529
/// <seealso cref="AnyBitmap"/>
519-
public AnyBitmap(byte[] bytes)
530+
public AnyBitmap(byte[] bytes, bool preserveOriginalFormat = true)
520531
{
521-
LoadImage(bytes);
532+
LoadImage(bytes, preserveOriginalFormat);
522533
}
523534

524535
/// <summary>
525536
/// Construct a new Bitmap from a <see cref="Stream"/> (bytes).
526537
/// </summary>
527-
/// <param name="stream">A <see cref="Stream"/> of image data in any
528-
/// common format.</param>
529-
/// <seealso cref="FromStream(Stream)"/>
538+
/// <param name="stream">A <see cref="Stream"/> of image data in any common format.</param>
539+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
540+
/// Default is true. Set to false to load as Rgba32.</param>
541+
/// <seealso cref="FromStream(Stream, bool)"/>
530542
/// <seealso cref="AnyBitmap"/>
531-
public AnyBitmap(MemoryStream stream)
543+
public AnyBitmap(MemoryStream stream, bool preserveOriginalFormat = true)
532544
{
533-
LoadImage(stream.ToArray());
545+
LoadImage(stream.ToArray(), preserveOriginalFormat);
534546
}
535547

536548
/// <summary>
537549
/// Construct a new Bitmap from a <see cref="Stream"/> (bytes).
538550
/// </summary>
539-
/// <param name="stream">A <see cref="Stream"/> of image data in any
540-
/// common format.</param>
541-
/// <seealso cref="FromStream(MemoryStream)"/>
551+
/// <param name="stream">A <see cref="Stream"/> of image data in any common format.</param>
552+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
553+
/// Default is true. Set to false to load as Rgba32.</param>
554+
/// <seealso cref="FromStream(MemoryStream, bool)"/>
542555
/// <seealso cref="AnyBitmap"/>
543-
public AnyBitmap(Stream stream)
556+
public AnyBitmap(Stream stream, bool preserveOriginalFormat = true)
544557
{
545-
LoadImage(stream);
558+
LoadImage(stream, preserveOriginalFormat);
546559
}
547560

548561
/// <summary>
@@ -561,25 +574,29 @@ public AnyBitmap(AnyBitmap original, int width, int height)
561574
/// Construct a new Bitmap from a file.
562575
/// </summary>
563576
/// <param name="file">A fully qualified file path./</param>
577+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
578+
/// Default is true. Set to false to load as Rgba32.</param>
564579
/// <seealso cref="FromFile"/>
565580
/// <seealso cref="AnyBitmap"/>
566-
public AnyBitmap(string file)
581+
public AnyBitmap(string file, bool preserveOriginalFormat = true)
567582
{
568-
LoadImage(File.ReadAllBytes(file));
583+
LoadImage(File.ReadAllBytes(file), preserveOriginalFormat);
569584
}
570585

571586
/// <summary>
572587
/// Construct a new Bitmap from a Uri
573588
/// </summary>
574589
/// <param name="uri">The uri of the image.</param>
590+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
591+
/// Default is true. Set to false to load as Rgba32.</param>
575592
/// <seealso cref="FromUriAsync"/>
576593
/// <seealso cref="AnyBitmap"/>
577-
public AnyBitmap(Uri uri)
594+
public AnyBitmap(Uri uri, bool preserveOriginalFormat = true)
578595
{
579596
try
580597
{
581598
using Stream stream = LoadUriAsync(uri).GetAwaiter().GetResult();
582-
LoadImage(stream);
599+
LoadImage(stream, preserveOriginalFormat);
583600
}
584601
catch (Exception e)
585602
{
@@ -602,34 +619,38 @@ public AnyBitmap(int width, int height, Color backgroundColor = null)
602619
/// Create a new Bitmap from a file.
603620
/// </summary>
604621
/// <param name="file">A fully qualified file path.</param>
622+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
623+
/// Default is true. Set to false to load as Rgba32.</param>
605624
/// <seealso cref="FromFile"/>
606625
/// <seealso cref="AnyBitmap"/>
607-
public static AnyBitmap FromFile(string file)
626+
public static AnyBitmap FromFile(string file, bool preserveOriginalFormat = true)
608627
{
609628
if (file.ToLower().EndsWith(".svg"))
610629
{
611-
return LoadSVGImage(file);
630+
return LoadSVGImage(file, preserveOriginalFormat);
612631
}
613632
else
614633
{
615-
return new AnyBitmap(file);
634+
return new AnyBitmap(file, preserveOriginalFormat);
616635
}
617636
}
618637

619638
/// <summary>
620639
/// Construct a new Bitmap from a Uri
621640
/// </summary>
622641
/// <param name="uri">The uri of the image.</param>
642+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
643+
/// Default is true. Set to false to load as Rgba32.</param>
623644
/// <returns></returns>
624645
/// <seealso cref="AnyBitmap"/>
625646
/// <seealso cref="FromUri"/>
626647
/// <seealso cref="FromUriAsync"/>
627-
public static async Task<AnyBitmap> FromUriAsync(Uri uri)
648+
public static async Task<AnyBitmap> FromUriAsync(Uri uri, bool preserveOriginalFormat = true)
628649
{
629650
try
630651
{
631652
using Stream stream = await LoadUriAsync(uri);
632-
return new AnyBitmap(stream);
653+
return new AnyBitmap(stream, preserveOriginalFormat);
633654
}
634655
catch (Exception e)
635656
{
@@ -641,13 +662,15 @@ public static async Task<AnyBitmap> FromUriAsync(Uri uri)
641662
/// Construct a new Bitmap from a Uri
642663
/// </summary>
643664
/// <param name="uri">The uri of the image.</param>
665+
/// <param name="preserveOriginalFormat">Determine whether to load <see cref="SixLabors.ImageSharp.Image"/> as its original pixel format or Rgba32.
666+
/// Default is true. Set to false to load as Rgba32.</param>
644667
/// <returns></returns>
645668
/// <seealso cref="AnyBitmap"/>
646669
/// <seealso cref="FromUriAsync"/>
647670
#if NET6_0_OR_GREATER
648671
[Obsolete("FromUri(Uri) is obsolete for net60 or greater because it uses WebClient which is obsolete. Consider using FromUriAsync(Uri) method.")]
649672
#endif
650-
public static AnyBitmap FromUri(Uri uri)
673+
public static AnyBitmap FromUri(Uri uri, bool preserveOriginalFormat = true)
651674
{
652675
try
653676
{
@@ -2017,19 +2040,33 @@ private void CreateNewImageInstance(int width, int height, Color backgroundColor
20172040
Binary = stream.ToArray();
20182041
}
20192042

2020-
private void LoadImage(ReadOnlySpan<byte> bytes)
2043+
private void LoadImage(ReadOnlySpan<byte> bytes, bool preserveOriginalFormat)
20212044
{
20222045
Format = Image.DetectFormat(bytes);
20232046
try
20242047
{
20252048
if (Format is TiffFormat)
20262049
OpenTiffToImageSharp(bytes);
2027-
20282050
else
20292051
{
20302052
Binary = bytes.ToArray();
2031-
Image = Image.Load(bytes);
2032-
2053+
2054+
if (preserveOriginalFormat)
2055+
Image = Image.Load(bytes);
2056+
else
2057+
{
2058+
PreserveOriginalFormat = preserveOriginalFormat;
2059+
Image = Image.Load<Rgba32>(bytes);
2060+
2061+
// .png image pre-processing
2062+
if (Format.Name == "PNG")
2063+
Image.Mutate(img => img.BackgroundColor(SixLabors.ImageSharp.Color.White));
2064+
}
2065+
2066+
// Fix if the input image is auto-rotated; this issue is acknowledged by SixLabors.ImageSharp community
2067+
// ref: https://github.com/SixLabors/ImageSharp/discussions/2685
2068+
Image.Mutate(x => x.AutoOrient());
2069+
20332070
var resolutionUnit = this.Image.Metadata.ResolutionUnits;
20342071
var horizontal = this.Image.Metadata.HorizontalResolution;
20352072
var vertical = this.Image.Metadata.VerticalResolution;
@@ -2067,7 +2104,7 @@ private void LoadImage(ReadOnlySpan<byte> bytes)
20672104
}
20682105
}
20692106

2070-
private void LoadImage(Stream stream)
2107+
private void LoadImage(Stream stream, bool preserveOriginalFormat)
20712108
{
20722109
byte[] buffer = new byte[16 * 1024];
20732110
using MemoryStream ms = new();
@@ -2077,17 +2114,17 @@ private void LoadImage(Stream stream)
20772114
ms.Write(buffer, 0, read);
20782115
}
20792116

2080-
LoadImage(ms.ToArray());
2117+
LoadImage(ms.ToArray(), preserveOriginalFormat);
20812118
}
20822119

2083-
private static AnyBitmap LoadSVGImage(string file)
2120+
private static AnyBitmap LoadSVGImage(string file, bool preserveOriginalFormat)
20842121
{
20852122
try
20862123

20872124
{
20882125
return new AnyBitmap(
20892126
DecodeSVG(file).Encode(SKEncodedImageFormat.Png, 100)
2090-
.ToArray());
2127+
.ToArray(), preserveOriginalFormat);
20912128
}
20922129
catch (DllNotFoundException e)
20932130
{

NuGet/IronSoftware.Drawing.nuspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ For general support and technical inquiries, please email us at: support@ironsof
5454
</group>
5555
<group targetFramework="net60">
5656
<dependency id="IronSoftware.Drawing.Abstractions" version="2025.4.2" />
57-
<dependency id="SixLabors.ImageSharp" version="3.1.7" />
58-
<dependency id="SixLabors.ImageSharp.Drawing" version="2.1.5" />
57+
<dependency id="SixLabors.ImageSharp" version="3.1.8" />
58+
<dependency id="SixLabors.ImageSharp.Drawing" version="2.1.6" />
5959
<dependency id="BitMiracle.LibTiff.NET" version="2.4.649" />
6060
<dependency id="System.Memory" version="4.5.5" />
6161
</group>

0 commit comments

Comments
 (0)