Skip to content

Commit 412e451

Browse files
Merge branch 'main' into MakerProfileResolver
2 parents c7f3aa4 + afe2133 commit 412e451

File tree

130 files changed

+3407
-1809
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+3407
-1809
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using System.Buffers.Binary;
5+
using System.Text;
6+
7+
namespace SixLabors.ImageSharp.Common.Helpers;
8+
9+
internal static class RiffHelper
10+
{
11+
/// <summary>
12+
/// The header bytes identifying RIFF file.
13+
/// </summary>
14+
private const uint RiffFourCc = 0x52_49_46_46;
15+
16+
public static void WriteRiffFile(Stream stream, string formType, Action<Stream> func) =>
17+
WriteChunk(stream, RiffFourCc, s =>
18+
{
19+
s.Write(Encoding.ASCII.GetBytes(formType));
20+
func(s);
21+
});
22+
23+
public static void WriteChunk(Stream stream, uint fourCc, Action<Stream> func)
24+
{
25+
Span<byte> buffer = stackalloc byte[4];
26+
27+
// write the fourCC
28+
BinaryPrimitives.WriteUInt32BigEndian(buffer, fourCc);
29+
stream.Write(buffer);
30+
31+
long sizePosition = stream.Position;
32+
stream.Position += 4;
33+
34+
func(stream);
35+
36+
long position = stream.Position;
37+
38+
uint dataSize = (uint)(position - sizePosition - 4);
39+
40+
// padding
41+
if (dataSize % 2 == 1)
42+
{
43+
stream.WriteByte(0);
44+
position++;
45+
}
46+
47+
BinaryPrimitives.WriteUInt32LittleEndian(buffer, dataSize);
48+
stream.Position = sizePosition;
49+
stream.Write(buffer);
50+
stream.Position = position;
51+
}
52+
53+
public static void WriteChunk(Stream stream, uint fourCc, ReadOnlySpan<byte> data)
54+
{
55+
Span<byte> buffer = stackalloc byte[4];
56+
57+
// write the fourCC
58+
BinaryPrimitives.WriteUInt32BigEndian(buffer, fourCc);
59+
stream.Write(buffer);
60+
uint size = (uint)data.Length;
61+
BinaryPrimitives.WriteUInt32LittleEndian(buffer, size);
62+
stream.Write(buffer);
63+
stream.Write(data);
64+
65+
// padding
66+
if (size % 2 is 1)
67+
{
68+
stream.WriteByte(0);
69+
}
70+
}
71+
72+
public static unsafe void WriteChunk<TStruct>(Stream stream, uint fourCc, in TStruct chunk)
73+
where TStruct : unmanaged
74+
{
75+
fixed (TStruct* ptr = &chunk)
76+
{
77+
WriteChunk(stream, fourCc, new Span<byte>(ptr, sizeof(TStruct)));
78+
}
79+
}
80+
81+
public static long BeginWriteChunk(Stream stream, uint fourCc)
82+
{
83+
Span<byte> buffer = stackalloc byte[4];
84+
85+
// write the fourCC
86+
BinaryPrimitives.WriteUInt32BigEndian(buffer, fourCc);
87+
stream.Write(buffer);
88+
89+
long sizePosition = stream.Position;
90+
stream.Position += 4;
91+
92+
return sizePosition;
93+
}
94+
95+
public static void EndWriteChunk(Stream stream, long sizePosition)
96+
{
97+
Span<byte> buffer = stackalloc byte[4];
98+
99+
long position = stream.Position;
100+
101+
uint dataSize = (uint)(position - sizePosition - 4);
102+
103+
// padding
104+
if (dataSize % 2 is 1)
105+
{
106+
stream.WriteByte(0);
107+
position++;
108+
}
109+
110+
BinaryPrimitives.WriteUInt32LittleEndian(buffer, dataSize);
111+
stream.Position = sizePosition;
112+
stream.Write(buffer);
113+
stream.Position = position;
114+
}
115+
116+
public static long BeginWriteRiffFile(Stream stream, string formType)
117+
{
118+
long sizePosition = BeginWriteChunk(stream, RiffFourCc);
119+
stream.Write(Encoding.ASCII.GetBytes(formType));
120+
return sizePosition;
121+
}
122+
123+
public static void EndWriteRiffFile(Stream stream, long sizePosition) => EndWriteChunk(stream, sizePosition);
124+
}

