Skip to content

Commit 8a202c0

Browse files
committed
Initial support for subsampling interleave mode line
1 parent 0d6684f commit 8a202c0

File tree

9 files changed

+85
-7
lines changed

9 files changed

+85
-7
lines changed

fuzzing/lib-fuzzer-decode/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ public static void Main()
1616
byte[] input = readOnlyInput.ToArray();
1717
var decoder = new JpegLSDecoder(input, false);
1818
decoder.ReadHeader();
19+
if (decoder.CompressedDataFormat == CompressedDataFormat.AbbreviatedTableSpecification)
20+
return;
21+
1922
int size = decoder.GetDestinationSize();
2023
if (size > 8192 * 8192 * 3)
2124
return;

src/JpegLSDecoder.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,12 +205,14 @@ public InterleaveMode GetInterleaveMode(int componentIndex = 0)
205205
/// Gets the required size of the destination buffer.
206206
/// </summary>
207207
/// <param name="stride">The stride to use; byte count to the next pixel row. Pass 0 (AutoCalculateStride) for the default.</param>
208-
/// <returns>The size of the destination buffer in bytes.</returns>
208+
/// <returns>The size of the destination buffer in bytes or 0 for abbreviated table specification format.</returns>
209209
/// <exception cref="InvalidDataException">When the required destination size doesn't fit in an int.</exception>
210210
/// <exception cref="InvalidOperationException">Thrown when this method is called before <see cref="ReadHeader(bool)"/>.</exception>
211211
public int GetDestinationSize(int stride = AutoCalculateStride)
212212
{
213213
CheckStateHeaderRead();
214+
if (CompressedDataFormat == CompressedDataFormat.AbbreviatedTableSpecification)
215+
return 0;
214216

215217
checked
216218
{

src/RunModeContext.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,25 @@ internal RunModeContext(int runInterruptionType, int range)
1818

1919
internal int RunInterruptionType { get; }
2020

21+
internal readonly int ComputeGolombCodingParameterChecked()
22+
{
23+
uint temp = (uint)(_a + ((_n >> 1) * RunInterruptionType));
24+
uint nTest = _n;
25+
int k = 0;
26+
for (; nTest < temp; ++k)
27+
{
28+
nTest <<= 1;
29+
if (k > 32)
30+
ThrowHelper.ThrowInvalidDataException(ErrorCode.InvalidData);
31+
}
32+
33+
return k;
34+
}
35+
2136
internal readonly int ComputeGolombCodingParameter()
2237
{
23-
int temp = _a + ((_n >> 1) * RunInterruptionType);
24-
int nTest = _n;
38+
uint temp = (uint)(_a + ((_n >> 1) * RunInterruptionType));
39+
uint nTest = _n;
2540
int k = 0;
2641
for (; nTest < temp; ++k)
2742
{

src/ScanDecoder.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,8 +1207,8 @@ private int DecodeRegular(int qs, int predicted)
12071207
{
12081208
int sign = BitWiseSign(qs);
12091209
ref var context = ref _scanCodec.RegularModeContext[ApplySign(qs, sign)];
1210+
int correctedPrediction = Traits.CorrectPrediction(predicted + ApplySign(context.C, sign));
12101211
int k = context.ComputeGolombCodingParameterChecked();
1211-
int predictedValue = Traits.CorrectPrediction(predicted + ApplySign(context.C, sign));
12121212

12131213
int errorValue;
12141214
var golombCodeMatch = GolombCodeTable[k].Get(PeekByte());
@@ -1233,7 +1233,7 @@ private int DecodeRegular(int qs, int predicted)
12331233

12341234
context.UpdateVariablesAndBias(errorValue, _scanCodec.NearLossless, _scanCodec.ResetThreshold);
12351235
errorValue = ApplySign(errorValue, sign);
1236-
return Traits.ComputeReconstructedSample(predictedValue, errorValue);
1236+
return Traits.ComputeReconstructedSample(correctedPrediction, errorValue);
12371237
}
12381238

12391239
private int DecodeRunMode(int startIndex, Span<byte> previousLine, Span<byte> currentLine)
@@ -1741,7 +1741,7 @@ private Quad<ushort> DecodeRunInterruptionPixel(Quad<ushort> ra, Quad<ushort> rb
17411741

17421742
private int DecodeRunInterruptionError(ref RunModeContext context)
17431743
{
1744-
int k = context.ComputeGolombCodingParameter();
1744+
int k = context.ComputeGolombCodingParameterChecked();
17451745
int eMappedErrorValue = DecodeMappedErrorValue(k, _scanCodec.Limit - ScanCodec.J[_scanCodec.RunIndex] - 1, _scanCodec.QuantizedBitsPerSample);
17461746
int errorValue = context.ComputeErrorValue(eMappedErrorValue + context.RunInterruptionType, k);
17471747
context.UpdateVariables(errorValue, eMappedErrorValue, (byte)_scanCodec.PresetCodingParameters.ResetValue);

test/CharLS.Managed.Test.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@
120120
<None Update="test-images/fuzzy-input-no-valid-bits-at-the-end.jls">
121121
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
122122
</None>
123+
<None Update="test-images/fuzzy-input-bad-run-mode-golomb-code.jls">
124+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
125+
</None>
126+
123127
</ItemGroup>
124128

125129
</Project>

test/EncodeTest.cs

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

442+
[Fact]
443+
public void EncodeSubSamplingInterleaveLine()
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[] components = [24, 25, 26, 23, 0, 0, 22, 0, 0, 21, 0, 0];
451+
452+
encoder.SetSamplingFactor(0, 2, 2);
453+
encoder.SetSamplingFactor(1, 1, 1);
454+
encoder.SetSamplingFactor(2, 1, 1);
455+
encoder.InterleaveMode = InterleaveMode.Line;
456+
encoder.Encode(components);
457+
458+
JpegLSDecoder decoder = new() { Source = encoder.EncodedData };
459+
decoder.ReadHeader();
460+
461+
Span<byte> destination = new byte[decoder.GetDestinationSize()];
462+
decoder.Decode(destination);
463+
464+
//CheckOutput(component0, destination, decoder, 1, 2 * 2);
465+
//CheckOutput(component1And2, destination[(2 * 2)..], decoder, 1, 1 * 2);
466+
}
467+
442468
[Fact]
443469
public void EncodeSubSamplingInterleaveSample()
444470
{

test/JpegLSDecoderTest.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,33 @@ public void DecodeFuzzyInputNoValidBitsAtTheEndThrows()
168168
Assert.Equal(ErrorCode.InvalidData, exception.GetErrorCode());
169169
}
170170

171+
[Fact]
172+
public void DecodeFuzzyInputBadRunModeGolombCodeThrows()
173+
{
174+
JpegLSDecoder decoder = new(ReadAllBytes("test-images/fuzzy-input-bad-run-mode-golomb-code.jls"));
175+
byte[] destination = new byte[decoder.GetDestinationSize()];
176+
177+
var exception = Assert.Throws<InvalidDataException>(() => decoder.Decode(destination));
178+
179+
Assert.False(string.IsNullOrEmpty(exception.Message));
180+
Assert.Equal(ErrorCode.InvalidData, exception.GetErrorCode());
181+
}
182+
183+
[Fact]
184+
public void GetDestinationSizeReturnsZeroForAbbreviatedTableSpecification()
185+
{
186+
byte[] tableData = new byte[255];
187+
JpegTestStreamWriter writer = new();
188+
writer.WriteStartOfImage();
189+
writer.WriteJpegLSPresetParametersSegment(1, 1, tableData, false);
190+
writer.WriteMarker(JpegMarkerCode.EndOfImage);
191+
JpegLSDecoder decoder = new(writer.GetBuffer());
192+
193+
int size = decoder.GetDestinationSize();
194+
195+
Assert.Equal(0, size);
196+
}
197+
171198
[Fact]
172199
public void DecodeDestinationSizeOverflowThrows()
173200
{
@@ -635,7 +662,7 @@ public void OversizeImageDimensionZeroBeforeStartOfFrame()
635662
}
636663

637664
[Fact]
638-
public void OversizeImageDimensionWithInvalidNumberOfBytesThrows() // NOLINT
665+
public void OversizeImageDimensionWithInvalidNumberOfBytesThrows()
639666
{
640667
JpegTestStreamWriter writer = new();
641668
writer.WriteStartOfImage();

test/RunModeContextTest.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ public void UpdateVariables()
1313
runModeContext.UpdateVariables(3, 27, 0);
1414

1515
Assert.Equal(3, runModeContext.ComputeGolombCodingParameter());
16+
Assert.Equal(3, runModeContext.ComputeGolombCodingParameterChecked());
1617
}
1718
}
3.51 KB
Binary file not shown.

0 commit comments

Comments
 (0)