mirror of https://github.com/SixLabors/ImageSharp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
4.9 KiB
143 lines
4.9 KiB
// Copyright (c) Six Labors.
|
|
// Licensed under the Six Labors Split License.
|
|
#nullable disable
|
|
|
|
using System.Buffers.Binary;
|
|
|
|
namespace SixLabors.ImageSharp.Formats.Png.Chunks;
|
|
|
|
/// <summary>
|
|
/// Represents the png header chunk.
|
|
/// </summary>
|
|
internal readonly struct PngHeader
|
|
{
|
|
public const int Size = 13;
|
|
|
|
public PngHeader(
|
|
int width,
|
|
int height,
|
|
byte bitDepth,
|
|
PngColorType colorType,
|
|
byte compressionMethod,
|
|
byte filterMethod,
|
|
PngInterlaceMode interlaceMethod)
|
|
{
|
|
this.Width = width;
|
|
this.Height = height;
|
|
this.BitDepth = bitDepth;
|
|
this.ColorType = colorType;
|
|
this.CompressionMethod = compressionMethod;
|
|
this.FilterMethod = filterMethod;
|
|
this.InterlaceMethod = interlaceMethod;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the dimension in x-direction of the image in pixels.
|
|
/// </summary>
|
|
public int Width { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the dimension in y-direction of the image in pixels.
|
|
/// </summary>
|
|
public int Height { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the bit depth.
|
|
/// Bit depth is a single-byte integer giving the number of bits per sample
|
|
/// or per palette index (not per pixel). Valid values are 1, 2, 4, 8, and 16,
|
|
/// although not all values are allowed for all color types.
|
|
/// </summary>
|
|
public byte BitDepth { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the color type.
|
|
/// Color type is a integer that describes the interpretation of the
|
|
/// image data. Color type codes represent sums of the following values:
|
|
/// 1 (palette used), 2 (color used), and 4 (alpha channel used).
|
|
/// </summary>
|
|
public PngColorType ColorType { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the compression method.
|
|
/// Indicates the method used to compress the image data. At present,
|
|
/// only compression method 0 (deflate/inflate compression with a sliding
|
|
/// window of at most 32768 bytes) is defined.
|
|
/// </summary>
|
|
public byte CompressionMethod { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the preprocessing method.
|
|
/// Indicates the preprocessing method applied to the image
|
|
/// data before compression. At present, only filter method 0
|
|
/// (adaptive filtering with five basic filter types) is defined.
|
|
/// </summary>
|
|
public byte FilterMethod { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the transmission order.
|
|
/// Indicates the transmission order of the image data.
|
|
/// Two values are currently defined: 0 (no interlace) or 1 (Adam7 interlace).
|
|
/// </summary>
|
|
public PngInterlaceMode InterlaceMethod { get; }
|
|
|
|
/// <summary>
|
|
/// Validates the png header.
|
|
/// </summary>
|
|
/// <exception cref="NotSupportedException">
|
|
/// Thrown if the image does pass validation.
|
|
/// </exception>
|
|
public void Validate()
|
|
{
|
|
if (!PngConstants.ColorTypes.TryGetValue(this.ColorType, out byte[] supportedBitDepths))
|
|
{
|
|
throw new NotSupportedException($"Invalid or unsupported color type. Was '{this.ColorType}'.");
|
|
}
|
|
|
|
if (supportedBitDepths.AsSpan().IndexOf(this.BitDepth) == -1)
|
|
{
|
|
throw new NotSupportedException($"Invalid or unsupported bit depth. Was '{this.BitDepth}'.");
|
|
}
|
|
|
|
if (this.FilterMethod != 0)
|
|
{
|
|
throw new NotSupportedException($"Invalid filter method. Expected 0. Was '{this.FilterMethod}'.");
|
|
}
|
|
|
|
// The png specification only defines 'None' and 'Adam7' as interlaced methods.
|
|
if (this.InterlaceMethod is not PngInterlaceMode.None and not PngInterlaceMode.Adam7)
|
|
{
|
|
throw new NotSupportedException($"Invalid interlace method. Expected 'None' or 'Adam7'. Was '{this.InterlaceMethod}'.");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes the header to the given buffer.
|
|
/// </summary>
|
|
/// <param name="buffer">The buffer to write to.</param>
|
|
public void WriteTo(Span<byte> buffer)
|
|
{
|
|
BinaryPrimitives.WriteInt32BigEndian(buffer[..4], this.Width);
|
|
BinaryPrimitives.WriteInt32BigEndian(buffer.Slice(4, 4), this.Height);
|
|
|
|
buffer[8] = this.BitDepth;
|
|
buffer[9] = (byte)this.ColorType;
|
|
buffer[10] = this.CompressionMethod;
|
|
buffer[11] = this.FilterMethod;
|
|
buffer[12] = (byte)this.InterlaceMethod;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parses the PngHeader from the given data buffer.
|
|
/// </summary>
|
|
/// <param name="data">The data to parse.</param>
|
|
/// <returns>The parsed PngHeader.</returns>
|
|
public static PngHeader Parse(ReadOnlySpan<byte> data)
|
|
=> new(
|
|
width: BinaryPrimitives.ReadInt32BigEndian(data[..4]),
|
|
height: BinaryPrimitives.ReadInt32BigEndian(data.Slice(4, 4)),
|
|
bitDepth: data[8],
|
|
colorType: (PngColorType)data[9],
|
|
compressionMethod: data[10],
|
|
filterMethod: data[11],
|
|
interlaceMethod: (PngInterlaceMode)data[12]);
|
|
}
|
|
|