22// Licensed under the Six Labors Split License.
33#nullable disable
44
5+ using System . Buffers ;
56using System . Buffers . Binary ;
6- using System . Collections ;
7- using System . Text ;
87using SixLabors . ImageSharp . Common . Helpers ;
98using SixLabors . ImageSharp . Formats . Jpeg . Components ;
109using SixLabors . ImageSharp . Formats . Jpeg . Components . Encoder ;
@@ -27,6 +26,9 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
2726 /// </summary>
2827 private static readonly JpegFrameConfig [ ] FrameConfigs = CreateFrameConfigs ( ) ;
2928
29+ /// <summary>
30+ /// The current calling encoder.
31+ /// </summary>
3032 private readonly JpegEncoder encoder ;
3133
3234 /// <summary>
@@ -92,7 +94,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
9294 this . WriteProfiles ( metadata , buffer ) ;
9395
9496 // Write comments
95- this . WriteComment ( jpegMetadata ) ;
97+ this . WriteComments ( image . Configuration , jpegMetadata ) ;
9698
9799 // Write the image dimensions.
98100 this . WriteStartOfFrame ( image . Width , image . Height , frameConfig , buffer ) ;
@@ -173,67 +175,48 @@ private void WriteJfifApplicationHeader(ImageMetadata meta, Span<byte> buffer)
173175 }
174176
175177 /// <summary>
176- /// Writes comment
178+ /// Writes the COM tags.
177179 /// </summary>
180+ /// <param name="configuration">The configuration.</param>
178181 /// <param name="metadata">The image metadata.</param>
179- private void WriteComment ( JpegMetadata metadata )
182+ private void WriteComments ( Configuration configuration , JpegMetadata metadata )
180183 {
181- int maxCommentLength = 65533 ;
182-
183184 if ( metadata . Comments . Count == 0 )
184185 {
185186 return ;
186187 }
187188
188- // We don't want to modify original metadata
189- List < JpegComData > comments = new ( metadata . Comments ) ;
190-
191- int totalPayloadLength = 0 ;
192- for ( int i = 0 ; i < comments . Count ; i ++ )
189+ const int maxCommentLength = 65533 ;
190+ using IMemoryOwner < byte > bufferOwner = configuration . MemoryAllocator . Allocate < byte > ( maxCommentLength ) ;
191+ Span < byte > buffer = bufferOwner . Memory . Span ;
192+ foreach ( JpegComData comment in metadata . Comments )
193193 {
194- JpegComData comment = comments [ i ] ;
195- ReadOnlyMemory < char > currentComment = comment . Value ;
196-
197- if ( comment . Value . Length > maxCommentLength )
194+ int totalLength = comment . Value . Length ;
195+ if ( totalLength == 0 )
198196 {
199- ReadOnlyMemory < char > splitComment =
200- currentComment . Slice ( maxCommentLength , currentComment . Length - maxCommentLength ) ;
201- comments . Insert ( i + 1 , new JpegComData ( splitComment ) ) ;
202-
203- // We don't want to keep the extra bytes
204- comments [ i ] = new JpegComData ( currentComment . Slice ( 0 , maxCommentLength ) ) ;
197+ continue ;
205198 }
206199
207- totalPayloadLength += comment . Value . Length + 4 ;
208- }
209-
210- Span < byte > payload = new byte [ totalPayloadLength ] ;
211- int currentCommentStartingIndex = 0 ;
212-
213- for ( int i = 0 ; i < comments . Count ; i ++ )
214- {
215- ReadOnlyMemory < char > comment = comments [ i ] . Value ;
200+ // Loop through and split the comment into multiple comments if the comment length
201+ // is greater than the maximum allowed length.
202+ while ( totalLength > 0 )
203+ {
204+ int currentLength = Math . Min ( totalLength , maxCommentLength ) ;
216205
217- // Beginning of comment ff fe
218- payload [ currentCommentStartingIndex ] = JpegConstants . Markers . XFF ;
219- payload [ currentCommentStartingIndex + 1 ] = JpegConstants . Markers . COM ;
206+ // Write the marker header.
207+ this . WriteMarkerHeader ( JpegConstants . Markers . COM , currentLength + 2 , buffer ) ;
220208
221- // Write payload size
222- int comWithoutMarker = comment . Length + 2 ;
223- payload [ currentCommentStartingIndex + 2 ] = ( byte ) ( ( comWithoutMarker >> 8 ) & 0xFF ) ;
224- payload [ currentCommentStartingIndex + 3 ] = ( byte ) ( comWithoutMarker & 0xFF ) ;
209+ ReadOnlySpan < char > commentValue = comment . Value . Span . Slice ( comment . Value . Length - totalLength , currentLength ) ;
210+ for ( int i = 0 ; i < commentValue . Length ; i ++ )
211+ {
212+ buffer [ i ] = ( byte ) commentValue [ i ] ;
213+ }
225214
226- char [ ] commentChars = comment . ToArray ( ) ;
227- for ( int j = 0 ; j < commentChars . Length ; j ++ )
228- {
229- // Initial 4 bytes are always reserved
230- payload [ 4 + currentCommentStartingIndex + j ] = ( byte ) commentChars [ j ] ;
215+ // Write the comment.
216+ this . outputStream . Write ( buffer , 0 , currentLength ) ;
217+ totalLength -= currentLength ;
231218 }
232-
233- currentCommentStartingIndex += comment . Length + 4 ;
234219 }
235-
236- this . outputStream . Write ( payload , 0 , payload . Length ) ;
237220 }
238221
239222 /// <summary>
0 commit comments