Skip to content

Commit

Permalink
Merge branch 'main' into js/webp-allocations
Browse files Browse the repository at this point in the history
  • Loading branch information
JimBobSquarePants authored Oct 31, 2023
2 parents 2f61d94 + 0888e54 commit c51f5ae
Show file tree
Hide file tree
Showing 81 changed files with 1,530 additions and 573 deletions.
8 changes: 4 additions & 4 deletions src/ImageSharp/Compression/Zlib/ZlibInflateStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,12 @@ public override int ReadByte()
/// <inheritdoc/>
public override int Read(byte[] buffer, int offset, int count)
{
if (this.currentDataRemaining == 0)
if (this.currentDataRemaining is 0)
{
// Last buffer was read in its entirety, let's make sure we don't actually have more in additional IDAT chunks.
this.currentDataRemaining = this.getData();

if (this.currentDataRemaining == 0)
if (this.currentDataRemaining is 0)
{
return 0;
}
Expand All @@ -142,11 +142,11 @@ public override int Read(byte[] buffer, int offset, int count)
// Keep reading data until we've reached the end of the stream or filled the buffer.
int bytesRead = 0;
offset += totalBytesRead;
while (this.currentDataRemaining == 0 && totalBytesRead < count)
while (this.currentDataRemaining is 0 && totalBytesRead < count)
{
this.currentDataRemaining = this.getData();

if (this.currentDataRemaining == 0)
if (this.currentDataRemaining is 0)
{
return totalBytesRead;
}
Expand Down
47 changes: 47 additions & 0 deletions src/ImageSharp/Formats/Png/Chunks/AnimationControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using System.Buffers.Binary;

namespace SixLabors.ImageSharp.Formats.Png.Chunks;

internal readonly struct AnimationControl
{
public const int Size = 8;

public AnimationControl(int numberFrames, int numberPlays)
{
this.NumberFrames = numberFrames;
this.NumberPlays = numberPlays;
}

/// <summary>
/// Gets the number of frames
/// </summary>
public int NumberFrames { get; }

/// <summary>
/// Gets the number of times to loop this APNG. 0 indicates infinite looping.
/// </summary>
public int NumberPlays { get; }

/// <summary>
/// Writes the acTL 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.NumberFrames);
BinaryPrimitives.WriteInt32BigEndian(buffer[4..8], this.NumberPlays);
}

/// <summary>
/// Parses the APngAnimationControl from the given data buffer.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <returns>The parsed acTL.</returns>
public static AnimationControl Parse(ReadOnlySpan<byte> data)
=> new(
numberFrames: BinaryPrimitives.ReadInt32BigEndian(data[..4]),
numberPlays: BinaryPrimitives.ReadInt32BigEndian(data[4..8]));
}
160 changes: 160 additions & 0 deletions src/ImageSharp/Formats/Png/Chunks/FrameControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using System.Buffers.Binary;

namespace SixLabors.ImageSharp.Formats.Png.Chunks;

internal readonly struct FrameControl
{
public const int Size = 26;

public FrameControl(uint width, uint height)
: this(0, width, height, 0, 0, 0, 0, default, default)
{
}

public FrameControl(
uint sequenceNumber,
uint width,
uint height,
uint xOffset,
uint yOffset,
ushort delayNumerator,
ushort delayDenominator,
PngDisposalMethod disposeOperation,
PngBlendMethod blendOperation)
{
this.SequenceNumber = sequenceNumber;
this.Width = width;
this.Height = height;
this.XOffset = xOffset;
this.YOffset = yOffset;
this.DelayNumerator = delayNumerator;
this.DelayDenominator = delayDenominator;
this.DisposeOperation = disposeOperation;
this.BlendOperation = blendOperation;
}

/// <summary>
/// Gets the sequence number of the animation chunk, starting from 0
/// </summary>
public uint SequenceNumber { get; }

/// <summary>
/// Gets the width of the following frame
/// </summary>
public uint Width { get; }

/// <summary>
/// Gets the height of the following frame
/// </summary>
public uint Height { get; }

/// <summary>
/// Gets the X position at which to render the following frame
/// </summary>
public uint XOffset { get; }

/// <summary>
/// Gets the Y position at which to render the following frame
/// </summary>
public uint YOffset { get; }

/// <summary>
/// Gets the X limit at which to render the following frame
/// </summary>
public uint XMax => this.XOffset + this.Width;

/// <summary>
/// Gets the Y limit at which to render the following frame
/// </summary>
public uint YMax => this.YOffset + this.Height;

/// <summary>
/// Gets the frame delay fraction numerator
/// </summary>
public ushort DelayNumerator { get; }

/// <summary>
/// Gets the frame delay fraction denominator
/// </summary>
public ushort DelayDenominator { get; }

/// <summary>
/// Gets the type of frame area disposal to be done after rendering this frame
/// </summary>
public PngDisposalMethod DisposeOperation { get; }

/// <summary>
/// Gets the type of frame area rendering for this frame
/// </summary>
public PngBlendMethod BlendOperation { get; }

public Rectangle Bounds => new((int)this.XOffset, (int)this.YOffset, (int)this.Width, (int)this.Height);

/// <summary>
/// Validates the APng fcTL.
/// </summary>
/// <param name="header">The header.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the image does pass validation.
/// </exception>
public void Validate(PngHeader header)
{
if (this.Width == 0)
{
PngThrowHelper.ThrowInvalidParameter(this.Width, "Expected > 0");
}

if (this.Height == 0)
{
PngThrowHelper.ThrowInvalidParameter(this.Height, "Expected > 0");
}

if (this.XMax > header.Width)
{
PngThrowHelper.ThrowInvalidParameter(this.XOffset, this.Width, $"The x-offset plus width > {nameof(PngHeader)}.{nameof(PngHeader.Width)}");
}

if (this.YMax > header.Height)
{
PngThrowHelper.ThrowInvalidParameter(this.YOffset, this.Height, $"The y-offset plus height > {nameof(PngHeader)}.{nameof(PngHeader.Height)}");
}
}

/// <summary>
/// Writes the fcTL to the given buffer.
/// </summary>
/// <param name="buffer">The buffer to write to.</param>
public void WriteTo(Span<byte> buffer)
{
BinaryPrimitives.WriteUInt32BigEndian(buffer[..4], this.SequenceNumber);
BinaryPrimitives.WriteUInt32BigEndian(buffer[4..8], this.Width);
BinaryPrimitives.WriteUInt32BigEndian(buffer[8..12], this.Height);
BinaryPrimitives.WriteUInt32BigEndian(buffer[12..16], this.XOffset);
BinaryPrimitives.WriteUInt32BigEndian(buffer[16..20], this.YOffset);
BinaryPrimitives.WriteUInt16BigEndian(buffer[20..22], this.DelayNumerator);
BinaryPrimitives.WriteUInt16BigEndian(buffer[22..24], this.DelayDenominator);

buffer[24] = (byte)this.DisposeOperation;
buffer[25] = (byte)this.BlendOperation;
}

/// <summary>
/// Parses the APngFrameControl from the given data buffer.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <returns>The parsed fcTL.</returns>
public static FrameControl Parse(ReadOnlySpan<byte> data)
=> new(
sequenceNumber: BinaryPrimitives.ReadUInt32BigEndian(data[..4]),
width: BinaryPrimitives.ReadUInt32BigEndian(data[4..8]),
height: BinaryPrimitives.ReadUInt32BigEndian(data[8..12]),
xOffset: BinaryPrimitives.ReadUInt32BigEndian(data[12..16]),
yOffset: BinaryPrimitives.ReadUInt32BigEndian(data[16..20]),
delayNumerator: BinaryPrimitives.ReadUInt16BigEndian(data[20..22]),
delayDenominator: BinaryPrimitives.ReadUInt16BigEndian(data[22..24]),
disposeOperation: (PngDisposalMethod)data[24],
blendOperation: (PngBlendMethod)data[25]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

using System.Buffers.Binary;

namespace SixLabors.ImageSharp.Formats.Png;
namespace SixLabors.ImageSharp.Formats.Png.Chunks;

/// <summary>
/// Represents the png header chunk.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using System.Buffers.Binary;
Expand All @@ -10,11 +10,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Chunks;
/// <summary>
/// The pHYs chunk specifies the intended pixel size or aspect ratio for display of the image.
/// </summary>
internal readonly struct PhysicalChunkData
internal readonly struct PngPhysical
{
public const int Size = 9;

public PhysicalChunkData(uint x, uint y, byte unitSpecifier)
public PngPhysical(uint x, uint y, byte unitSpecifier)
{
this.XAxisPixelsPerUnit = x;
this.YAxisPixelsPerUnit = y;
Expand Down Expand Up @@ -44,13 +44,13 @@ public PhysicalChunkData(uint x, uint y, byte unitSpecifier)
/// </summary>
/// <param name="data">The data buffer.</param>
/// <returns>The parsed PhysicalChunkData.</returns>
public static PhysicalChunkData Parse(ReadOnlySpan<byte> data)
public static PngPhysical Parse(ReadOnlySpan<byte> data)
{
uint hResolution = BinaryPrimitives.ReadUInt32BigEndian(data[..4]);
uint vResolution = BinaryPrimitives.ReadUInt32BigEndian(data.Slice(4, 4));
byte unit = data[8];

return new PhysicalChunkData(hResolution, vResolution, unit);
return new PngPhysical(hResolution, vResolution, unit);
}

/// <summary>
Expand All @@ -59,7 +59,7 @@ public static PhysicalChunkData Parse(ReadOnlySpan<byte> data)
/// </summary>
/// <param name="meta">The metadata.</param>
/// <returns>The constructed PngPhysicalChunkData instance.</returns>
public static PhysicalChunkData FromMetadata(ImageMetadata meta)
public static PngPhysical FromMetadata(ImageMetadata meta)
{
byte unitSpecifier = 0;
uint x;
Expand Down Expand Up @@ -92,7 +92,7 @@ public static PhysicalChunkData FromMetadata(ImageMetadata meta)
break;
}

return new PhysicalChunkData(x, y, unitSpecifier);
return new PngPhysical(x, y, unitSpecifier);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Png;
namespace SixLabors.ImageSharp.Formats.Png.Chunks;

/// <summary>
/// Stores text data contained in the iTXt, tEXt, and zTXt chunks.
Expand Down
20 changes: 18 additions & 2 deletions src/ImageSharp/Formats/Png/MetadataExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using System.Diagnostics.CodeAnalysis;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Metadata;

Expand All @@ -14,7 +15,22 @@ public static partial class MetadataExtensions
/// <summary>
/// Gets the png format specific metadata for the image.
/// </summary>
/// <param name="metadata">The metadata this method extends.</param>
/// <param name="source">The metadata this method extends.</param>
/// <returns>The <see cref="PngMetadata"/>.</returns>
public static PngMetadata GetPngMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(PngFormat.Instance);
public static PngMetadata GetPngMetadata(this ImageMetadata source) => source.GetFormatMetadata(PngFormat.Instance);

/// <summary>
/// Gets the aPng format specific metadata for the image frame.
/// </summary>
/// <param name="source">The metadata this method extends.</param>
/// <returns>The <see cref="PngFrameMetadata"/>.</returns>
public static PngFrameMetadata GetPngFrameMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(PngFormat.Instance);

/// <summary>
/// Gets the aPng format specific metadata for the image frame.
/// </summary>
/// <param name="source">The metadata this method extends.</param>
/// <param name="metadata">The metadata.</param>
/// <returns>The <see cref="PngFrameMetadata"/>.</returns>
public static bool TryGetPngFrameMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out PngFrameMetadata? metadata) => source.TryGetFormatMetadata(PngFormat.Instance, out metadata);
}
22 changes: 22 additions & 0 deletions src/ImageSharp/Formats/Png/PngBlendMethod.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Png;

/// <summary>
/// Specifies whether the frame is to be alpha blended into the current output buffer content,
/// or whether it should completely replace its region in the output buffer.
/// </summary>
public enum PngBlendMethod
{
/// <summary>
/// All color components of the frame, including alpha, overwrite the current contents of the frame's output buffer region.
/// </summary>
Source,

/// <summary>
/// The frame should be composited onto the output buffer based on its alpha, using a simple OVER operation as
/// described in the "Alpha Channel Processing" section of the PNG specification [PNG-1.2].
/// </summary>
Over
}
7 changes: 4 additions & 3 deletions src/ImageSharp/Formats/Png/PngChunk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public PngChunk(int length, PngChunkType type, IMemoryOwner<byte> data = null)
/// Gets a value indicating whether the given chunk is critical to decoding
/// </summary>
public bool IsCritical =>
this.Type == PngChunkType.Header ||
this.Type == PngChunkType.Palette ||
this.Type == PngChunkType.Data;
this.Type is PngChunkType.Header or
PngChunkType.Palette or
PngChunkType.Data or
PngChunkType.FrameData;
}
Loading

0 comments on commit c51f5ae

Please sign in to comment.