22// Licensed under the Six Labors Split License.
33
44using System . Buffers . Binary ;
5+ using System . Drawing ;
56using System . Runtime . InteropServices ;
67using SixLabors . ImageSharp . Metadata . Profiles . Exif ;
78using SixLabors . ImageSharp . Metadata . Profiles . Xmp ;
@@ -92,7 +93,7 @@ protected void WriteRiffHeader(Stream stream, uint riffSize)
9293 {
9394 stream . Write ( WebpConstants . RiffFourCc ) ;
9495 BinaryPrimitives . WriteUInt32LittleEndian ( this . scratchBuffer . Span , riffSize ) ;
95- stream . Write ( this . scratchBuffer . Span . Slice ( 0 , 4 ) ) ;
96+ stream . Write ( this . scratchBuffer . Span [ .. 4 ] ) ;
9697 stream . Write ( WebpConstants . WebpHeader ) ;
9798 }
9899
@@ -129,7 +130,7 @@ protected void WriteMetadataProfile(Stream stream, byte[]? metadataBytes, WebpCh
129130 DebugGuard . NotNull ( metadataBytes , nameof ( metadataBytes ) ) ;
130131
131132 uint size = ( uint ) metadataBytes . Length ;
132- Span < byte > buf = this . scratchBuffer . Span . Slice ( 0 , 4 ) ;
133+ Span < byte > buf = this . scratchBuffer . Span [ .. 4 ] ;
133134 BinaryPrimitives . WriteUInt32BigEndian ( buf , ( uint ) chunkType ) ;
134135 stream . Write ( buf ) ;
135136 BinaryPrimitives . WriteUInt32LittleEndian ( buf , size ) ;
@@ -143,6 +144,61 @@ protected void WriteMetadataProfile(Stream stream, byte[]? metadataBytes, WebpCh
143144 }
144145 }
145146
147+ /// <summary>
148+ /// Writes the color profile(<see cref="WebpChunkType.Iccp"/>) to the stream.
149+ /// </summary>
150+ /// <param name="stream">The stream to write to.</param>
151+ /// <param name="iccProfileBytes">The color profile bytes.</param>
152+ protected void WriteColorProfile ( Stream stream , byte [ ] iccProfileBytes ) => this . WriteMetadataProfile ( stream , iccProfileBytes , WebpChunkType . Iccp ) ;
153+
154+ /// <summary>
155+ /// Writes the animation parameter(<see cref="WebpChunkType.AnimationParameter"/>) to the stream.
156+ /// </summary>
157+ /// <param name="stream">The stream to write to.</param>
158+ /// <param name="background">
159+ /// The default background color of the canvas in [Blue, Green, Red, Alpha] byte order.
160+ /// This color MAY be used to fill the unused space on the canvas around the frames,
161+ /// as well as the transparent pixels of the first frame.
162+ /// The background color is also used when the Disposal method is 1.
163+ /// </param>
164+ /// <param name="loopCount">The number of times to loop the animation. If it is 0, this means infinitely.</param>
165+ protected void WriteAnimationParameter ( Stream stream , uint background , ushort loopCount )
166+ {
167+ Span < byte > buf = this . scratchBuffer . Span [ ..4 ] ;
168+ BinaryPrimitives . WriteUInt32BigEndian ( buf , ( uint ) WebpChunkType . AnimationParameter ) ;
169+ stream . Write ( buf ) ;
170+ BinaryPrimitives . WriteUInt32LittleEndian ( buf , sizeof ( uint ) + sizeof ( ushort ) ) ;
171+ stream . Write ( buf ) ;
172+ BinaryPrimitives . WriteUInt32LittleEndian ( buf , background ) ;
173+ stream . Write ( buf ) ;
174+ BinaryPrimitives . WriteUInt16LittleEndian ( buf [ ..2 ] , loopCount ) ;
175+ stream . Write ( buf [ ..2 ] ) ;
176+ }
177+
178+ /// <summary>
179+ /// Writes the animation frame(<see cref="WebpChunkType.Animation"/>) to the stream.
180+ /// </summary>
181+ /// <param name="stream">The stream to write to.</param>
182+ /// <param name="animation">Animation frame data.</param>
183+ /// <param name="data">Frame data.</param>
184+ protected void WriteAnimationFrame ( Stream stream , AnimationFrameData animation , byte [ ] data )
185+ {
186+ uint size = AnimationFrameData . HeaderSize + ( uint ) data . Length ;
187+ Span < byte > buf = this . scratchBuffer . Span [ ..4 ] ;
188+ BinaryPrimitives . WriteUInt32BigEndian ( buf , ( uint ) WebpChunkType . Animation ) ;
189+ stream . Write ( buf ) ;
190+ BinaryPrimitives . WriteUInt32BigEndian ( buf , size ) ;
191+ stream . Write ( buf ) ;
192+ WebpChunkParsingUtils . WriteUInt24LittleEndian ( stream , animation . X ) ;
193+ WebpChunkParsingUtils . WriteUInt24LittleEndian ( stream , animation . Y ) ;
194+ WebpChunkParsingUtils . WriteUInt24LittleEndian ( stream , animation . Width - 1 ) ;
195+ WebpChunkParsingUtils . WriteUInt24LittleEndian ( stream , animation . Height - 1 ) ;
196+ WebpChunkParsingUtils . WriteUInt24LittleEndian ( stream , animation . Duration ) ;
197+ byte flag = ( byte ) ( ( ( int ) animation . BlendingMethod << 1 ) | ( int ) animation . DisposalMethod ) ;
198+ stream . WriteByte ( flag ) ;
199+ stream . Write ( data ) ;
200+ }
201+
146202 /// <summary>
147203 /// Writes the alpha chunk to the stream.
148204 /// </summary>
@@ -152,7 +208,7 @@ protected void WriteMetadataProfile(Stream stream, byte[]? metadataBytes, WebpCh
152208 protected void WriteAlphaChunk ( Stream stream , Span < byte > dataBytes , bool alphaDataIsCompressed )
153209 {
154210 uint size = ( uint ) dataBytes . Length + 1 ;
155- Span < byte > buf = this . scratchBuffer . Span . Slice ( 0 , 4 ) ;
211+ Span < byte > buf = this . scratchBuffer . Span [ .. 4 ] ;
156212 BinaryPrimitives . WriteUInt32BigEndian ( buf , ( uint ) WebpChunkType . Alpha ) ;
157213 stream . Write ( buf ) ;
158214 BinaryPrimitives . WriteUInt32LittleEndian ( buf , size ) ;
@@ -161,7 +217,7 @@ protected void WriteAlphaChunk(Stream stream, Span<byte> dataBytes, bool alphaDa
161217 byte flags = 0 ;
162218 if ( alphaDataIsCompressed )
163219 {
164- flags | = 1 ;
220+ flags = 1 ;
165221 }
166222
167223 stream . WriteByte ( flags ) ;
@@ -174,30 +230,6 @@ protected void WriteAlphaChunk(Stream stream, Span<byte> dataBytes, bool alphaDa
174230 }
175231 }
176232
177- /// <summary>
178- /// Writes the color profile to the stream.
179- /// </summary>
180- /// <param name="stream">The stream to write to.</param>
181- /// <param name="iccProfileBytes">The color profile bytes.</param>
182- protected void WriteColorProfile ( Stream stream , byte [ ] iccProfileBytes )
183- {
184- uint size = ( uint ) iccProfileBytes . Length ;
185-
186- Span < byte > buf = this . scratchBuffer . Span . Slice ( 0 , 4 ) ;
187- BinaryPrimitives . WriteUInt32BigEndian ( buf , ( uint ) WebpChunkType . Iccp ) ;
188- stream . Write ( buf ) ;
189- BinaryPrimitives . WriteUInt32LittleEndian ( buf , size ) ;
190- stream . Write ( buf ) ;
191-
192- stream . Write ( iccProfileBytes ) ;
193-
194- // Add padding byte if needed.
195- if ( ( size & 1 ) == 1 )
196- {
197- stream . WriteByte ( 0 ) ;
198- }
199- }
200-
201233 /// <summary>
202234 /// Writes a VP8X header to the stream.
203235 /// </summary>
@@ -246,8 +278,9 @@ protected void WriteVp8XHeader(Stream stream, ExifProfile? exifProfile, XmpProfi
246278 flags |= 32 ;
247279 }
248280
249- Span < byte > buf = this . scratchBuffer . Span . Slice ( 0 , 4 ) ;
250- stream . Write ( WebpConstants . Vp8XMagicBytes ) ;
281+ Span < byte > buf = this . scratchBuffer . Span [ ..4 ] ;
282+ BinaryPrimitives . WriteUInt32BigEndian ( buf , ( uint ) WebpChunkType . Vp8X ) ;
283+ stream . Write ( buf ) ;
251284 BinaryPrimitives . WriteUInt32LittleEndian ( buf , WebpConstants . Vp8XChunkSize ) ;
252285 stream . Write ( buf ) ;
253286 BinaryPrimitives . WriteUInt32LittleEndian ( buf , flags ) ;
0 commit comments