Browse Source

Wire up BmpMetadata proper

pull/2751/head
James Jackson-South 2 years ago
parent
commit
d52815bfd0
  1. 96
      src/ImageSharp/Formats/Bmp/BmpMetadata.cs
  2. 2
      src/ImageSharp/Formats/FormatConnectingMetadata.cs
  3. 7
      src/ImageSharp/PixelFormats/PixelColorType.cs
  4. 13
      src/ImageSharp/PixelFormats/PixelComponentInfo.cs
  5. 37
      tests/ImageSharp.Tests/PixelFormats/PixelColorTypeTests.cs

96
src/ImageSharp/Formats/Bmp/BmpMetadata.cs

@ -1,6 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.PixelFormats;
// TODO: Add color table information.
namespace SixLabors.ImageSharp.Formats.Bmp;
/// <summary>
@ -37,25 +40,106 @@ public class BmpMetadata : IFormatMetadata<BmpMetadata>, IFormatFrameMetadata<Bm
/// <inheritdoc/>
public static BmpMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata)
=> throw new NotImplementedException();
{
int bpp = metadata.PixelTypeInfo.BitsPerPixel;
if (bpp == 1)
{
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel1 };
}
if (bpp == 2)
{
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel2 };
}
if (bpp <= 4)
{
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel4 };
}
if (bpp <= 8)
{
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel8 };
}
if (bpp <= 16)
{
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel16, InfoHeaderType = BmpInfoHeaderType.WinVersion3 };
}
if (bpp <= 24)
{
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel24, InfoHeaderType = BmpInfoHeaderType.WinVersion4 };
}
return new BmpMetadata { BitsPerPixel = BmpBitsPerPixel.Pixel32, InfoHeaderType = BmpInfoHeaderType.WinVersion5 };
}
/// <inheritdoc/>
public static BmpMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata)
=> throw new NotImplementedException();
=> new();
/// <inheritdoc/>
public FormatConnectingMetadata ToFormatConnectingMetadata()
=> throw new NotImplementedException();
{
int bpp = (int)this.BitsPerPixel;
PixelAlphaRepresentation alpha = this.InfoHeaderType switch
{
BmpInfoHeaderType.WinVersion2 or
BmpInfoHeaderType.Os2Version2Short or
BmpInfoHeaderType.WinVersion3 or
BmpInfoHeaderType.AdobeVersion3 or
BmpInfoHeaderType.Os2Version2 => PixelAlphaRepresentation.None,
BmpInfoHeaderType.AdobeVersion3WithAlpha or
BmpInfoHeaderType.WinVersion4 or
BmpInfoHeaderType.WinVersion5 or
_ => bpp < 32 ? PixelAlphaRepresentation.None : PixelAlphaRepresentation.Unassociated
};
PixelComponentInfo info = this.BitsPerPixel switch
{
BmpBitsPerPixel.Pixel1 => PixelComponentInfo.Create(1, bpp, 1),
BmpBitsPerPixel.Pixel2 => PixelComponentInfo.Create(1, bpp, 2),
BmpBitsPerPixel.Pixel4 => PixelComponentInfo.Create(1, bpp, 4),
BmpBitsPerPixel.Pixel8 => PixelComponentInfo.Create(1, bpp, 8),
// Could be 555 with padding but 565 is more common in newer bitmaps and offers
// greater accuracy due to extra green precision.
BmpBitsPerPixel.Pixel16 => PixelComponentInfo.Create(3, bpp, 5, 6, 5),
BmpBitsPerPixel.Pixel24 => PixelComponentInfo.Create(3, bpp, 8, 8, 8),
BmpBitsPerPixel.Pixel32 or _ => PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8),
};
PixelColorType color = this.BitsPerPixel switch
{
BmpBitsPerPixel.Pixel1 or
BmpBitsPerPixel.Pixel2 or
BmpBitsPerPixel.Pixel4 or
BmpBitsPerPixel.Pixel8 => PixelColorType.Indexed,
BmpBitsPerPixel.Pixel16 or
BmpBitsPerPixel.Pixel24 => PixelColorType.RGB,
BmpBitsPerPixel.Pixel32 or _ => PixelColorType.RGB | PixelColorType.Alpha,
};
return new()
{
PixelTypeInfo = new PixelTypeInfo(bpp)
{
AlphaRepresentation = alpha,
ComponentInfo = info,
ColorType = color
}
};
}
/// <inheritdoc/>
public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata()
=> throw new NotImplementedException();
=> new();
/// <inheritdoc/>
public IDeepCloneable DeepClone() => ((IDeepCloneable<BmpMetadata>)this).DeepClone();
/// <inheritdoc/>
BmpMetadata IDeepCloneable<BmpMetadata>.DeepClone() => new(this);
// TODO: Colors used once we support encoding palette bmps.
}

