22// Licensed under the Six Labors Split License.
33#nullable disable
44
5+ using System . Buffers ;
56using System . Buffers . Binary ;
67using SixLabors . ImageSharp . Common . Helpers ;
78using SixLabors . ImageSharp . Formats . Jpeg . Components ;
@@ -25,6 +26,9 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
2526 /// </summary>
2627 private static readonly JpegFrameConfig [ ] FrameConfigs = CreateFrameConfigs ( ) ;
2728
29+ /// <summary>
30+ /// The current calling encoder.
31+ /// </summary>
2832 private readonly JpegEncoder encoder ;
2933
3034 /// <summary>
@@ -89,6 +93,9 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
8993 // Write Exif, XMP, ICC and IPTC profiles
9094 this . WriteProfiles ( metadata , buffer ) ;
9195
96+ // Write comments
97+ this . WriteComments ( image . Configuration , jpegMetadata ) ;
98+
9299 // Write the image dimensions.
93100 this . WriteStartOfFrame ( image . Width , image . Height , frameConfig , buffer ) ;
94101
@@ -167,6 +174,51 @@ private void WriteJfifApplicationHeader(ImageMetadata meta, Span<byte> buffer)
167174 this . outputStream . Write ( buffer , 0 , 18 ) ;
168175 }
169176
177+ /// <summary>
178+ /// Writes the COM tags.
179+ /// </summary>
180+ /// <param name="configuration">The configuration.</param>
181+ /// <param name="metadata">The image metadata.</param>
182+ private void WriteComments ( Configuration configuration , JpegMetadata metadata )
183+ {
184+ if ( metadata . Comments . Count == 0 )
185+ {
186+ return ;
187+ }
188+
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 )
193+ {
194+ int totalLength = comment . Value . Length ;
195+ if ( totalLength == 0 )
196+ {
197+ continue ;
198+ }
199+
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 ) ;
205+
206+ // Write the marker header.
207+ this . WriteMarkerHeader ( JpegConstants . Markers . COM , currentLength + 2 , buffer ) ;
208+
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+ }
214+
215+ // Write the comment.
216+ this . outputStream . Write ( buffer , 0 , currentLength ) ;
217+ totalLength -= currentLength ;
218+ }
219+ }
220+ }
221+
170222 /// <summary>
171223 /// Writes the Define Huffman Table marker and tables.
172224 /// </summary>
0 commit comments