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
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());
}
@ -118,7 +118,7 @@ public readonly partial struct Color : IEquatable<Color>
// Avoid boxing in case we can convert to Vector4 safely and efficiently
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++)
{

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.
// 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
// a sensible default based upon the pixel format.
this.colorType = encoder.ColorType ?? pngMetadata.ColorType ?? SuggestColorType<TPixel>();
if (!encoder.FilterMethod.HasValue)
PngColorType? colorType = encoder.ColorType ?? pngMetadata.ColorType;
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.
this.filterMethod = this.colorType is PngColorType.Palette ? PngFilterMethod.None : PngFilterMethod.Paeth;
PixelTypeInfo info = TPixel.GetPixelTypeInfo();
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.
// Bit8 is the only bit depth supported by all color types.
byte bits = (byte)(encoder.BitDepth ?? pngMetadata.BitDepth ?? SuggestBitDepth<TPixel>());
byte[] validBitDepths = PngConstants.ColorTypes[this.colorType];
byte[] validBitDepths = PngConstants.ColorTypes[colorType.Value];
if (Array.IndexOf(validBitDepths, bits) == -1)
{
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;
bytesPerPixel = CalculateBytesPerPixel(this.colorType, use16Bit);
@ -1611,53 +1636,44 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
/// <summary>
/// Returns a suggested <see cref="PngColorType"/> for the given <typeparamref name="TPixel"/>
/// This is not exhaustive but covers many common pixel formats.
/// </summary>
/// <param name="info">The pixel type info.</param>
/// <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>
=> default(TPixel) switch
{
A8 => PngColorType.GrayscaleWithAlpha,
Argb32 => PngColorType.RgbWithAlpha,
Bgr24 => PngColorType.Rgb,
Bgra32 => PngColorType.RgbWithAlpha,
L8 => PngColorType.Grayscale,
L16 => PngColorType.Grayscale,
La16 => PngColorType.GrayscaleWithAlpha,
La32 => PngColorType.GrayscaleWithAlpha,
Rgb24 => PngColorType.Rgb,
Rgba32 => PngColorType.RgbWithAlpha,
Rgb48 => PngColorType.Rgb,
Rgba64 => PngColorType.RgbWithAlpha,
RgbaVector => PngColorType.RgbWithAlpha,
_ => PngColorType.RgbWithAlpha
{
if (info.AlphaRepresentation == PixelAlphaRepresentation.None)
{
return info.ColorType switch
{
PixelColorType.Grayscale => PngColorType.Grayscale,
_ => PngColorType.Rgb,
};
}
return info.ColorType switch
{
PixelColorType.Grayscale | PixelColorType.Alpha or PixelColorType.Alpha => PngColorType.GrayscaleWithAlpha,
_ => PngColorType.RgbWithAlpha,
};
}
/// <summary>
/// Returns a suggested <see cref="PngBitDepth"/> for the given <typeparamref name="TPixel"/>
/// This is not exhaustive but covers many common pixel formats.
/// </summary>
/// <param name="info">The pixel type info.</param>
/// <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>
=> default(TPixel) switch
{
A8 => PngBitDepth.Bit8,
Argb32 => PngBitDepth.Bit8,
Bgr24 => PngBitDepth.Bit8,
Bgra32 => PngBitDepth.Bit8,
L8 => PngBitDepth.Bit8,
L16 => PngBitDepth.Bit16,
La16 => PngBitDepth.Bit8,
La32 => PngBitDepth.Bit16,
Rgb24 => PngBitDepth.Bit8,
Rgba32 => PngBitDepth.Bit8,
Rgb48 => PngBitDepth.Bit16,
Rgba64 => PngBitDepth.Bit16,
RgbaVector => PngBitDepth.Bit16,
_ => PngBitDepth.Bit8
};
{
int bits = info.GetMaximumComponentPrecision();
if (bits > (int)PixelComponentBitDepth.Bit8)
{
return PngBitDepth.Bit16;
}
return PngBitDepth.Bit8;
}
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;
// 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.
// Only the bits per pixel is used by the decoder, we should make it a property of the image metadata.
namespace SixLabors.ImageSharp.PixelFormats;
/// <summary>

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

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

Loading…
Cancel
Save