Skip to content

Commit 7b6c32d

Browse files
committed
implement APNG encoder
1 parent 45f6f5b commit 7b6c32d

File tree

11 files changed

+311
-234
lines changed

11 files changed

+311
-234
lines changed

src/ImageSharp/Configuration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public Configuration()
4343
/// Initializes a new instance of the <see cref="Configuration" /> class.
4444
/// </summary>
4545
/// <param name="configurationModules">A collection of configuration modules to register.</param>
46-
public Configuration(params IImageFormatConfigurationModule[] configurationModules)
46+
public Configuration(params IImageFormatConfigurationModule[]? configurationModules)
4747
{
4848
if (configurationModules != null)
4949
{

src/ImageSharp/Formats/Png/Chunks/APngFrameControl.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,26 @@ public void Validate(PngHeader hdr)
115115
}
116116
}
117117

118+
/// <summary>
119+
/// Parses the APngFrameControl from the given metadata.
120+
/// </summary>
121+
/// <param name="frameMetadata">The metadata to parse.</param>
122+
/// <param name="sequenceNumber">Sequence number.</param>
123+
public static APngFrameControl FromMetadata(APngFrameMetadata frameMetadata, int sequenceNumber)
124+
{
125+
APngFrameControl fcTL = new(
126+
sequenceNumber,
127+
frameMetadata.Width,
128+
frameMetadata.Height,
129+
frameMetadata.XOffset,
130+
frameMetadata.YOffset,
131+
frameMetadata.DelayNumber,
132+
frameMetadata.DelayDenominator,
133+
frameMetadata.DisposeOperation,
134+
frameMetadata.BlendOperation);
135+
return fcTL;
136+
}
137+
118138
/// <summary>
119139
/// Writes the fcTL to the given buffer.
120140
/// </summary>
@@ -126,8 +146,8 @@ public void WriteTo(Span<byte> buffer)
126146
BinaryPrimitives.WriteInt32BigEndian(buffer[8..12], this.Height);
127147
BinaryPrimitives.WriteInt32BigEndian(buffer[12..16], this.XOffset);
128148
BinaryPrimitives.WriteInt32BigEndian(buffer[16..20], this.YOffset);
129-
BinaryPrimitives.WriteInt32BigEndian(buffer[20..22], this.DelayNumber);
130-
BinaryPrimitives.WriteInt32BigEndian(buffer[12..24], this.DelayDenominator);
149+
BinaryPrimitives.WriteInt16BigEndian(buffer[20..22], this.DelayNumber);
150+
BinaryPrimitives.WriteInt16BigEndian(buffer[22..24], this.DelayDenominator);
131151

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

