@@ -10,11 +10,22 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
1010{
1111 internal abstract class BitWriterBase
1212 {
13+ private const uint MaxDimension = 16777215 ;
14+
15+ private const ulong MaxCanvasPixels = 4294967295ul ;
16+
17+ protected const uint ExtendedFileChunkSize = WebpConstants . ChunkHeaderSize + WebpConstants . Vp8XChunkSize ;
18+
1319 /// <summary>
1420 /// Buffer to write to.
1521 /// </summary>
1622 private byte [ ] buffer ;
1723
24+ /// <summary>
25+ /// A scratch buffer to reduce allocations.
26+ /// </summary>
27+ private readonly byte [ ] scratchBuffer = new byte [ 4 ] ;
28+
1829 /// <summary>
1930 /// Initializes a new instance of the <see cref="BitWriterBase"/> class.
2031 /// </summary>
@@ -81,13 +92,25 @@ protected void ResizeBuffer(int maxBytes, int sizeRequired)
8192 /// <param name="riffSize">The block length.</param>
8293 protected void WriteRiffHeader ( Stream stream , uint riffSize )
8394 {
84- Span < byte > buf = stackalloc byte [ 4 ] ;
8595 stream . Write ( WebpConstants . RiffFourCc ) ;
86- BinaryPrimitives . WriteUInt32LittleEndian ( buf , riffSize ) ;
87- stream . Write ( buf ) ;
96+ BinaryPrimitives . WriteUInt32LittleEndian ( this . scratchBuffer , riffSize ) ;
97+ stream . Write ( this . scratchBuffer . AsSpan ( 0 , 4 ) ) ;
8898 stream . Write ( WebpConstants . WebpHeader ) ;
8999 }
90100
101+ /// <summary>
102+ /// Calculates the exif chunk size.
103+ /// </summary>
104+ /// <param name="exifBytes">The exif profile bytes.</param>
105+ /// <returns>The exif chunk size in bytes.</returns>
106+ protected uint ExifChunkSize ( byte [ ] exifBytes )
107+ {
108+ uint exifSize = ( uint ) exifBytes . Length ;
109+ uint exifChunkSize = WebpConstants . ChunkHeaderSize + exifSize + ( exifSize & 1 ) ;
110+
111+ return exifChunkSize ;
112+ }
113+
91114 /// <summary>
92115 /// Writes the Exif profile to the stream.
93116 /// </summary>
@@ -97,12 +120,19 @@ protected void WriteExifProfile(Stream stream, byte[] exifBytes)
97120 {
98121 DebugGuard . NotNull ( exifBytes , nameof ( exifBytes ) ) ;
99122
100- Span < byte > buf = stackalloc byte [ 4 ] ;
123+ uint size = ( uint ) exifBytes . Length ;
124+ Span < byte > buf = this . scratchBuffer . AsSpan ( 0 , 4 ) ;
101125 BinaryPrimitives . WriteUInt32BigEndian ( buf , ( uint ) WebpChunkType . Exif ) ;
102126 stream . Write ( buf ) ;
103- BinaryPrimitives . WriteUInt32LittleEndian ( buf , ( uint ) exifBytes . Length ) ;
127+ BinaryPrimitives . WriteUInt32LittleEndian ( buf , size ) ;
104128 stream . Write ( buf ) ;
105129 stream . Write ( exifBytes ) ;
130+
131+ // Add padding byte if needed.
132+ if ( ( size & 1 ) == 1 )
133+ {
134+ stream . WriteByte ( 0 ) ;
135+ }
106136 }
107137
108138 /// <summary>
@@ -114,14 +144,13 @@ protected void WriteExifProfile(Stream stream, byte[] exifBytes)
114144 /// <param name="height">The height of the image.</param>
115145 protected void WriteVp8XHeader ( Stream stream , ExifProfile exifProfile , uint width , uint height )
116146 {
117- int maxDimension = 16777215 ;
118- if ( width > maxDimension || height > maxDimension )
147+ if ( width > MaxDimension || height > MaxDimension )
119148 {
120- WebpThrowHelper . ThrowInvalidImageDimensions ( $ "Image width or height exceeds maximum allowed dimension of { maxDimension } ") ;
149+ WebpThrowHelper . ThrowInvalidImageDimensions ( $ "Image width or height exceeds maximum allowed dimension of { MaxDimension } ") ;
121150 }
122151
123152 // The spec states that the product of Canvas Width and Canvas Height MUST be at most 2^32 - 1.
124- if ( width * height > 4294967295ul )
153+ if ( width * height > MaxCanvasPixels )
125154 {
126155 WebpThrowHelper . ThrowInvalidImageDimensions ( "The product of image width and height MUST be at most 2^32 - 1" ) ;
127156 }
@@ -133,7 +162,7 @@ protected void WriteVp8XHeader(Stream stream, ExifProfile exifProfile, uint widt
133162 flags |= 8 ;
134163 }
135164
136- Span < byte > buf = stackalloc byte [ 4 ] ;
165+ Span < byte > buf = this . scratchBuffer . AsSpan ( 0 , 4 ) ;
137166 stream . Write ( WebpConstants . Vp8XMagicBytes ) ;
138167 BinaryPrimitives . WriteUInt32LittleEndian ( buf , WebpConstants . Vp8XChunkSize ) ;
139168 stream . Write ( buf ) ;
0 commit comments