Skip to content

Commit d52815b

Browse files
Wire up BmpMetadata proper
1 parent a971082 commit d52815b

5 files changed

Lines changed: 146 additions & 9 deletions

File tree

src/ImageSharp/Formats/Bmp/BmpMetadata.cs

Lines changed: 90 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Six Labors Split License.
33

4+
using SixLabors.ImageSharp.PixelFormats;
5+
6+
// TODO: Add color table information.
47
namespace SixLabors.ImageSharp.Formats.Bmp;
58

69
/// <summary>
@@ -37,25 +40,106 @@ private BmpMetadata(BmpMetadata other)
3740

3841
/// <inheritdoc/>
3942
public static BmpMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata)
40-
=> throw new NotImplementedException();
43+
{
44+
int bpp = metadata.PixelTypeInfo.BitsPerPixel;
45+
if (bpp == 1)
46+
{
47+
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel1 };
48+
}
49+
50+
if (bpp == 2)
51+
{
52+
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel2 };
53+
}
54+
55+
if (bpp <= 4)
56+
{
57+
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel4 };
58+
}
59+
60+
if (bpp <= 8)
61+
{
62+
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel8 };
63+
}
64+
65+
if (bpp <= 16)
66+
{
67+
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel16, InfoHeaderType = BmpInfoHeaderType.WinVersion3 };
68+
}
69+
70+
if (bpp <= 24)
71+
{
72+
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel24, InfoHeaderType = BmpInfoHeaderType.WinVersion4 };
73+
}
74+
75+
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel32, InfoHeaderType = BmpInfoHeaderType.WinVersion5 };
76+
}
4177

4278
/// <inheritdoc/>
4379
public static BmpMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata)
44-
=> throw new NotImplementedException();
80+
=> new();
4581

4682
/// <inheritdoc/>
4783
public FormatConnectingMetadata ToFormatConnectingMetadata()
48-
=> throw new NotImplementedException();
84+
{
85+
int bpp = (int)this.BitsPerPixel;
86+
87+
PixelAlphaRepresentation alpha = this.InfoHeaderType switch
88+
{
89+
BmpInfoHeaderType.WinVersion2 or
90+
BmpInfoHeaderType.Os2Version2Short or
91+
BmpInfoHeaderType.WinVersion3 or
92+
BmpInfoHeaderType.AdobeVersion3 or
93+
BmpInfoHeaderType.Os2Version2 => PixelAlphaRepresentation.None,
94+
BmpInfoHeaderType.AdobeVersion3WithAlpha or
95+
BmpInfoHeaderType.WinVersion4 or
96+
BmpInfoHeaderType.WinVersion5 or
97+
_ => bpp < 32 ? PixelAlphaRepresentation.None : PixelAlphaRepresentation.Unassociated
98+
};
99+
100+
PixelComponentInfo info = this.BitsPerPixel switch
101+
{
102+
BmpBitsPerPixel.Pixel1 => PixelComponentInfo.Create(1, bpp, 1),
103+
BmpBitsPerPixel.Pixel2 => PixelComponentInfo.Create(1, bpp, 2),
104+
BmpBitsPerPixel.Pixel4 => PixelComponentInfo.Create(1, bpp, 4),
105+
BmpBitsPerPixel.Pixel8 => PixelComponentInfo.Create(1, bpp, 8),
106+
107+
// Could be 555 with padding but 565 is more common in newer bitmaps and offers
108+
// greater accuracy due to extra green precision.
109+
BmpBitsPerPixel.Pixel16 => PixelComponentInfo.Create(3, bpp, 5, 6, 5),
110+
BmpBitsPerPixel.Pixel24 => PixelComponentInfo.Create(3, bpp, 8, 8, 8),
111+
BmpBitsPerPixel.Pixel32 or _ => PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8),
112+
};
113+
114+
PixelColorType color = this.BitsPerPixel switch
115+
{
116+
BmpBitsPerPixel.Pixel1 or
117+
BmpBitsPerPixel.Pixel2 or
118+
BmpBitsPerPixel.Pixel4 or
119+
BmpBitsPerPixel.Pixel8 => PixelColorType.Indexed,
120+
BmpBitsPerPixel.Pixel16 or
121+
BmpBitsPerPixel.Pixel24 => PixelColorType.RGB,
122+
BmpBitsPerPixel.Pixel32 or _ => PixelColorType.RGB | PixelColorType.Alpha,
123+
};
124+
125+
return new()
126+
{
127+
PixelTypeInfo = new PixelTypeInfo(bpp)
128+
{
129+
AlphaRepresentation = alpha,
130+
ComponentInfo = info,
131+
ColorType = color
132+
}
133+
};
134+
}
49135