src/ImageSharp/Compression/Zlib/ZlibInflateStream.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,12 @@ public override int ReadByte()
123123
/// <inheritdoc/>
124124
public override int Read(byte[] buffer, int offset, int count)
125125
{
126-
if (this.currentDataRemaining == 0)
126+
if (this.currentDataRemaining is 0)
127127
{
128128
// Last buffer was read in its entirety, let's make sure we don't actually have more in additional IDAT chunks.
129129
this.currentDataRemaining = this.getData();
130130

131-
if (this.currentDataRemaining == 0)
131+
if (this.currentDataRemaining is 0)
132132
{
133133
return 0;
134134
}
@@ -142,11 +142,11 @@ public override int Read(byte[] buffer, int offset, int count)
142142
// Keep reading data until we've reached the end of the stream or filled the buffer.
143143
int bytesRead = 0;
144144
offset += totalBytesRead;
145-
while (this.currentDataRemaining == 0 && totalBytesRead < count)
145+
while (this.currentDataRemaining is 0 && totalBytesRead < count)
146146
{
147147
this.currentDataRemaining = this.getData();
148148

149-
if (this.currentDataRemaining == 0)
149+
if (this.currentDataRemaining is 0)
150150
{
151151
return totalBytesRead;
152152
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using System.Buffers.Binary;
5+
6+
namespace SixLabors.ImageSharp.Formats.Png.Chunks;
7+
8+
internal readonly struct AnimationControl
9+
{
10+
public const int Size = 8;
11+
12+
public AnimationControl(int numberFrames, int numberPlays)
13+
{
14+
this.NumberFrames = numberFrames;
15+
this.NumberPlays = numberPlays;
16+
}
17+
18+
/// <summary>
19+
/// Gets the number of frames
20+
/// </summary>
21+
public int NumberFrames { get; }
22+
23+
/// <summary>
24+
/// Gets the number of times to loop this APNG. 0 indicates infinite looping.
25+
/// </summary>
26+
public int NumberPlays { get; }
27+
28+
/// <summary>
29+
/// Writes the acTL to the given buffer.
30+
/// </summary>
31+
/// <param name="buffer">The buffer to write to.</param>
32+
public void WriteTo(Span<byte> buffer)
33+
{
34+
BinaryPrimitives.WriteInt32BigEndian(buffer[..4], this.NumberFrames);
35+
BinaryPrimitives.WriteInt32BigEndian(buffer[4..8], this.NumberPlays);
36+
}
37+
38+
/// <summary>
39+
/// Parses the APngAnimationControl from the given data buffer.
40+
/// </summary>
41+
/// <param name="data">The data to parse.</param>
42+
/// <returns>The parsed acTL.</returns>
43+
public static AnimationControl Parse(ReadOnlySpan<byte> data)
44+
=> new(
45+
numberFrames: BinaryPrimitives.ReadInt32BigEndian(data[..4]),
46+
numberPlays: BinaryPrimitives.ReadInt32BigEndian(data[4..8]));
47+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using System.Buffers.Binary;
5+
6+
namespace SixLabors.ImageSharp.Formats.Png.Chunks;
7+
8+
internal readonly struct FrameControl
9+
{
10+
public const int Size = 26;
11+
12+
public FrameControl(uint width, uint height)
13+
: this(0, width, height, 0, 0, 0, 0, default, default)
14+
{
15+
}
16+
17+
public FrameControl(
18+
uint sequenceNumber,
19+
uint width,
20+
uint height,
21+
uint xOffset,
22+
uint yOffset,
23+
ushort delayNumerator,
24+
ushort delayDenominator,
25+
PngDisposalMethod disposeOperation,
26+
PngBlendMethod blendOperation)
27+
{
28+
this.SequenceNumber = sequenceNumber;
29+
this.Width = width;
30+
this.Height = height;
31+
this.XOffset = xOffset;
32+
this.YOffset = yOffset;
33+
this.DelayNumerator = delayNumerator;
34+
this.DelayDenominator = delayDenominator;
35+
this.DisposeOperation = disposeOperation;
36+
this.BlendOperation = blendOperation;
37+
}
38+
39+
/// <summary>
40+
/// Gets the sequence number of the animation chunk, starting from 0
41+
/// </summary>
42+
public uint SequenceNumber { get; }
43+
44+
/// <summary>
45+
/// Gets the width of the following frame
46+
/// </summary>
47+
public uint Width { get; }
48+
49+
/// <summary>
50+
/// Gets the height of the following frame
51+
/// </summary>
52+
public uint Height { get; }
53+
54+
/// <summary>
55+
/// Gets the X position at which to render the following frame
56+
/// </summary>
57+
public uint XOffset { get; }
58+
59+
/// <summary>
60+
/// Gets the Y position at which to render the following frame
61+
/// </summary>
62+
public uint YOffset { get; }
63+
64+
/// <summary>
65+
/// Gets the X limit at which to render the following frame
66+
/// </summary>
67+
public uint XMax => this.XOffset + this.Width;
68+
69+
/// <summary>
70+
/// Gets the Y limit at which to render the following frame
71+
/// </summary>
72+
public uint YMax => this.YOffset + this.Height;
73+
74+
/// <summary>
75+
/// Gets the frame delay fraction numerator
76+
/// </summary>
77+
public ushort DelayNumerator { get; }
78+
79+
/// <summary>
80+
/// Gets the frame delay fraction denominator
81+
/// </summary>
82+
public ushort DelayDenominator { get; }
83+
84+
/// <summary>
85+
/// Gets the type of frame area disposal to be done after rendering this frame
86+
/// </summary>
87+
public PngDisposalMethod DisposeOperation { get; }
88+
89+
/// <summary>
90+
/// Gets the type of frame area rendering for this frame
91+
/// </summary>
92+
public PngBlendMethod BlendOperation { get; }
93+
94+
public Rectangle Bounds => new((int)this.XOffset, (int)this.YOffset, (int)this.Width, (int)this.Height);
95+
96+
/// <summary>
97+
/// Validates the APng fcTL.
98+
/// </summary>
99+
/// <param name="header">The header.</param>
100+
/// <exception cref="NotSupportedException">
101+
/// Thrown if the image does pass validation.
102+
/// </exception>
103+
public void Validate(PngHeader header)
104+
{
105+
if (this.Width == 0)
106+
{
107+
PngThrowHelper.ThrowInvalidParameter(this.Width, "Expected > 0");
108+
}
109+
110+
if (this.Height == 0)
111+
{
112+
PngThrowHelper.ThrowInvalidParameter(this.Height, "Expected > 0");
113+
}
114+
115+
if (this.XMax > header.Width)
116+
{
117+
PngThrowHelper.ThrowInvalidParameter(this.XOffset, this.Width, $"The x-offset plus width > {nameof(PngHeader)}.{nameof(PngHeader.Width)}");
118+
}
119+
120+
if (this.YMax > header.Height)
121+
{
122+
PngThrowHelper.ThrowInvalidParameter(this.YOffset, this.Height, $"The y-offset plus height > {nameof(PngHeader)}.{nameof(PngHeader.Height)}");
123+
}
124+
}
125+
126+
/// <summary>
127+
/// Writes the fcTL to the given buffer.
128+
/// </summary>
129+
/// <param name="buffer">The buffer to write to.</param>
130+
public void WriteTo(Span<byte> buffer)
131+
{
132+
BinaryPrimitives.WriteUInt32BigEndian(buffer[..4], this.SequenceNumber);
133+
BinaryPrimitives.WriteUInt32BigEndian(buffer[4..8], this.Width);
134+
BinaryPrimitives.WriteUInt32BigEndian(buffer[8..12], this.Height);
135+
BinaryPrimitives.WriteUInt32BigEndian(buffer[12..16], this.XOffset);
136+
BinaryPrimitives.WriteUInt32BigEndian(buffer[16..20], this.YOffset);
137+
BinaryPrimitives.WriteUInt16BigEndian(buffer[20..22], this.DelayNumerator);
138+
BinaryPrimitives.WriteUInt16BigEndian(buffer[22..24], this.DelayDenominator);
139+
140+
buffer[24] = (byte)this.DisposeOperation;
141+
buffer[25] = (byte)this.BlendOperation;
142+
}
143+
144+
/// <summary>
145+
/// Parses the APngFrameControl from the given data buffer.
146+
/// </summary>
147+
/// <param name="data">The data to parse.</param>
148+
/// <returns>The parsed fcTL.</returns>
149+
public static FrameControl Parse(ReadOnlySpan<byte> data)
150+
=> new(
151+
sequenceNumber: BinaryPrimitives.ReadUInt32BigEndian(data[..4]),
152+
width: BinaryPrimitives.ReadUInt32BigEndian(data[4..8]),
153+
height: BinaryPrimitives.ReadUInt32BigEndian(data[8..12]),
154+
xOffset: BinaryPrimitives.ReadUInt32BigEndian(data[12..16]),
155+
yOffset: BinaryPrimitives.ReadUInt32BigEndian(data[16..20]),
156+
delayNumerator: BinaryPrimitives.ReadUInt16BigEndian(data[20..22]),
157+
delayDenominator: BinaryPrimitives.ReadUInt16BigEndian(data[22..24]),
158+
disposeOperation: (PngDisposalMethod)data[24],
159+
blendOperation: (PngBlendMethod)data[25]);
160+
}

src/ImageSharp/Formats/Png/PngHeader.cs renamed to src/ImageSharp/Formats/Png/Chunks/PngHeader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
using System.Buffers.Binary;
66

7-
namespace SixLabors.ImageSharp.Formats.Png;
7+
namespace SixLabors.ImageSharp.Formats.Png.Chunks;
88

99
/// <summary>
1010
/// Represents the png header chunk.

0 commit comments

Comments
 (0)