diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index 817d00f7e..108006ade 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -2,6 +2,7 @@
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
+
namespace ImageSharp.Formats
{
using System;
@@ -135,11 +136,6 @@ namespace ImageSharp.Formats
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);
@@ -374,11 +370,69 @@ namespace ImageSharp.Formats
///
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 e41c29501..30961646f 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
@@ -58,7 +58,7 @@ namespace ImageSharp.Formats
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 dc6a489d3..c920bfbbe 100644
--- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
@@ -13,12 +13,27 @@ namespace ImageSharp.Formats
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 08ed69f3e..f9909de4a 100644
--- a/tests/ImageSharp.Tests/FileTestBase.cs
+++ b/tests/ImageSharp.Tests/FileTestBase.cs
@@ -77,6 +77,7 @@ namespace 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
index 84edca001..0537ffda0 100644
--- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
@@ -1,17 +1,29 @@
-//
+//
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
-// ReSharper disable InconsistentNaming
+using ImageSharp.Formats;
+
namespace ImageSharp.Tests
{
- using System.IO;
+ using ImageSharp.PixelFormats;
using Xunit;
- public class BmpDecoderTests
+ 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");
+ }
+ }
+
[Theory]
[InlineData(TestImages.Bmp.Car, 24)]
[InlineData(TestImages.Bmp.F, 24)]
@@ -26,4 +38,4 @@ namespace ImageSharp.Tests
}
}
}
-}
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index 644e4d3eb..c80fde6d0 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -120,7 +120,8 @@ namespace ImageSharp.Tests
public const string F = "Bmp/F.bmp";
public const string Bpp8 = "Bmp/bpp8.bmp";
public const string NegHeight = "Bmp/neg_height.bmp";
- public static readonly string[] All = { Car, F, NegHeight, Bpp8 };
+ public const string CoreHeader = "Bmp/BitmapCoreHeaderQR.bmp";
+ public static readonly string[] All = { Car, F, NegHeight, CoreHeader, Bpp8 };
}
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..4c2f26da7
--- /dev/null
+++ b/tests/ImageSharp.Tests/TestImages/Formats/Bmp/BitmapCoreHeaderQR.bmp
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:04709a3b7e9a73e87f12c5c63f66bc608e3cd61c23fcd38629bb8638bbb1b4de
+size 2580