2
src/ImageSharp/Formats/FormatConnectingMetadata.cs

@ -34,7 +34,7 @@ public class FormatConnectingMetadata
/// <remarks>
/// Defaults to <see cref="FrameColorTableMode.Global"/>.
/// </remarks>
public FrameColorTableMode ColorTableMode { get; init; }
public FrameColorTableMode ColorTableMode { get; init; } = FrameColorTableMode.Global;
/// <summary>
/// Gets the default background color of the canvas when animating.

7
src/ImageSharp/PixelFormats/PixelColorType.cs

@ -99,8 +99,13 @@ public enum PixelColorType
/// </summary>
YCCK = Luminance | ChrominanceBlue | ChrominanceRed | Key,
/// <summary>
/// Indicates that the color is indexed using a palette.
/// </summary>
Indexed = 1 << 14,
/// <summary>
/// Indicates that the color is of a type not specified in this enum.
/// </summary>
Other = 1 << 14
Other = 1 << 15
}

13
src/ImageSharp/PixelFormats/PixelComponentInfo.cs

@ -41,6 +41,17 @@ public readonly struct PixelComponentInfo
/// <exception cref="ArgumentOutOfRangeException">The component precision and index cannot exceed the component range.</exception>
public static PixelComponentInfo Create<TPixel>(int count, params int[] precision)
where TPixel : unmanaged, IPixel<TPixel>
=> Create(count, Unsafe.SizeOf<TPixel>() * 8, precision);
/// <summary>
/// Creates a new <see cref="PixelComponentInfo"/> instance.
/// </summary>
/// <param name="count">The number of components within the pixel format.</param>
/// <param name="bitsPerPixel">The number of bits per pixel.</param>
/// <param name="precision">The precision in bits of each component.</param>
/// <returns>The <see cref="PixelComponentInfo"/>.</returns>
/// <exception cref="ArgumentOutOfRangeException">The component precision and index cannot exceed the component range.</exception>
public static PixelComponentInfo Create(int count, int bitsPerPixel, params int[] precision)
{
if (precision.Length != count || precision.Length > 16)
{
@ -70,7 +81,7 @@ public readonly struct PixelComponentInfo
sum += p;
}
return new PixelComponentInfo(count, (Unsafe.SizeOf<TPixel>() * 8) - sum, precisionData1, precisionData2);
return new PixelComponentInfo(count, bitsPerPixel - sum, precisionData1, precisionData2);
}
/// <summary>

37
tests/ImageSharp.Tests/PixelFormats/PixelColorTypeTests.cs

