Browse Source

Use the new metadata

pull/2601/head
James Jackson-South 2 years ago
parent
commit
057edd8ddd
  1. 4
      src/ImageSharp/Color/Color.cs
  2. 2
      src/ImageSharp/Formats/Png/PngBitDepth.cs
  3. 104
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  4. 50
      src/ImageSharp/PixelFormats/PixelComponentBitDepth.cs
  5. 70
      src/ImageSharp/PixelFormats/PixelComponentPrecision.cs
  6. 3
      src/ImageSharp/PixelFormats/PixelTypeInfo.cs
  7. 20
      tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs

4
src/ImageSharp/Color/Color.cs

@ -94,7 +94,7 @@ public readonly partial struct Color : IEquatable<Color>
{ {
// Avoid boxing in case we can convert to Vector4 safely and efficiently // Avoid boxing in case we can convert to Vector4 safely and efficiently
PixelTypeInfo info = TPixel.GetPixelTypeInfo(); PixelTypeInfo info = TPixel.GetPixelTypeInfo();
if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentPrecision.Float) if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentBitDepth.Bit32)
{ {
return new(pixel.ToScaledVector4()); return new(pixel.ToScaledVector4());
} }
@ -118,7 +118,7 @@ public readonly partial struct Color : IEquatable<Color>
// Avoid boxing in case we can convert to Vector4 safely and efficiently // Avoid boxing in case we can convert to Vector4 safely and efficiently
PixelTypeInfo info = TPixel.GetPixelTypeInfo(); PixelTypeInfo info = TPixel.GetPixelTypeInfo();
if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentPrecision.Float) if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentBitDepth.Bit32)
{ {
for (int i = 0; i < destination.Length; i++) for (int i = 0; i < destination.Length; i++)
{ {

2
src/ImageSharp/Formats/Png/PngBitDepth.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
// Note the value assignment, This will allow us to add 1, 2, and 4 bit encoding when we support it. // Note the value assignment, This will allow us to add 1, 2, and 4 bit encoding when we support it.

104
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -1466,23 +1466,48 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
// Use options, then check metadata, if nothing set there then we suggest // Use options, then check metadata, if nothing set there then we suggest
// a sensible default based upon the pixel format. // a sensible default based upon the pixel format.
this.colorType = encoder.ColorType ?? pngMetadata.ColorType ?? SuggestColorType<TPixel>(); PngColorType? colorType = encoder.ColorType ?? pngMetadata.ColorType;
if (!encoder.FilterMethod.HasValue) byte? bits = (byte?)(encoder.BitDepth ?? pngMetadata.BitDepth);
if (colorType is null || bits is null)
{ {
// Specification recommends default filter method None for paletted images and Paeth for others. PixelTypeInfo info = TPixel.GetPixelTypeInfo();
this.filterMethod = this.colorType is PngColorType.Palette ? PngFilterMethod.None : PngFilterMethod.Paeth; PixelComponentInfo? componentInfo = info.ComponentInfo;
colorType ??= SuggestColorType<TPixel>(in info);
if (bits is null)
{
// TODO: Update once we stop abusing PixelTypeInfo in decoders.
if (componentInfo.HasValue)
{
PixelComponentInfo c = componentInfo.Value;
bits = (byte)SuggestBitDepth<TPixel>(in c);
}
else
{
bits = (byte)PngBitDepth.Bit8;
}
}
} }
// Ensure bit depth and color type are a supported combination. // Ensure bit depth and color type are a supported combination.
// Bit8 is the only bit depth supported by all color types. // Bit8 is the only bit depth supported by all color types.
byte bits = (byte)(encoder.BitDepth ?? pngMetadata.BitDepth ?? SuggestBitDepth<TPixel>()); byte[] validBitDepths = PngConstants.ColorTypes[colorType.Value];
byte[] validBitDepths = PngConstants.ColorTypes[this.colorType];
if (Array.IndexOf(validBitDepths, bits) == -1) if (Array.IndexOf(validBitDepths, bits) == -1)
{ {
bits = (byte)PngBitDepth.Bit8; bits = (byte)PngBitDepth.Bit8;
} }
this.bitDepth = bits; this.colorType = colorType.Value;
this.bitDepth = bits.Value;
if (!encoder.FilterMethod.HasValue)
{
// Specification recommends default filter method None for paletted images and Paeth for others.
this.filterMethod = this.colorType is PngColorType.Palette ? PngFilterMethod.None : PngFilterMethod.Paeth;
}
use16Bit = bits == (byte)PngBitDepth.Bit16; use16Bit = bits == (byte)PngBitDepth.Bit16;
bytesPerPixel = CalculateBytesPerPixel(this.colorType, use16Bit); bytesPerPixel = CalculateBytesPerPixel(this.colorType, use16Bit);
@ -1611,53 +1636,44 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
/// <summary> /// <summary>
/// Returns a suggested <see cref="PngColorType"/> for the given <typeparamref name="TPixel"/> /// Returns a suggested <see cref="PngColorType"/> for the given <typeparamref name="TPixel"/>
/// This is not exhaustive but covers many common pixel formats.
/// </summary> /// </summary>
/// <param name="info">The pixel type info.</param>
/// <typeparam name="TPixel">The type of pixel format.</typeparam> /// <typeparam name="TPixel">The type of pixel format.</typeparam>
private static PngColorType SuggestColorType<TPixel>() private static PngColorType SuggestColorType<TPixel>(in PixelTypeInfo info)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
=> default(TPixel) switch {
{ if (info.AlphaRepresentation == PixelAlphaRepresentation.None)
A8 => PngColorType.GrayscaleWithAlpha, {
Argb32 => PngColorType.RgbWithAlpha, return info.ColorType switch
Bgr24 => PngColorType.Rgb, {
Bgra32 => PngColorType.RgbWithAlpha, PixelColorType.Grayscale => PngColorType.Grayscale,
L8 => PngColorType.Grayscale, _ => PngColorType.Rgb,
L16 => PngColorType.Grayscale, };
La16 => PngColorType.GrayscaleWithAlpha, }
La32 => PngColorType.GrayscaleWithAlpha,
Rgb24 => PngColorType.Rgb, return info.ColorType switch
Rgba32 => PngColorType.RgbWithAlpha, {
Rgb48 => PngColorType.Rgb, PixelColorType.Grayscale | PixelColorType.Alpha or PixelColorType.Alpha => PngColorType.GrayscaleWithAlpha,
Rgba64 => PngColorType.RgbWithAlpha, _ => PngColorType.RgbWithAlpha,
RgbaVector => PngColorType.RgbWithAlpha,
_ => PngColorType.RgbWithAlpha
}; };
}
/// <summary> /// <summary>
/// Returns a suggested <see cref="PngBitDepth"/> for the given <typeparamref name="TPixel"/> /// Returns a suggested <see cref="PngBitDepth"/> for the given <typeparamref name="TPixel"/>
/// This is not exhaustive but covers many common pixel formats.
/// </summary> /// </summary>
/// <param name="info">The pixel type info.</param>
/// <typeparam name="TPixel">The type of pixel format.</typeparam> /// <typeparam name="TPixel">The type of pixel format.</typeparam>
private static PngBitDepth SuggestBitDepth<TPixel>() private static PngBitDepth SuggestBitDepth<TPixel>(in PixelComponentInfo info)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
=> default(TPixel) switch {
{ int bits = info.GetMaximumComponentPrecision();
A8 => PngBitDepth.Bit8, if (bits > (int)PixelComponentBitDepth.Bit8)
Argb32 => PngBitDepth.Bit8, {
Bgr24 => PngBitDepth.Bit8, return PngBitDepth.Bit16;
Bgra32 => PngBitDepth.Bit8, }
L8 => PngBitDepth.Bit8,
L16 => PngBitDepth.Bit16, return PngBitDepth.Bit8;
La16 => PngBitDepth.Bit8, }
La32 => PngBitDepth.Bit16,
Rgb24 => PngBitDepth.Bit8,
Rgba32 => PngBitDepth.Bit8,
Rgb48 => PngBitDepth.Bit16,
Rgba64 => PngBitDepth.Bit16,
RgbaVector => PngBitDepth.Bit16,
_ => PngBitDepth.Bit8
};
private unsafe struct ScratchBuffer private unsafe struct ScratchBuffer
{ {

50
src/ImageSharp/PixelFormats/PixelComponentBitDepth.cs

@ -0,0 +1,50 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.PixelFormats;
/// <summary>
/// Provides enumeration of the precision in bits of individual components within a pixel format.
/// </summary>
public enum PixelComponentBitDepth
{
/// <summary>
/// 1 bit per component.
/// </summary>
Bit1 = 1,
/// <summary>
/// 2 bits per component.
/// </summary>
Bit2 = 2,
/// <summary>
/// 4 bits per component.
/// </summary>
Bit4 = 4,
/// <summary>
/// 8 bits per component.
/// </summary>
Bit8 = 8,
/// <summary>
/// 16 bits per component.
/// </summary>
Bit16 = 16,
/// <summary>
/// 32 bits per component.
/// </summary>
Bit32 = 32,
/// <summary>
/// 64 bits per component.
/// </summary>
Bit64 = 64,
/// <summary>
/// 128 bits per component.
/// </summary>
Bit128 = 128
}

70
src/ImageSharp/PixelFormats/PixelComponentPrecision.cs

@ -1,70 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.PixelFormats;
/// <summary>
/// Provides enumeration of the precision in bits of individual components within a pixel format.
/// </summary>
public enum PixelComponentPrecision
{
/// <summary>
/// 8-bit signed integer.
/// </summary>
SByte = sizeof(sbyte) * 8,
/// <summary>
/// 8-bit unsigned integer.
/// </summary>
Byte = sizeof(byte) * 8,
/// <summary>
/// 16-bit signed integer.
/// </summary>
Short = sizeof(short) * 8,
/// <summary>
/// 16-bit unsigned integer.
/// </summary>
UShort = sizeof(ushort) * 8,
/// <summary>
/// 32-bit signed integer.
/// </summary>
Int = sizeof(int) * 8,
/// <summary>
/// 32-bit unsigned integer.
/// </summary>
UInt = sizeof(uint) * 8,
/// <summary>
/// 64-bit signed integer.
/// </summary>
Long = sizeof(long) * 8,
/// <summary>
/// 64-bit unsigned integer.
/// </summary>
ULong = sizeof(ulong) * 8,
/// <summary>
/// 16-bit floating point.
/// </summary>
Half = (sizeof(float) * 8) / 2,
/// <summary>
/// 32-bit floating point.
/// </summary>
Float = sizeof(float) * 8,
/// <summary>
/// 64-bit floating point.
/// </summary>
Double = sizeof(double) * 8,
/// <summary>
/// 128-bit floating point.
/// </summary>
Decimal = sizeof(decimal) * 8,
}

3
src/ImageSharp/PixelFormats/PixelTypeInfo.cs

@ -4,8 +4,9 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
// TODO: Review this type as it's used to represent 2 different things. // TODO: Review this type as it's used to represent 2 different things.
// 1.The encoded image pixel format. // 1. The encoded image pixel format.
// 2. The pixel format of the decoded image. // 2. The pixel format of the decoded image.
// Only the bits per pixel is used by the decoder, we should make it a property of the image metadata.
namespace SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.PixelFormats;
/// <summary> /// <summary>

20
tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs

@ -256,21 +256,21 @@ public partial class PngEncoderTests
[Theory] [Theory]
[WithBlankImages(1, 1, PixelTypes.A8, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.A8, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit8)]
[WithBlankImages(1, 1, PixelTypes.Argb32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Argb32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)]
[WithBlankImages(1, 1, PixelTypes.Bgr565, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Bgr565, PngColorType.Rgb, PngBitDepth.Bit8)]
[WithBlankImages(1, 1, PixelTypes.Bgra4444, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Bgra4444, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)]
[WithBlankImages(1, 1, PixelTypes.Byte4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Byte4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)]
[WithBlankImages(1, 1, PixelTypes.HalfSingle, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.HalfSingle, PngColorType.Rgb, PngBitDepth.Bit16)]
[WithBlankImages(1, 1, PixelTypes.HalfVector2, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.HalfVector2, PngColorType.Rgb, PngBitDepth.Bit16)]
[WithBlankImages(1, 1, PixelTypes.HalfVector4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.HalfVector4, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)]
[WithBlankImages(1, 1, PixelTypes.NormalizedByte2, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.NormalizedByte2, PngColorType.Rgb, PngBitDepth.Bit8)]
[WithBlankImages(1, 1, PixelTypes.NormalizedByte4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.NormalizedByte4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)]
[WithBlankImages(1, 1, PixelTypes.NormalizedShort4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.NormalizedShort4, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)]
[WithBlankImages(1, 1, PixelTypes.Rg32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Rg32, PngColorType.Rgb, PngBitDepth.Bit16)]
[WithBlankImages(1, 1, PixelTypes.Rgba1010102, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Rgba1010102, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)]
[WithBlankImages(1, 1, PixelTypes.Rgba32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Rgba32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)]
[WithBlankImages(1, 1, PixelTypes.RgbaVector, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)] [WithBlankImages(1, 1, PixelTypes.RgbaVector, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)]
[WithBlankImages(1, 1, PixelTypes.Short2, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Short2, PngColorType.Rgb, PngBitDepth.Bit16)]
[WithBlankImages(1, 1, PixelTypes.Short4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Short4, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)]
[WithBlankImages(1, 1, PixelTypes.Rgb24, PngColorType.Rgb, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Rgb24, PngColorType.Rgb, PngBitDepth.Bit8)]
[WithBlankImages(1, 1, PixelTypes.Bgr24, PngColorType.Rgb, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Bgr24, PngColorType.Rgb, PngBitDepth.Bit8)]
[WithBlankImages(1, 1, PixelTypes.Bgra32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Bgra32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)]

Loading…
Cancel
Save