diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index c464cae0e..07e17680a 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -1,5 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+
using System;
using System.IO;
using System.Runtime.CompilerServices;
@@ -133,11 +134,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
switch (this.infoHeader.Compression)
{
case BmpCompression.RGB:
- if (this.infoHeader.HeaderSize != 40)
- {
- throw new ImageFormatException($"Header Size value '{this.infoHeader.HeaderSize}' is not valid.");
- }
-
if (this.infoHeader.BitsPerPixel == 32)
{
this.ReadRgb32(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
@@ -372,11 +368,69 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
private void ReadInfoHeader()
{
- byte[] data = new byte[BmpInfoHeader.Size];
+ byte[] data = new byte[BmpInfoHeader.MaxHeaderSize];
+
+ // read header size
+ this.currentStream.Read(data, 0, BmpInfoHeader.HeaderSizeSize);
+ int headerSize = BitConverter.ToInt32(data, 0);
+ if (headerSize < BmpInfoHeader.HeaderSizeSize || headerSize > BmpInfoHeader.MaxHeaderSize)
+ {
+ throw new NotSupportedException($"This kind of bitmap files (header size $headerSize) is not supported.");
+ }
+
+ // read the rest of the header
+ this.currentStream.Read(data, BmpInfoHeader.HeaderSizeSize, headerSize - BmpInfoHeader.HeaderSizeSize);
+
+ switch (headerSize)
+ {
+ case BmpInfoHeader.BitmapCoreHeaderSize:
+ this.infoHeader = this.ParseBitmapCoreHeader(data);
+ break;
+
+ case BmpInfoHeader.BitmapInfoHeaderSize:
+ this.infoHeader = this.ParseBitmapInfoHeader(data);
+ break;
+
+ default:
+ throw new NotSupportedException($"This kind of bitmap files (header size $headerSize) is not supported.");
+ }
+ }
- this.currentStream.Read(data, 0, BmpInfoHeader.Size);
+ ///
+ /// Parses the from the stream, assuming it uses the BITMAPCOREHEADER format.
+ ///
+ /// Header bytes read from the stream
+ /// Parsed header
+ ///
+ private BmpInfoHeader ParseBitmapCoreHeader(byte[] data)
+ {
+ return new BmpInfoHeader
+ {
+ HeaderSize = BitConverter.ToInt32(data, 0),
+ Width = BitConverter.ToUInt16(data, 4),
+ Height = BitConverter.ToUInt16(data, 6),
+ Planes = BitConverter.ToInt16(data, 8),
+ BitsPerPixel = BitConverter.ToInt16(data, 10),
+
+ // the rest is not present in the core header
+ ImageSize = 0,
+ XPelsPerMeter = 0,
+ YPelsPerMeter = 0,
+ ClrUsed = 0,
+ ClrImportant = 0,
+ Compression = BmpCompression.RGB
+ };
+ }
- this.infoHeader = new BmpInfoHeader
+ ///
+ /// Parses the from the stream, assuming it uses the BITMAPINFOHEADER format.
+ ///
+ /// Header bytes read from the stream
+ /// Parsed header
+ ///
+ private BmpInfoHeader ParseBitmapInfoHeader(byte[] data)
+ {
+ return new BmpInfoHeader
{
HeaderSize = BitConverter.ToInt32(data, 0),
Width = BitConverter.ToInt32(data, 4),
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index 7f49be12a..12dd0f91a 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
@@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
BmpInfoHeader infoHeader = new BmpInfoHeader
{
- HeaderSize = BmpInfoHeader.Size,
+ HeaderSize = BmpInfoHeader.BitmapInfoHeaderSize,
Height = image.Height,
Width = image.Width,
BitsPerPixel = bpp,
diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
index 1037a97f9..b24404cac 100644
--- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
@@ -11,12 +11,27 @@ namespace SixLabors.ImageSharp.Formats.Bmp
internal sealed class BmpInfoHeader
{
///
- /// Defines of the data structure in the bitmap file.
+ /// Defines the size of the BITMAPINFOHEADER data structure in the bitmap file.
///
- public const int Size = 40;
+ public const int BitmapInfoHeaderSize = 40;
///
- /// Gets or sets the size of this header (40 bytes)
+ /// Defines the size of the BITMAPCOREHEADER data structure in the bitmap file.
+ ///
+ public const int BitmapCoreHeaderSize = 12;
+
+ ///
+ /// Defines the size of the biggest supported header data structure in the bitmap file.
+ ///
+ public const int MaxHeaderSize = BitmapInfoHeaderSize;
+
+ ///
+ /// Defines the size of the field.
+ ///
+ public const int HeaderSizeSize = 4;
+
+ ///
+ /// Gets or sets the size of this header
///
public int HeaderSize { get; set; }
diff --git a/tests/ImageSharp.Tests/FileTestBase.cs b/tests/ImageSharp.Tests/FileTestBase.cs
index 933cfa86b..88d618880 100644
--- a/tests/ImageSharp.Tests/FileTestBase.cs
+++ b/tests/ImageSharp.Tests/FileTestBase.cs
@@ -83,6 +83,7 @@ namespace SixLabors.ImageSharp.Tests
// TestFile.Create(TestImages.Jpeg.Progressive.Bad.BadEOF), // Perf: Enable for local testing only
TestFile.Create(TestImages.Bmp.Car),
// TestFile.Create(TestImages.Bmp.NegHeight), // Perf: Enable for local testing only
+ // TestFile.Create(TestImages.Bmp.CoreHeader), // Perf: Enable for local testing only
TestFile.Create(TestImages.Png.Splash),
// TestFile.Create(TestImages.Png.Cross), // Perf: Enable for local testing only
// TestFile.Create(TestImages.Png.Bad.ChunkLength1), // Perf: Enable for local testing only
diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
new file mode 100644
index 000000000..4e10de23f
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
@@ -0,0 +1,27 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+using ImageSharp.Formats;
+
+namespace ImageSharp.Tests
+{
+ using ImageSharp.PixelFormats;
+
+ using Xunit;
+
+ public class BmpDecoderTests : FileTestBase
+ {
+ [Theory]
+ [WithFileCollection(nameof(AllBmpFiles), PixelTypes.Rgb24)]
+ public void OpenAllBmpFiles_SaveBmp(TestImageProvider provider)
+ where TPixel : struct, IPixel
+ {
+ using (Image image = provider.GetImage())
+ {
+ provider.Utility.SaveTestOutputFile(image, "bmp");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index 4adc9bd72..3fdbecf50 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -119,7 +119,8 @@ namespace SixLabors.ImageSharp.Tests
public const string Car = "Bmp/Car.bmp";
public const string F = "Bmp/F.bmp";
public const string NegHeight = "Bmp/neg_height.bmp";
- public static readonly string[] All = { Car, F, NegHeight };
+ public const string CoreHeader = "Bmp/BitmapCoreHeaderQR.bmp";
+ public static readonly string[] All = { Car, F, NegHeight, CoreHeader };
}
public static class Gif
diff --git a/tests/ImageSharp.Tests/TestImages/Formats/Bmp/BitmapCoreHeaderQR.bmp b/tests/ImageSharp.Tests/TestImages/Formats/Bmp/BitmapCoreHeaderQR.bmp
new file mode 100644
index 000000000..b5c58f8cb
Binary files /dev/null and b/tests/ImageSharp.Tests/TestImages/Formats/Bmp/BitmapCoreHeaderQR.bmp differ