@ -140,6 +140,13 @@ public class PixelColorTypeTests
Assert.True(colorType.HasFlag(PixelColorType.Key));
}
[Fact]
public void PixelColorType_Indexed_ShouldBeSet()
{
const PixelColorType colorType = PixelColorType.Indexed;
Assert.True(colorType.HasFlag(PixelColorType.Indexed));
}
[Fact]
public void PixelColorType_Other_ShouldBeSet()
{
@ -166,6 +173,7 @@ public class PixelColorTypeTests
Assert.False(colorType.HasFlag(PixelColorType.Magenta));
Assert.False(colorType.HasFlag(PixelColorType.Yellow));
Assert.False(colorType.HasFlag(PixelColorType.Key));
Assert.False(colorType.HasFlag(PixelColorType.Indexed));
Assert.False(colorType.HasFlag(PixelColorType.Other));
}
@ -181,6 +189,7 @@ public class PixelColorTypeTests
Assert.False(colorType.HasFlag(PixelColorType.Magenta));
Assert.False(colorType.HasFlag(PixelColorType.Yellow));
Assert.False(colorType.HasFlag(PixelColorType.Key));
Assert.False(colorType.HasFlag(PixelColorType.Indexed));
Assert.False(colorType.HasFlag(PixelColorType.Other));
}
@ -197,6 +206,7 @@ public class PixelColorTypeTests
Assert.False(colorType.HasFlag(PixelColorType.Magenta));
Assert.False(colorType.HasFlag(PixelColorType.Yellow));
Assert.False(colorType.HasFlag(PixelColorType.Key));
Assert.False(colorType.HasFlag(PixelColorType.Indexed));
Assert.False(colorType.HasFlag(PixelColorType.Other));
}
@ -212,6 +222,7 @@ public class PixelColorTypeTests
Assert.False(colorType.HasFlag(PixelColorType.Luminance));
Assert.False(colorType.HasFlag(PixelColorType.ChrominanceBlue));
Assert.False(colorType.HasFlag(PixelColorType.ChrominanceRed));
Assert.False(colorType.HasFlag(PixelColorType.Indexed));
Assert.False(colorType.HasFlag(PixelColorType.Other));
}
@ -227,6 +238,31 @@ public class PixelColorTypeTests
Assert.False(colorType.HasFlag(PixelColorType.Cyan));
Assert.False(colorType.HasFlag(PixelColorType.Magenta));
Assert.False(colorType.HasFlag(PixelColorType.Yellow));
Assert.False(colorType.HasFlag(PixelColorType.Indexed));
Assert.False(colorType.HasFlag(PixelColorType.Other));
}
[Fact]
public void PixelColorType_Indexed_ShouldNotContainOtherFlags()
{
const PixelColorType colorType = PixelColorType.Indexed;
Assert.False(colorType.HasFlag(PixelColorType.Red));
Assert.False(colorType.HasFlag(PixelColorType.Green));
Assert.False(colorType.HasFlag(PixelColorType.Blue));
Assert.False(colorType.HasFlag(PixelColorType.Alpha));
Assert.False(colorType.HasFlag(PixelColorType.Grayscale));
Assert.False(colorType.HasFlag(PixelColorType.RGB));
Assert.False(colorType.HasFlag(PixelColorType.BGR));
Assert.False(colorType.HasFlag(PixelColorType.Luminance));
Assert.False(colorType.HasFlag(PixelColorType.ChrominanceBlue));
Assert.False(colorType.HasFlag(PixelColorType.ChrominanceRed));
Assert.False(colorType.HasFlag(PixelColorType.YCbCr));
Assert.False(colorType.HasFlag(PixelColorType.Cyan));
Assert.False(colorType.HasFlag(PixelColorType.Magenta));
Assert.False(colorType.HasFlag(PixelColorType.Yellow));
Assert.False(colorType.HasFlag(PixelColorType.Key));
Assert.False(colorType.HasFlag(PixelColorType.CMYK));
Assert.False(colorType.HasFlag(PixelColorType.YCCK));
Assert.False(colorType.HasFlag(PixelColorType.Other));
}
@ -251,5 +287,6 @@ public class PixelColorTypeTests
Assert.False(colorType.HasFlag(PixelColorType.Key));
Assert.False(colorType.HasFlag(PixelColorType.CMYK));
Assert.False(colorType.HasFlag(PixelColorType.YCCK));
Assert.False(colorType.HasFlag(PixelColorType.Indexed));
}
}

Loading…
Cancel
Save