diff --git a/src/ImageSharp/Formats/Bmp/BmpColorSpace.cs b/src/ImageSharp/Formats/Bmp/BmpColorSpace.cs
new file mode 100644
index 000000000..864087121
--- /dev/null
+++ b/src/ImageSharp/Formats/Bmp/BmpColorSpace.cs
@@ -0,0 +1,37 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+// ReSharper disable InconsistentNaming
+namespace SixLabors.ImageSharp.Formats.Bmp
+{
+ ///
+ /// Enum for the different color spaces.
+ ///
+ internal enum BmpColorSpace
+ {
+ ///
+ /// This value implies that endpoints and gamma values are given in the appropriate fields.
+ ///
+ LCS_CALIBRATED_RGB = 0,
+
+ ///
+ /// The Windows default color space ('Win ').
+ ///
+ LCS_WINDOWS_COLOR_SPACE = 1466527264,
+
+ ///
+ /// Specifies that the bitmap is in sRGB color space ('sRGB').
+ ///
+ LCS_sRGB = 1934772034,
+
+ ///
+ /// This value indicates that bV5ProfileData points to the file name of the profile to use (gamma and endpoints values are ignored).
+ ///
+ PROFILE_LINKED = 1279872587,
+
+ ///
+ /// This value indicates that bV5ProfileData points to a memory buffer that contains the profile to be used (gamma and endpoints values are ignored).
+ ///
+ PROFILE_EMBEDDED = 1296188740
+ }
+}
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index a22a04980..ab0f1bd03 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -1271,12 +1271,18 @@ namespace SixLabors.ImageSharp.Formats.Bmp
infoHeaderType = BmpInfoHeaderType.Os2Version2;
this.infoHeader = BmpInfoHeader.ParseOs2Version2(buffer);
}
- else if (headerSize >= BmpInfoHeader.SizeV4)
+ else if (headerSize == BmpInfoHeader.SizeV4)
{
- // >= 108 bytes
- infoHeaderType = headerSize == BmpInfoHeader.SizeV4 ? BmpInfoHeaderType.WinVersion4 : BmpInfoHeaderType.WinVersion5;
+ // == 108 bytes
+ infoHeaderType = BmpInfoHeaderType.WinVersion4;
this.infoHeader = BmpInfoHeader.ParseV4(buffer);
}
+ else if (headerSize > BmpInfoHeader.SizeV4)
+ {
+ // > 108 bytes
+ infoHeaderType = BmpInfoHeaderType.WinVersion5;
+ this.infoHeader = BmpInfoHeader.ParseV5(buffer);
+ }
else
{
BmpThrowHelper.ThrowNotSupportedException($"ImageSharp does not support this BMP file. HeaderSize '{headerSize}'.");
diff --git a/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs
index acbcdaef3..ab56bd246 100644
--- a/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs
@@ -57,10 +57,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
public int Offset { get; }
- public static BmpFileHeader Parse(Span data)
- {
- return MemoryMarshal.Cast(data)[0];
- }
+ public static BmpFileHeader Parse(Span data) => MemoryMarshal.Cast(data)[0];
public void WriteTo(Span buffer)
{
diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
index 0d0c05c9f..70462b73a 100644
--- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
@@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int greenMask = 0,
int blueMask = 0,
int alphaMask = 0,
- int csType = 0,
+ BmpColorSpace csType = 0,
int redX = 0,
int redY = 0,
int redZ = 0,
@@ -94,7 +94,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int blueZ = 0,
int gammeRed = 0,
int gammeGreen = 0,
- int gammeBlue = 0)
+ int gammeBlue = 0,
+ BmpRenderingIntent intent = BmpRenderingIntent.Invalid,
+ int profileData = 0,
+ int profileSize = 0,
+ int reserved = 0)
{
this.HeaderSize = headerSize;
this.Width = width;
@@ -124,6 +128,10 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.GammaRed = gammeRed;
this.GammaGreen = gammeGreen;
this.GammaBlue = gammeBlue;
+ this.Intent = intent;
+ this.ProfileData = profileData;
+ this.ProfileSize = profileSize;
+ this.Reserved = reserved;
}
///
@@ -211,7 +219,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
/// Gets or sets the Color space type. Not used yet.
///
- public int CsType { get; set; }
+ public BmpColorSpace CsType { get; set; }
///
/// Gets or sets the X coordinate of red endpoint. Not used yet.
@@ -273,21 +281,38 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
public int GammaBlue { get; set; }
+ ///
+ /// Gets or sets the rendering intent for bitmap.
+ ///
+ public BmpRenderingIntent Intent { get; set; }
+
+ ///
+ /// Gets or sets the offset, in bytes, from the beginning of the BITMAPV5HEADER structure to the start of the profile data.
+ ///
+ public int ProfileData { get; set; }
+
+ ///
+ /// Gets or sets the size, in bytes, of embedded profile data.
+ ///
+ public int ProfileSize { get; set; }
+
+ ///
+ /// Gets or sets the reserved value.
+ ///
+ public int Reserved { get; set; }
+
///
/// Parses the BITMAPCOREHEADER (BMP Version 2) consisting of the headerSize, width, height, planes, and bitsPerPixel fields (12 bytes).
///
/// The data to parse.
/// The parsed header.
///
- public static BmpInfoHeader ParseCore(ReadOnlySpan data)
- {
- return new BmpInfoHeader(
+ public static BmpInfoHeader ParseCore(ReadOnlySpan data) => new(
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)));
- }
///
/// Parses a short variant of the OS22XBITMAPHEADER. It is identical to the BITMAPCOREHEADER, except that the width and height
@@ -296,15 +321,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// The data to parse.
/// The parsed header.
///
- public static BmpInfoHeader ParseOs22Short(ReadOnlySpan data)
- {
- return new BmpInfoHeader(
+ public static BmpInfoHeader ParseOs22Short(ReadOnlySpan data) => new(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)),
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)));
- }
///
/// Parses the full BMP Version 3 BITMAPINFOHEADER header (40 bytes).
@@ -312,9 +334,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// The data to parse.
/// The parsed header.
///
- public static BmpInfoHeader ParseV3(ReadOnlySpan data)
- {
- return new BmpInfoHeader(
+ public static BmpInfoHeader ParseV3(ReadOnlySpan data) => new(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)),
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
@@ -326,7 +346,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
yPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(28, 4)),
clrUsed: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(32, 4)),
clrImportant: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(36, 4)));
- }
///
/// Special case of the BITMAPINFOHEADER V3 used by adobe where the color bitmasks are part of the info header instead of following it.
@@ -336,9 +355,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// Indicates, if the alpha bitmask is present.
/// The parsed header.
///
- public static BmpInfoHeader ParseAdobeV3(ReadOnlySpan data, bool withAlpha = true)
- {
- return new BmpInfoHeader(
+ public static BmpInfoHeader ParseAdobeV3(ReadOnlySpan data, bool withAlpha = true) => new(
headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)),
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
@@ -354,7 +371,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
greenMask: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(44, 4)),
blueMask: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(48, 4)),
alphaMask: withAlpha ? BinaryPrimitives.ReadInt32LittleEndian(data.Slice(52, 4)) : 0);
- }
///
/// Parses a OS/2 version 2 bitmap header (64 bytes). Only the first 40 bytes are parsed which are
@@ -413,11 +429,47 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// The data to parse.
/// The parsed header.
///
- public static BmpInfoHeader ParseV4(ReadOnlySpan data)
+ public static BmpInfoHeader ParseV4(ReadOnlySpan data) => new(
+ headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)),
+ width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
+ height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
+ planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
+ bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)),
+ compression: (BmpCompression)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)),
+ imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)),
+ xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)),
+ yPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(28, 4)),
+ clrUsed: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(32, 4)),
+ clrImportant: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(36, 4)),
+ redMask: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(40, 4)),
+ greenMask: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(44, 4)),
+ blueMask: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(48, 4)),
+ alphaMask: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(52, 4)),
+ csType: (BmpColorSpace)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(56, 4)),
+ redX: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(60, 4)),
+ redY: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(64, 4)),
+ redZ: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(68, 4)),
+ greenX: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(72, 4)),
+ greenY: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(76, 4)),
+ greenZ: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(80, 4)),
+ blueX: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(84, 4)),
+ blueY: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(88, 4)),
+ blueZ: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(92, 4)),
+ gammeRed: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(96, 4)),
+ gammeGreen: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(100, 4)),
+ gammeBlue: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(104, 4)));
+
+ ///
+ /// Parses the full BMP Version 5 BITMAPINFOHEADER header (124 bytes).
+ ///
+ /// The data to parse.
+ /// The parsed header.
+ ///
+ public static BmpInfoHeader ParseV5(ReadOnlySpan data)
{
- if (data.Length < SizeV4)
+ if (data.Length < SizeV5)
{
- throw new ArgumentException(nameof(data), $"Must be {SizeV4} bytes. Was {data.Length} bytes.");
+ throw new ArgumentException(nameof(data), $"Must be {SizeV5} bytes. Was {data.Length} bytes.");
}
return MemoryMarshal.Cast(data)[0];
diff --git a/src/ImageSharp/Formats/Bmp/BmpRenderingIntent.cs b/src/ImageSharp/Formats/Bmp/BmpRenderingIntent.cs
new file mode 100644
index 000000000..8e0362595
--- /dev/null
+++ b/src/ImageSharp/Formats/Bmp/BmpRenderingIntent.cs
@@ -0,0 +1,37 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+// ReSharper disable InconsistentNaming
+namespace SixLabors.ImageSharp.Formats.Bmp
+{
+ ///
+ /// Enum for the different rendering intent's.
+ ///
+ internal enum BmpRenderingIntent
+ {
+ ///
+ /// Invalid default value.
+ ///
+ Invalid = 0,
+
+ ///
+ /// TMaintains saturation. Used for business charts and other situations in which undithered colors are required.
+ ///
+ LCS_GM_BUSINESS = 1,
+
+ ///
+ /// Maintains colorimetric match. Used for graphic designs and named colors.
+ ///
+ LCS_GM_GRAPHICS = 2,
+
+ ///
+ /// Maintains contrast. Used for photographs and natural images.
+ ///
+ LCS_GM_IMAGES = 4,
+
+ ///
+ /// Maintains the white point. Matches the colors to their nearest color in the destination gamut.
+ ///
+ LCS_GM_ABS_COLORIMETRIC = 8,
+ }
+}