src/ImageSharp/Formats/Png/PngChunkType.cs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,149 +10,149 @@ internal enum PngChunkType : uint
1010
{
1111
/// <summary>
1212
/// </summary>
13-
/// <remarks>acTL</remarks>
13+
/// <remarks>acTL (Single)</remarks>
1414
AnimationControl = 0x6163544cU,
1515

1616
/// <summary>
1717
/// </summary>
18-
/// <remarks>fcTL</remarks>
18+
/// <remarks>fcTL (Multiple)</remarks>
1919
FrameControl = 0x6663544cU,
2020

2121
/// <summary>
2222
/// </summary>
23-
/// <remarks>fdAT</remarks>
23+
/// <remarks>fdAT (Multiple)</remarks>
2424
FrameData = 0x66644154U,
2525

2626
/// <summary>
2727
/// The IDAT chunk contains the actual image data. The image can contains more
2828
/// than one chunk of this type. All chunks together are the whole image.
2929
/// </summary>
30-
/// <remarks>IDAT</remarks>
30+
/// <remarks>IDAT (Multiple)</remarks>
3131
Data = 0x49444154U,
3232

3333
/// <summary>
3434
/// This chunk must appear last. It marks the end of the PNG data stream.
3535
/// The chunk's data field is empty.
3636
/// </summary>
37-
/// <remarks>IEND</remarks>
37+
/// <remarks>IEND (Single)</remarks>
3838
End = 0x49454E44U,
3939

4040
/// <summary>
4141
/// The first chunk in a png file. Can only exists once. Contains
4242
/// common information like the width and the height of the image or
4343
/// the used compression method.
4444
/// </summary>
45-
/// <remarks>IHDR</remarks>
45+
/// <remarks>IHDR (Single)</remarks>
4646
Header = 0x49484452U,
4747

4848
/// <summary>
4949
/// The PLTE chunk contains from 1 to 256 palette entries, each a three byte
5050
/// series in the RGB format.
5151
/// </summary>
52-
/// <remarks>PLTE</remarks>
52+
/// <remarks>PLTE (Single)</remarks>
5353
Palette = 0x504C5445U,
5454

5555
/// <summary>
5656
/// The eXIf data chunk which contains the Exif profile.
5757
/// </summary>
58-
/// <remarks>eXIF</remarks>
58+
/// <remarks>eXIF (Single)</remarks>
5959
Exif = 0x65584966U,
6060

6161
/// <summary>
6262
/// This chunk specifies the relationship between the image samples and the desired
6363
/// display output intensity.
6464
/// </summary>
65-
/// <remarks>gAMA</remarks>
65+
/// <remarks>gAMA (Single)</remarks>
6666
Gamma = 0x67414D41U,
6767

6868
/// <summary>
6969
/// This chunk specifies the intended pixel size or aspect ratio for display of the image.
7070
/// </summary>
71-
/// <remarks>pHYs</remarks>
71+
/// <remarks>pHYs (Single)</remarks>
7272
Physical = 0x70485973U,
7373

7474
/// <summary>
7575
/// Textual information that the encoder wishes to record with the image can be stored in
7676
/// tEXt chunks. Each tEXt chunk contains a keyword and a text string.
7777
/// </summary>
78-
/// <remarks>tEXT</remarks>
78+
/// <remarks>tEXT (Multiple)</remarks>
7979
Text = 0x74455874U,
8080

8181
/// <summary>
8282
/// Textual information that the encoder wishes to record with the image. The zTXt and tEXt chunks are semantically equivalent,
8383
/// but the zTXt chunk is recommended for storing large blocks of text. Each zTXt chunk contains a (uncompressed) keyword and
8484
/// a compressed text string.
8585
/// </summary>
86-
/// <remarks>zTXt</remarks>
86+
/// <remarks>zTXt (Multiple)</remarks>
8787
CompressedText = 0x7A545874U,
8888

8989
/// <summary>
9090
/// This chunk contains International textual data. It contains a keyword, an optional language tag, an optional translated keyword
9191
/// and the actual text string, which can be compressed or uncompressed.
9292
/// </summary>
93-
/// <remarks>iTXt</remarks>
93+
/// <remarks>iTXt (Multiple)</remarks>
9494
InternationalText = 0x69545874U,
9595

9696
/// <summary>
9797
/// This chunk specifies that the image uses simple transparency:
9898
/// either alpha values associated with palette entries (for indexed-color images)
9999
/// or a single transparent color (for grayscale and true color images).
100100
/// </summary>
101-
/// <remarks>tRNS</remarks>
101+
/// <remarks>tRNS (Single)</remarks>
102102
Transparency = 0x74524E53U,
103103

104104
/// <summary>
105105
/// This chunk gives the time of the last image modification (not the time of initial image creation).
106106
/// </summary>
107-
/// <remarks>tIME</remarks>
107+
/// <remarks>tIME (Single)</remarks>
108108
Time = 0x74494d45,
109109

110110
/// <summary>
111111
/// This chunk specifies a default background colour to present the image against.
112112
/// If there is any other preferred background, either user-specified or part of a larger page (as in a browser),
113113
/// the bKGD chunk should be ignored.
114114
/// </summary>
115-
/// <remarks>bKGD</remarks>
115+
/// <remarks>bKGD (Single)</remarks>
116116
Background = 0x624b4744,
117117

118118
/// <summary>
119119
/// This chunk contains a embedded color profile. If the iCCP chunk is present,
120120
/// the image samples conform to the colour space represented by the embedded ICC profile as defined by the International Color Consortium.
121121
/// </summary>
122-
/// <remarks>iCCP</remarks>
122+
/// <remarks>iCCP (Single)</remarks>
123123
EmbeddedColorProfile = 0x69434350,
124124

125125
/// <summary>
126126
/// This chunk defines the original number of significant bits (which can be less than or equal to the sample depth).
127127
/// This allows PNG decoders to recover the original data losslessly even if the data had a sample depth not directly supported by PNG.
128128
/// </summary>
129-
/// <remarks>sBIT</remarks>
129+
/// <remarks>sBIT (Single)</remarks>
130130
SignificantBits = 0x73424954,
131131

132132
/// <summary>
133133
/// If the this chunk is present, the image samples conform to the sRGB colour space [IEC 61966-2-1] and should be displayed
134134
/// using the specified rendering intent defined by the International Color Consortium.
135135
/// </summary>
136-
/// <remarks>sRGB</remarks>
136+
/// <remarks>sRGB (Single)</remarks>
137137
StandardRgbColourSpace = 0x73524742,
138138

139139
/// <summary>
140140
/// This chunk gives the approximate usage frequency of each colour in the palette.
141141
/// </summary>
142-
/// <remarks>hIST</remarks>
142+
/// <remarks>hIST (Single)</remarks>
143143
Histogram = 0x68495354,
144144

145145
/// <summary>
146146
/// This chunk contains the suggested palette.
147147
/// </summary>
148-
/// <remarks>sPLT</remarks>
148+
/// <remarks>sPLT (Single)</remarks>
149149
SuggestedPalette = 0x73504c54,
150150

151151
/// <summary>
152152
/// This chunk may be used to specify the 1931 CIE x,y chromaticities of the red,
153153
/// green, and blue display primaries used in the image, and the referenced white point.
154154
/// </summary>
155-
/// <remarks>cHRM</remarks>
155+
/// <remarks>cHRM (Single)</remarks>
156156
Chroma = 0x6348524d,
157157

158158
/// <summary>

src/ImageSharp/Formats/Png/PngEncoder.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Six Labors Split License.
3-
#nullable disable
43

54
using SixLabors.ImageSharp.Advanced;
65

@@ -18,7 +17,12 @@ public PngEncoder() =>
1817

1918
// We set the quantizer to null here to allow the underlying encoder to create a
2019
// quantizer with options appropriate to the encoding bit depth.
21-
this.Quantizer = null;
20+
this.Quantizer = null!;
21+
22+
/// <summary>
23+
/// Gets whether the file is a simple PNG.
24+
/// </summary>
25+
public bool? IsSimplePng { get; init; }
2226

2327
/// <summary>
2428
/// Gets the number of bits per sample or per palette index (not per pixel).

0 commit comments

Comments
 (0)