Skip to content

Commit 0d6684f

Browse files
committed
Add initial support for subsampeling in interleave mode sample
1 parent 757f1b5 commit 0d6684f

File tree

2 files changed

+48
-11
lines changed

2 files changed

+48
-11
lines changed

src/JpegLSEncoder.cs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -354,9 +354,11 @@ public void EncodeComponents(ReadOnlySpan<byte> source, int sourceComponentCount
354354
}
355355
else
356356
{
357-
int scanStride = CheckStrideAndSourceLength(source.Length, stride, sourceComponentCount);
357+
int scanWidth = GetScanWidth(_encodedComponentCount);
358+
int scanHeight = GetScanHeight(_encodedComponentCount);
359+
int scanStride = CheckStrideAndSourceLength(source.Length, stride, scanWidth, scanHeight, sourceComponentCount);
358360
_writer.WriteStartOfScanSegment(sourceComponentCount, NearLossless, InterleaveMode);
359-
EncodeScan(source, scanStride, FrameInfo.Width, FrameInfo.Height, sourceComponentCount, explicitCodingParameters);
361+
EncodeScan(source, scanStride, scanWidth, scanHeight, sourceComponentCount, explicitCodingParameters);
360362
}
361363

362364
_encodedComponentCount += sourceComponentCount;
@@ -651,9 +653,9 @@ private void CheckInterleaveModeAgainstComponentCount(int componentCount)
651653
ThrowHelper.ThrowArgumentException(ErrorCode.InvalidArgumentInterleaveMode);
652654
}
653655

654-
private int CheckStrideAndSourceLength(int sourceLength, int stride, int sourceComponentCount)
656+
private int CheckStrideAndSourceLength(int sourceLength, int stride, int scanWidth, int scanHeight, int sourceComponentCount)
655657
{
656-
int minimumStride = CalculateMinimumStride(sourceComponentCount);
658+
int minimumStride = CalculateMinimumStride(scanWidth, sourceComponentCount);
657659

658660
if (stride == AutoCalculateStride)
659661
{
@@ -667,8 +669,8 @@ private int CheckStrideAndSourceLength(int sourceLength, int stride, int sourceC
667669

668670
int notUsedBytesAtEnd = stride - minimumStride;
669671
int minimumSourceLength = InterleaveMode == InterleaveMode.None
670-
? (stride * sourceComponentCount * FrameInfo.Height) - notUsedBytesAtEnd
671-
: (stride * FrameInfo.Height) - notUsedBytesAtEnd;
672+
? (stride * sourceComponentCount * scanHeight) - notUsedBytesAtEnd
673+
: (stride * scanHeight) - notUsedBytesAtEnd;
672674

673675
if (sourceLength < minimumSourceLength)
674676
ThrowHelper.ThrowArgumentException(ErrorCode.InvalidArgumentSize);
@@ -698,13 +700,20 @@ private int CheckStrideAndSourceLengthInterleaveModeNone(int sourceLength, int s
698700
return stride;
699701
}
700702

701-
private int CalculateMinimumStride(int sourceComponentCount)
703+
private int CalculateMinimumStride(int scanWidth, int sourceComponentCount)
702704
{
703-
int stride = FrameInfo.Width * BitToByteCount(FrameInfo.BitsPerSample);
704-
if (_interleaveMode == InterleaveMode.None)
705-
return stride;
705+
switch (_interleaveMode)
706+
{
707+
case InterleaveMode.None:
708+
return FrameInfo.Width * BitToByteCount(FrameInfo.BitsPerSample);
709+
710+
case InterleaveMode.Line:
711+
return FrameInfo.Width * BitToByteCount(FrameInfo.BitsPerSample) * sourceComponentCount;
706712

707-
return stride * sourceComponentCount;
713+
default:
714+
Debug.Assert(_interleaveMode == InterleaveMode.Sample);
715+
return scanWidth * BitToByteCount(FrameInfo.BitsPerSample) * sourceComponentCount;
716+
}
708717
}
709718

710719
private void DetermineMaxSamplingFactors()

test/EncodeTest.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,34 @@ public void EncodeSubSamplingInterleaveNone()
439439
CheckOutput(component2, destination[(2 * 2 * 2)..], decoder, 1, 2 * 1);
440440
}
441441

442+
[Fact]
443+
public void EncodeSubSamplingInterleaveSample()
444+
{
445+
JpegLSEncoder encoder = new() { FrameInfo = new FrameInfo(2, 2, 8, 3), InterleaveMode = InterleaveMode.None };
446+
447+
Memory<byte> encodedData = new byte[encoder.EstimatedDestinationSize];
448+
encoder.Destination = encodedData;
449+
450+
byte[] component0 = [24, 23, 22, 21];
451+
byte[] component1And2 = [25, 26];
452+
453+
encoder.SetSamplingFactor(0, 2, 2);
454+
encoder.SetSamplingFactor(1, 1, 1);
455+
encoder.SetSamplingFactor(2, 1, 1);
456+
encoder.EncodeComponents(component0, 1);
457+
encoder.InterleaveMode = InterleaveMode.Sample;
458+
encoder.EncodeComponents(component1And2, 2);
459+
460+
JpegLSDecoder decoder = new() { Source = encoder.EncodedData };
461+
decoder.ReadHeader();
462+
463+
Span<byte> destination = new byte[decoder.GetDestinationSize()];
464+
decoder.Decode(destination);
465+
466+
CheckOutput(component0, destination, decoder, 1, 2 * 2);
467+
CheckOutput(component1And2, destination[(2 * 2)..], decoder, 1, 1 * 2);
468+
}
469+
442470
private static void CheckOutput(Span<byte> source, Span<byte> destination, JpegLSDecoder decoder, int componentCount, int componentSize)
443471
{
444472
for (int component = 0; component < componentCount; ++component)

0 commit comments

Comments
 (0)