@@ -87,6 +87,8 @@ internal class HuffmanScanEncoder
87
87
/// </remarks>
88
88
private readonly byte [ ] streamWriteBuffer ;
89
89
90
+ private readonly int restartInterval ;
91
+
90
92
/// <summary>
91
93
/// Number of jagged bits stored in <see cref="accumulatedBits"/>
92
94
/// </summary>
@@ -103,13 +105,16 @@ internal class HuffmanScanEncoder
103
105
/// Initializes a new instance of the <see cref="HuffmanScanEncoder"/> class.
104
106
/// </summary>
105
107
/// <param name="blocksPerCodingUnit">Amount of encoded 8x8 blocks per single jpeg macroblock.</param>
108
+ /// <param name="restartInterval">Numbers of MCUs between restart markers.</param>
106
109
/// <param name="outputStream">Output stream for saving encoded data.</param>
107
- public HuffmanScanEncoder ( int blocksPerCodingUnit , Stream outputStream )
110
+ public HuffmanScanEncoder ( int blocksPerCodingUnit , int restartInterval , Stream outputStream )
108
111
{
109
112
int emitBufferByteLength = MaxBytesPerBlock * blocksPerCodingUnit ;
110
113
this . emitBuffer = new uint [ emitBufferByteLength / sizeof ( uint ) ] ;
111
114
this . emitWriteIndex = this . emitBuffer . Length ;
112
115
116
+ this . restartInterval = restartInterval ;
117
+
113
118
this . streamWriteBuffer = new byte [ emitBufferByteLength * OutputBufferLengthMultiplier ] ;
114
119
115
120
this . target = outputStream ;
@@ -211,6 +216,9 @@ public void EncodeScanBaseline(Component component, CancellationToken cancellati
211
216
ref HuffmanLut dcHuffmanTable = ref this . dcHuffmanTables [ component . DcTableId ] ;
212
217
ref HuffmanLut acHuffmanTable = ref this . acHuffmanTables [ component . AcTableId ] ;
213
218
219
+ int restarts = 0 ;
220
+ int restartsToGo = this . restartInterval ;
221
+
214
222
for ( int i = 0 ; i < h ; i ++ )
215
223
{
216
224
cancellationToken . ThrowIfCancellationRequested ( ) ;
@@ -221,6 +229,13 @@ public void EncodeScanBaseline(Component component, CancellationToken cancellati
221
229
222
230
for ( nuint k = 0 ; k < ( uint ) w ; k ++ )
223
231
{
232
+ if ( this . restartInterval > 0 && restartsToGo == 0 )
233
+ {
234
+ this . FlushRemainingBytes ( ) ;
235
+ this . WriteRestart ( restarts % 8 ) ;
236
+ component . DcPredictor = 0 ;
237
+ }
238
+
224
239
this . WriteBlock (
225
240
component ,
226
241
ref Unsafe . Add ( ref blockRef , k ) ,
@@ -231,6 +246,17 @@ ref Unsafe.Add(ref blockRef, k),
231
246
{
232
247
this . FlushToStream ( ) ;
233
248
}
249
+
250
+ if ( this . restartInterval > 0 )
251
+ {
252
+ if ( restartsToGo == 0 )
253
+ {
254
+ restartsToGo = this . restartInterval ;
255
+ restarts ++ ;
256
+ }
257
+
258
+ restartsToGo -- ;
259
+ }
234
260
}
235
261
}
236
262
@@ -241,17 +267,16 @@ ref Unsafe.Add(ref blockRef, k),
241
267
/// Encodes the DC coefficients for a given component's blocks in a scan.
242
268
/// </summary>
243
269
/// <param name="component">The component whose DC coefficients need to be encoded.</param>
244
- /// <param name="restartInterval">Numbers of MCUs between restart markers.</param>
245
270
/// <param name="cancellationToken">The token to request cancellation.</param>
246
- public void EncodeDcScan ( Component component , int restartInterval , CancellationToken cancellationToken )
271
+ public void EncodeDcScan ( Component component , CancellationToken cancellationToken )
247
272
{
248
273
int h = component . HeightInBlocks ;
249
274
int w = component . WidthInBlocks ;
250
275
251
276
ref HuffmanLut dcHuffmanTable = ref this . dcHuffmanTables [ component . DcTableId ] ;
252
277
253
278
int restarts = 0 ;
254
- int restartsToGo = restartInterval ;
279
+ int restartsToGo = this . restartInterval ;
255
280
256
281
for ( int i = 0 ; i < h ; i ++ )
257
282
{
@@ -262,7 +287,7 @@ public void EncodeDcScan(Component component, int restartInterval, CancellationT
262
287
263
288
for ( nuint k = 0 ; k < ( uint ) w ; k ++ )
264
289
{
265
- if ( restartInterval > 0 && restartsToGo == 0 )
290
+ if ( this . restartInterval > 0 && restartsToGo == 0 )
266
291
{
267
292
this . FlushRemainingBytes ( ) ;
268
293
this . WriteRestart ( restarts % 8 ) ;
@@ -279,13 +304,12 @@ ref Unsafe.Add(ref blockRef, k),
279
304
this . FlushToStream ( ) ;
280
305
}
281
306
282
- if ( restartInterval > 0 )
307
+ if ( this . restartInterval > 0 )
283
308
{
284
309
if ( restartsToGo == 0 )
285
310
{
286
- restartsToGo = restartInterval ;
311
+ restartsToGo = this . restartInterval ;
287
312
restarts ++ ;
288
- restarts &= 7 ;
289
313
}
290
314
291
315
restartsToGo -- ;
@@ -302,15 +326,14 @@ ref Unsafe.Add(ref blockRef, k),
302
326
/// <param name="component">The component whose AC coefficients need to be encoded.</param>
303
327
/// <param name="start">The starting index of the AC coefficient range to encode.</param>
304
328
/// <param name="end">The ending index of the AC coefficient range to encode.</param>
305
- /// <param name="restartInterval">Numbers of MCUs between restart markers.</param>
306
329
/// <param name="cancellationToken">The token to request cancellation.</param>
307
- public void EncodeAcScan ( Component component , nint start , nint end , int restartInterval , CancellationToken cancellationToken )
330
+ public void EncodeAcScan ( Component component , nint start , nint end , CancellationToken cancellationToken )
308
331
{
309
332
int h = component . HeightInBlocks ;
310
333
int w = component . WidthInBlocks ;
311
334
312
335
int restarts = 0 ;
313
- int restartsToGo = restartInterval ;
336
+ int restartsToGo = this . restartInterval ;
314
337
315
338
ref HuffmanLut acHuffmanTable = ref this . acHuffmanTables [ component . AcTableId ] ;
316
339
@@ -323,7 +346,7 @@ public void EncodeAcScan(Component component, nint start, nint end, int restartI
323
346
324
347
for ( nuint k = 0 ; k < ( uint ) w ; k ++ )
325
348
{
326
- if ( restartInterval > 0 && restartsToGo == 0 )
349
+ if ( this . restartInterval > 0 && restartsToGo == 0 )
327
350
{
328
351
this . FlushRemainingBytes ( ) ;
329
352
this . WriteRestart ( restarts % 8 ) ;
@@ -340,13 +363,12 @@ ref Unsafe.Add(ref blockRef, k),
340
363
this . FlushToStream ( ) ;
341
364
}
342
365
343
- if ( restartInterval > 0 )
366
+ if ( this . restartInterval > 0 )
344
367
{
345
368
if ( restartsToGo == 0 )
346
369
{
347
- restartsToGo = restartInterval ;
370
+ restartsToGo = this . restartInterval ;
348
371
restarts ++ ;
349
- restarts &= 7 ;
350
372
}
351
373
352
374
restartsToGo -- ;
@@ -370,6 +392,9 @@ private void EncodeScanBaselineInterleaved<TPixel>(JpegFrame frame, SpectralConv
370
392
int mcusPerColumn = frame . McusPerColumn ;
371
393
int mcusPerLine = frame . McusPerLine ;
372
394
395
+ int restarts = 0 ;
396
+ int restartsToGo = this . restartInterval ;
397
+
373
398
for ( int j = 0 ; j < mcusPerColumn ; j ++ )
374
399
{
375
400
cancellationToken . ThrowIfCancellationRequested ( ) ;
@@ -380,6 +405,16 @@ private void EncodeScanBaselineInterleaved<TPixel>(JpegFrame frame, SpectralConv
380
405
// Encode spectral to binary
381
406
for ( int i = 0 ; i < mcusPerLine ; i ++ )
382
407
{
408
+ if ( this . restartInterval > 0 && restartsToGo == 0 )
409
+ {
410
+ this . FlushRemainingBytes ( ) ;
411
+ this . WriteRestart ( restarts % 8 ) ;
412
+ foreach ( var component in frame . Components )
413
+ {
414
+ component . DcPredictor = 0 ;
415
+ }
416
+ }
417
+
383
418
// Scan an interleaved mcu... process components in order
384
419
int mcuCol = mcu % mcusPerLine ;
385
420
for ( int k = 0 ; k < frame . Components . Length ; k ++ )
@@ -420,6 +455,17 @@ ref Unsafe.Add(ref blockRef, blockCol),
420
455
{
421
456
this . FlushToStream ( ) ;
422
457
}
458
+
459
+ if ( this . restartInterval > 0 )
460
+ {
461
+ if ( restartsToGo == 0 )
462
+ {
463
+ restartsToGo = this . restartInterval ;
464
+ restarts ++ ;
465
+ }
466
+
467
+ restartsToGo -- ;
468
+ }
423
469
}
424
470
}
425
471
@@ -554,7 +600,7 @@ private void WriteBlock(
554
600
}
555
601
556
602
private void WriteRestart ( int restart ) =>
557
- this . target . Write ( [ 0xff , ( byte ) ( JpegConstants . Markers . RST0 + restart ) ] ) ;
603
+ this . target . Write ( [ 0xff , ( byte ) ( JpegConstants . Markers . RST0 + restart ) ] , 0 , 2 ) ;
558
604
559
605
/// <summary>
560
606
/// Emits the most significant count of bits to the buffer.
0 commit comments