50136
/// <inheritdoc/>
51137
public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata()
52-
=> throw new NotImplementedException();
138+
=> new();
53139

54140
/// <inheritdoc/>
55141
public IDeepCloneable DeepClone() => ((IDeepCloneable<BmpMetadata>)this).DeepClone();
56142

57143
/// <inheritdoc/>
58144
BmpMetadata IDeepCloneable<BmpMetadata>.DeepClone() => new(this);
59-
60-
// TODO: Colors used once we support encoding palette bmps.
61145
}

src/ImageSharp/Formats/FormatConnectingMetadata.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class FormatConnectingMetadata
3434
/// <remarks>
3535
/// Defaults to <see cref="FrameColorTableMode.Global"/>.
3636
/// </remarks>
37-
public FrameColorTableMode ColorTableMode { get; init; }
37+
public FrameColorTableMode ColorTableMode { get; init; } = FrameColorTableMode.Global;
3838

3939
/// <summary>
4040
/// Gets the default background color of the canvas when animating.

src/ImageSharp/PixelFormats/PixelColorType.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,13 @@ public enum PixelColorType
9999
/// </summary>
100100
YCCK = Luminance | ChrominanceBlue | ChrominanceRed | Key,
101101

102+
/// <summary>
103+
/// Indicates that the color is indexed using a palette.
104+
/// </summary>
105+
Indexed = 1 << 14,
106+
102107
/// <summary>
103108
/// Indicates that the color is of a type not specified in this enum.
104109
/// </summary>
105-
Other = 1 << 14
110+
Other = 1 << 15
106111
}

src/ImageSharp/PixelFormats/PixelComponentInfo.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ private PixelComponentInfo(int count, int padding, long precisionData1, long pre
4141
/// <exception cref="ArgumentOutOfRangeException">The component precision and index cannot exceed the component range.</exception>
4242
public static PixelComponentInfo Create<TPixel>(int count, params int[] precision)
4343
where TPixel : unmanaged, IPixel<TPixel>
44+
=> Create(count, Unsafe.SizeOf<TPixel>() * 8, precision);
45+
46+
/// <summary>
47+
/// Creates a new <see cref="PixelComponentInfo"/> instance.
48+
/// </summary>
49+
/// <param name="count">The number of components within the pixel format.</param>
50+
/// <param name="bitsPerPixel">The number of bits per pixel.</param>
51+
/// <param name="precision">The precision in bits of each component.</param>
52+
/// <returns>The <see cref="PixelComponentInfo"/>.</returns>
53+
/// <exception cref="ArgumentOutOfRangeException">The component precision and index cannot exceed the component range.</exception>
54+
public static PixelComponentInfo Create(int count, int bitsPerPixel, params int[] precision)
4455
{
4556
if (precision.Length != count || precision.Length > 16)
4657
{
@@ -70,7 +81,7 @@ public static PixelComponentInfo Create<TPixel>(int count, params int[] precisio
7081
sum += p;
7182
}
7283

73-
return new PixelComponentInfo(count, (Unsafe.SizeOf<TPixel>() * 8) - sum, precisionData1, precisionData2);
84+
return new PixelComponentInfo(count, bitsPerPixel - sum, precisionData1, precisionData2);
7485
}
7586

7687
/// <summary>

tests/ImageSharp.Tests/PixelFormats/PixelColorTypeTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,13 @@ public void PixelColorType_YCCKFlags_ShouldBeSet()
140140
Assert.True(colorType.HasFlag(PixelColorType.Key));
141141
}
142142

143+
[Fact]
144+
public void PixelColorType_Indexed_ShouldBeSet()
145+
{
146+
const PixelColorType colorType = PixelColorType.Indexed;
147+
Assert.True(colorType.HasFlag(PixelColorType.Indexed));
148+
}
149+
143150
[Fact]
144151
public void PixelColorType_Other_ShouldBeSet()
145152
{
@@ -166,6 +173,7 @@ public void PixelColorType_RGB_ShouldNotContainOtherFlags()
166173
Assert.False(colorType.HasFlag(PixelColorType.Magenta));
167174
Assert.False(colorType.HasFlag(PixelColorType.Yellow));
168175
Assert.False(colorType.HasFlag(PixelColorType.Key));
176+
Assert.False(colorType.HasFlag(PixelColorType.Indexed));
169177
Assert.False(colorType.HasFlag(PixelColorType.Other));
170178
}
171179

@@ -181,6 +189,7 @@ public void PixelColorType_BGR_ShouldNotContainOtherFlags()
181189
Assert.False(colorType.HasFlag(PixelColorType.Magenta));
182190
Assert.False(colorType.HasFlag(PixelColorType.Yellow));
183191
Assert.False(colorType.HasFlag(PixelColorType.Key));
192+
Assert.False(colorType.HasFlag(PixelColorType.Indexed));
184193
Assert.False(colorType.HasFlag(PixelColorType.Other));
185194
}
186195

