2
2
// Licensed under the Six Labors Split License.
3
3
#nullable disable
4
4
5
+ using System . Buffers ;
5
6
using System . Buffers . Binary ;
6
- using System . Collections ;
7
- using System . Text ;
8
7
using SixLabors . ImageSharp . Common . Helpers ;
9
8
using SixLabors . ImageSharp . Formats . Jpeg . Components ;
10
9
using SixLabors . ImageSharp . Formats . Jpeg . Components . Encoder ;
@@ -27,6 +26,9 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
27
26
/// </summary>
28
27
private static readonly JpegFrameConfig [ ] FrameConfigs = CreateFrameConfigs ( ) ;
29
28
29
+ /// <summary>
30
+ /// The current calling encoder.
31
+ /// </summary>
30
32
private readonly JpegEncoder encoder ;
31
33
32
34
/// <summary>
@@ -92,7 +94,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
92
94
this . WriteProfiles ( metadata , buffer ) ;
93
95
94
96
// Write comments
95
- this . WriteComment ( jpegMetadata ) ;
97
+ this . WriteComments ( image . Configuration , jpegMetadata ) ;
96
98
97
99
// Write the image dimensions.
98
100
this . WriteStartOfFrame ( image . Width , image . Height , frameConfig , buffer ) ;
@@ -173,67 +175,48 @@ private void WriteJfifApplicationHeader(ImageMetadata meta, Span<byte> buffer)
173
175
}
174
176
175
177
/// <summary>
176
- /// Writes comment
178
+ /// Writes the COM tags.
177
179
/// </summary>
180
+ /// <param name="configuration">The configuration.</param>
178
181
/// <param name="metadata">The image metadata.</param>
179
- private void WriteComment ( JpegMetadata metadata )
182
+ private void WriteComments ( Configuration configuration , JpegMetadata metadata )
180
183
{
181
- int maxCommentLength = 65533 ;
182
-
183
184
if ( metadata . Comments . Count == 0 )
184
185
{
185
186
return ;
186
187
}
187
188
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 )
193
193
{
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 )
198
196
{
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 ;
205
198
}
206
199
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 ) ;
216
205
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 ) ;
220
208
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
+ }
225
214
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 ;
231
218
}
232
-
233
- currentCommentStartingIndex += comment . Length + 4 ;
234
219
}
235
-
236
- this . outputStream . Write ( payload , 0 , payload . Length ) ;
237
220
}
238
221
239
222
/// <summary>
0 commit comments