diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index dfbd44c046..f4a009dd28 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -34,29 +34,29 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private const int Rgb16BMask = 0x1F;
///
- /// RLE8 flag value that indicates following byte has special meaning
+ /// RLE8 flag value that indicates following byte has special meaning.
///
private const int RleCommand = 0x00;
///
- /// RLE8 flag value marking end of a scan line
+ /// RLE8 flag value marking end of a scan line.
///
private const int RleEndOfLine = 0x00;
///
- /// RLE8 flag value marking end of bitmap data
+ /// RLE8 flag value marking end of bitmap data.
///
private const int RleEndOfBitmap = 0x01;
///
- /// RLE8 flag value marking the start of [x,y] offset instruction
+ /// RLE8 flag value marking the start of [x,y] offset instruction.
///
private const int RleDelta = 0x02;
///
/// The stream to decode from.
///
- private Stream currentStream;
+ private Stream stream;
///
/// The file header containing general information.
@@ -261,7 +261,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
while (count < buffer.Length)
{
- if (this.currentStream.Read(cmd, 0, cmd.Length) != 2)
+ if (this.stream.Read(cmd, 0, cmd.Length) != 2)
{
throw new Exception("Failed to read 2 bytes from stream");
}
@@ -283,8 +283,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp
break;
case RleDelta:
- int dx = this.currentStream.ReadByte();
- int dy = this.currentStream.ReadByte();
+ int dx = this.stream.ReadByte();
+ int dy = this.stream.ReadByte();
count += (w * dy) + dx;
break;
@@ -299,7 +299,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
length += length & 1;
byte[] run = new byte[length];
- this.currentStream.Read(run, 0, run.Length);
+ this.stream.Read(run, 0, run.Length);
for (int i = 0; i < copyLength; i++)
{
buffer[count++] = run[i];
@@ -356,7 +356,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
- this.currentStream.Read(row.Array, 0, row.Length());
+ this.stream.Read(row.Array, 0, row.Length());
int offset = 0;
Span pixelRow = pixels.GetRowSpan(newY);
@@ -402,7 +402,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
for (int y = 0; y < height; y++)
{
- this.currentStream.Read(buffer.Array, 0, stride);
+ this.stream.Read(buffer.Array, 0, stride);
int newY = Invert(y, height, inverted);
Span pixelRow = pixels.GetRowSpan(newY);
@@ -440,7 +440,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
for (int y = 0; y < height; y++)
{
- this.currentStream.Read(row);
+ this.stream.Read(row);
int newY = Invert(y, height, inverted);
Span pixelSpan = pixels.GetRowSpan(newY);
PixelOperations.Instance.PackFromBgr24Bytes(row.Span, pixelSpan, width);
@@ -465,7 +465,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
for (int y = 0; y < height; y++)
{
- this.currentStream.Read(row);
+ this.stream.Read(row);
int newY = Invert(y, height, inverted);
Span pixelSpan = pixels.GetRowSpan(newY);
PixelOperations.Instance.PackFromBgra32Bytes(row.Span, pixelSpan, width);
@@ -478,98 +478,43 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
private void ReadInfoHeader()
{
- byte[] data = new byte[BmpInfoHeader.MaxHeaderSize];
+ byte[] buffer = new byte[BmpInfoHeader.MaxHeaderSize]; // TODO: Stackalloc
// read header size
- this.currentStream.Read(data, 0, BmpInfoHeader.HeaderSizeSize);
- int headerSize = BitConverter.ToInt32(data, 0);
- if (headerSize < BmpInfoHeader.BitmapCoreHeaderSize)
+ this.stream.Read(buffer, 0, BmpInfoHeader.HeaderSizeSize);
+ int headerSize = BitConverter.ToInt32(buffer, 0);
+ if (headerSize < BmpInfoHeader.CoreSize)
{
throw new NotSupportedException($"This kind of bitmap files (header size $headerSize) is not supported.");
}
- int skipAmmount = 0;
+ int skipAmount = 0;
if (headerSize > BmpInfoHeader.MaxHeaderSize)
{
- skipAmmount = headerSize - BmpInfoHeader.MaxHeaderSize;
+ skipAmount = headerSize - BmpInfoHeader.MaxHeaderSize;
headerSize = BmpInfoHeader.MaxHeaderSize;
}
// read the rest of the header
- this.currentStream.Read(data, BmpInfoHeader.HeaderSizeSize, headerSize - BmpInfoHeader.HeaderSizeSize);
+ this.stream.Read(buffer, BmpInfoHeader.HeaderSizeSize, headerSize - BmpInfoHeader.HeaderSizeSize);
- switch (headerSize)
+ if (headerSize == BmpInfoHeader.CoreSize)
{
- case BmpInfoHeader.BitmapCoreHeaderSize:
- this.infoHeader = this.ParseBitmapCoreHeader(data);
- break;
- case BmpInfoHeader.BitmapInfoHeaderSize:
- this.infoHeader = this.ParseBitmapInfoHeader(data);
- break;
- default:
- if (headerSize > BmpInfoHeader.BitmapInfoHeaderSize)
- {
- this.infoHeader = this.ParseBitmapInfoHeader(data);
- break;
- }
- else
- {
- throw new NotSupportedException($"This kind of bitmap files (header size $headerSize) is not supported.");
- }
+ // 12 bytes
+ this.infoHeader = BmpInfoHeader.ParseCore(buffer);
}
-
- // skip the remaining header because we can't read those parts
- this.currentStream.Skip(skipAmmount);
- }
-
- ///
- /// 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
+ else if (headerSize >= BmpInfoHeader.Size)
{
- 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
- };
- }
-
- ///
- /// 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
+ // >= 40 bytes
+ this.infoHeader = BmpInfoHeader.Parse(buffer);
+ }
+ else
{
- HeaderSize = BitConverter.ToInt32(data, 0),
- Width = BitConverter.ToInt32(data, 4),
- Height = BitConverter.ToInt32(data, 8),
- Planes = BitConverter.ToInt16(data, 12),
- BitsPerPixel = BitConverter.ToInt16(data, 14),
- ImageSize = BitConverter.ToInt32(data, 20),
- XPelsPerMeter = BitConverter.ToInt32(data, 24),
- YPelsPerMeter = BitConverter.ToInt32(data, 28),
- ClrUsed = BitConverter.ToInt32(data, 32),
- ClrImportant = BitConverter.ToInt32(data, 36),
- Compression = (BmpCompression)BitConverter.ToInt32(data, 16)
- };
+ throw new NotSupportedException($"ImageSharp does not support this BMP file. HeaderSize: {headerSize}.");
+ }
+
+ // skip the remaining header because we can't read those parts
+ this.stream.Skip(skipAmount);
}
///
@@ -577,15 +522,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
private void ReadFileHeader()
{
- byte[] data = new byte[BmpFileHeader.Size];
+ byte[] data = new byte[BmpFileHeader.Size]; // TODO: Stackalloc
- this.currentStream.Read(data, 0, BmpFileHeader.Size);
+ this.stream.Read(data, 0, BmpFileHeader.Size);
- this.fileHeader = new BmpFileHeader(
- type: BitConverter.ToInt16(data, 0),
- fileSize: BitConverter.ToInt32(data, 2),
- reserved: BitConverter.ToInt32(data, 6),
- offset: BitConverter.ToInt32(data, 10));
+ this.fileHeader = BmpFileHeader.Parse(data);
}
///
@@ -593,7 +534,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
private void ReadImageHeaders(Stream stream, out bool inverted, out byte[] palette)
{
- this.currentStream = stream;
+ this.stream = stream;
try
{
@@ -640,7 +581,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
palette = new byte[colorMapSize];
- this.currentStream.Read(palette, 0, colorMapSize);
+ this.stream.Read(palette, 0, colorMapSize);
}
if (this.infoHeader.Width > int.MaxValue || this.infoHeader.Height > int.MaxValue)
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index 1e0ecd3b14..2b0c907338 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
@@ -18,9 +18,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
private int padding;
- ///
- /// Gets or sets the number of bits per pixel.
- ///
private readonly BmpBitsPerPixel bitsPerPixel;
private readonly MemoryManager memoryManager;
@@ -53,17 +50,15 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32);
this.padding = bytesPerLine - (image.Width * (int)this.bitsPerPixel);
- var infoHeader = new BmpInfoHeader
- {
- HeaderSize = BmpInfoHeader.BitmapInfoHeaderSize,
- Height = image.Height,
- Width = image.Width,
- BitsPerPixel = bpp,
- Planes = 1,
- ImageSize = image.Height * bytesPerLine,
- ClrUsed = 0,
- ClrImportant = 0
- };
+ var infoHeader = new BmpInfoHeader(
+ headerSize: BmpInfoHeader.Size,
+ height: image.Height,
+ width: image.Width,
+ bitsPerPixel: bpp,
+ planes: 1,
+ imageSize: image.Height * bytesPerLine,
+ clrUsed: 0,
+ clrImportant: 0);
var fileHeader = new BmpFileHeader(
type: 19778, // BM
diff --git a/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs
index 64474ad909..d94fefa057 100644
--- a/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Buffers.Binary;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Bmp
@@ -57,14 +56,17 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
public int Offset { get; }
+ public static BmpFileHeader Parse(Span data)
+ {
+ return MemoryMarshal.Cast(data)[0];
+ }
+
public unsafe void WriteTo(Span buffer)
{
fixed (BmpFileHeader* pointer = &this)
{
MemoryMarshal.AsBytes(new ReadOnlySpan(pointer, 1)).CopyTo(buffer);
}
-
- // TODO: Big Endian Platforms
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
index b38cfd450f..d7fb2f844e 100644
--- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Buffers.Binary;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Bmp
@@ -14,28 +15,52 @@ namespace SixLabors.ImageSharp.Formats.Bmp
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct BmpInfoHeader
{
- // TODO: Make readonly
-
///
/// Defines the size of the BITMAPINFOHEADER data structure in the bitmap file.
///
- public const int BitmapInfoHeaderSize = 40;
+ public const int Size = 40;
///
/// Defines the size of the BITMAPCOREHEADER data structure in the bitmap file.
///
- public const int BitmapCoreHeaderSize = 12;
+ public const int CoreSize = 12;
///
/// Defines the size of the biggest supported header data structure in the bitmap file.
///
- public const int MaxHeaderSize = BitmapInfoHeaderSize;
+ public const int MaxHeaderSize = Size;
///
/// Defines the size of the field.
///
public const int HeaderSizeSize = 4;
+ public BmpInfoHeader(
+ int headerSize,
+ int width,
+ int height,
+ short planes,
+ short bitsPerPixel,
+ BmpCompression compression = default,
+ int imageSize = 0,
+ int xPelsPerMeter = 0,
+ int yPelsPerMeter = 0,
+ int clrUsed = 0,
+ int clrImportant = 0)
+ {
+ this.HeaderSize = headerSize;
+ this.Width = width;
+ this.Height = height;
+ this.Planes = planes;
+ this.BitsPerPixel = bitsPerPixel;
+ this.Compression = compression;
+ this.ImageSize = imageSize;
+ this.XPelsPerMeter = xPelsPerMeter;
+ this.YPelsPerMeter = yPelsPerMeter;
+ this.ClrUsed = clrUsed;
+ this.ClrImportant = clrImportant;
+ }
+
///
/// Gets or sets the size of this header
///
@@ -98,14 +123,40 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
public int ClrImportant { get; set; }
+
+ ///
+ /// Parses the full BITMAPINFOHEADER header (40 bytes).
+ ///
+ /// The data to parse.
+ /// Parsed header
+ ///
+ public static BmpInfoHeader Parse(ReadOnlySpan data)
+ {
+ return MemoryMarshal.Cast(data)[0];
+ }
+
+ ///
+ /// Parses the BITMAPCOREHEADER consisting of the headerSize, width, height, planes, and bitsPerPixel fields (12 bytes).
+ ///
+ /// The data to parse,
+ /// Parsed header
+ ///
+ public static BmpInfoHeader ParseCore(ReadOnlySpan data)
+ {
+ return new BmpInfoHeader(
+ headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)),
+ width: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(4, 2)),
+ height: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(6, 2)),
+ planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(8, 2)),
+ bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(10, 2)));
+ }
+
public unsafe void WriteTo(Span buffer)
{
fixed (BmpInfoHeader* pointer = &this)
{
MemoryMarshal.AsBytes(new ReadOnlySpan(pointer, 1)).CopyTo(buffer);
}
-
- // TODO: Big Endian Platforms
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs
index 920c9ce028..c44ca73f2e 100644
--- a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs
+++ b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs
@@ -1,11 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Collections.Generic;
-using System.IO;
-using SixLabors.ImageSharp.PixelFormats;
-
namespace SixLabors.ImageSharp.Formats.Bmp
{
///
@@ -15,4 +10,4 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
// added this for consistancy so we can add stuff as required, no options currently availible
}
-}
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs
index c4e219889d..0bfd6980bf 100644
--- a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs
+++ b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs
@@ -1,11 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Collections.Generic;
-using System.IO;
-using SixLabors.ImageSharp.PixelFormats;
-
namespace SixLabors.ImageSharp.Formats.Bmp
{
///
diff --git a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs
index 35e168e278..57e4615bad 100644
--- a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs
+++ b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs
@@ -1,10 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System;
using System.IO;
using SixLabors.ImageSharp.Advanced;
-using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.PixelFormats;