@@ -197,6 +206,7 @@ public void PixelColorType_YCbCr_ShouldNotContainOtherFlags()
197206
Assert.False(colorType.HasFlag(PixelColorType.Magenta));
198207
Assert.False(colorType.HasFlag(PixelColorType.Yellow));
199208
Assert.False(colorType.HasFlag(PixelColorType.Key));
209+
Assert.False(colorType.HasFlag(PixelColorType.Indexed));
200210
Assert.False(colorType.HasFlag(PixelColorType.Other));
201211
}
202212

@@ -212,6 +222,7 @@ public void PixelColorType_CMYK_ShouldNotContainOtherFlags()
212222
Assert.False(colorType.HasFlag(PixelColorType.Luminance));
213223
Assert.False(colorType.HasFlag(PixelColorType.ChrominanceBlue));
214224
Assert.False(colorType.HasFlag(PixelColorType.ChrominanceRed));
225+
Assert.False(colorType.HasFlag(PixelColorType.Indexed));
215226
Assert.False(colorType.HasFlag(PixelColorType.Other));
216227
}
217228

@@ -227,6 +238,31 @@ public void PixelColorType_YCCK_ShouldNotContainOtherFlags()
227238
Assert.False(colorType.HasFlag(PixelColorType.Cyan));
228239
Assert.False(colorType.HasFlag(PixelColorType.Magenta));
229240
Assert.False(colorType.HasFlag(PixelColorType.Yellow));
241+
Assert.False(colorType.HasFlag(PixelColorType.Indexed));
242+
Assert.False(colorType.HasFlag(PixelColorType.Other));
243+
}
244+
245+
[Fact]
246+
public void PixelColorType_Indexed_ShouldNotContainOtherFlags()
247+
{
248+
const PixelColorType colorType = PixelColorType.Indexed;
249+
Assert.False(colorType.HasFlag(PixelColorType.Red));
250+
Assert.False(colorType.HasFlag(PixelColorType.Green));
251+
Assert.False(colorType.HasFlag(PixelColorType.Blue));
252+
Assert.False(colorType.HasFlag(PixelColorType.Alpha));
253+
Assert.False(colorType.HasFlag(PixelColorType.Grayscale));
254+
Assert.False(colorType.HasFlag(PixelColorType.RGB));
255+
Assert.False(colorType.HasFlag(PixelColorType.BGR));
256+
Assert.False(colorType.HasFlag(PixelColorType.Luminance));
257+
Assert.False(colorType.HasFlag(PixelColorType.ChrominanceBlue));
258+
Assert.False(colorType.HasFlag(PixelColorType.ChrominanceRed));
259+
Assert.False(colorType.HasFlag(PixelColorType.YCbCr));
260+
Assert.False(colorType.HasFlag(PixelColorType.Cyan));
261+
Assert.False(colorType.HasFlag(PixelColorType.Magenta));
262+
Assert.False(colorType.HasFlag(PixelColorType.Yellow));
263+
Assert.False(colorType.HasFlag(PixelColorType.Key));
264+
Assert.False(colorType.HasFlag(PixelColorType.CMYK));
265+
Assert.False(colorType.HasFlag(PixelColorType.YCCK));
230266
Assert.False(colorType.HasFlag(PixelColorType.Other));
231267
}
232268

@@ -251,5 +287,6 @@ public void PixelColorType_Other_ShouldNotContainPreviousFlags()
251287
Assert.False(colorType.HasFlag(PixelColorType.Key));
252288
Assert.False(colorType.HasFlag(PixelColorType.CMYK));
253289
Assert.False(colorType.HasFlag(PixelColorType.YCCK));
290+
Assert.False(colorType.HasFlag(PixelColorType.Indexed));
254291
}
255292
}

0 commit comments

Comments
 (0)