diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/ScanDecoder.cs
index 6c781dc8d4..8b5ed0c053 100644
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/ScanDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/ScanDecoder.cs
@@ -84,8 +84,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// The DC Huffman tables.
/// The AC Huffman tables.
/// The fast AC decoding tables.
- /// The
- public int ParseEntropyCodedData(
+ public void ParseEntropyCodedData(
PdfJsFrame frame,
PdfJsHuffmanTables dcHuffmanTables,
PdfJsHuffmanTables acHuffmanTables,
@@ -95,256 +94,272 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (!frame.Progressive)
{
- if (this.componentsLength == 1)
+ this.ParseBaselineData(frame, dcHuffmanTables, acHuffmanTables, fastACTables);
+ }
+ else
+ {
+ this.ParseProgressiveData(frame, dcHuffmanTables, acHuffmanTables, fastACTables);
+ }
+
+ if (this.badMarker)
+ {
+ this.stream.Position = this.markerPosition;
+ }
+ }
+
+ private void ParseBaselineData(
+ PdfJsFrame frame,
+ PdfJsHuffmanTables dcHuffmanTables,
+ PdfJsHuffmanTables acHuffmanTables,
+ FastACTables fastACTables)
+ {
+ if (this.componentsLength == 1)
+ {
+ PdfJsFrameComponent component = this.components[this.componentIndex];
+
+ // Non-interleaved data, we just need to process one block at a time,
+ // in trivial scanline order
+ // number of blocks to do just depends on how many actual "pixels" this
+ // component has, independent of interleaved MCU blocking and such
+ int w = component.WidthInBlocks;
+ int h = component.HeightInBlocks;
+ ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(component.SpectralBlocks.Span));
+ ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
+ ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
+ ReadOnlySpan fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId);
+
+ int mcu = 0;
+ for (int j = 0; j < h; j++)
{
- PdfJsFrameComponent component = this.components[this.componentIndex];
-
- // Non-interleaved data, we just need to process one block at a time,
- // in trivial scanline order
- // number of blocks to do just depends on how many actual "pixels" this
- // component has, independent of interleaved MCU blocking and such
- int w = component.WidthInBlocks;
- int h = component.HeightInBlocks;
- ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(component.SpectralBlocks.Span));
- ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
- ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
- ReadOnlySpan fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId);
-
- int mcu = 0;
- for (int j = 0; j < h; j++)
+ for (int i = 0; i < w; i++)
{
- for (int i = 0; i < w; i++)
+ if (this.eof)
{
- if (this.eof)
- {
- continue;
- }
+ return;
+ }
- int blockRow = mcu / w;
- int blockCol = mcu % w;
- int offset = component.GetBlockBufferOffset(blockRow, blockCol);
- this.DecodeBlock(component, ref Unsafe.Add(ref blockDataRef, offset), ref dcHuffmanTable, ref acHuffmanTable, fastAC);
- mcu++;
+ int blockRow = mcu / w;
+ int blockCol = mcu % w;
+ int offset = component.GetBlockBufferOffset(blockRow, blockCol);
+ this.DecodeBlock(component, ref Unsafe.Add(ref blockDataRef, offset), ref dcHuffmanTable, ref acHuffmanTable, fastAC);
+ mcu++;
- // Every data block is an MCU, so countdown the restart interval
- if (--this.todo <= 0)
+ // Every data block is an MCU, so countdown the restart interval
+ if (--this.todo <= 0)
+ {
+ if (this.codeBits < 24)
{
- if (this.codeBits < 24)
- {
- this.GrowBufferUnsafe();
- }
-
- // If it's NOT a restart, then just bail, so we get corrupt data
- // rather than no data
- if (!this.IsRestartMarker(this.marker))
- {
- return 1;
- }
+ this.GrowBufferUnsafe();
+ }
- this.Reset();
+ // If it's NOT a restart, then just bail, so we get corrupt data
+ // rather than no data
+ if (!this.ContinueOnRestart())
+ {
+ return;
}
+
+ this.Reset();
}
}
}
- else
+ }
+ else
+ {
+ // Interleaved
+ int mcu = 0;
+ int mcusPerColumn = frame.McusPerColumn;
+ int mcusPerLine = frame.McusPerLine;
+ for (int j = 0; j < mcusPerColumn; j++)
{
- // Interleaved
- int mcu = 0;
- int mcusPerColumn = frame.McusPerColumn;
- int mcusPerLine = frame.McusPerLine;
- for (int j = 0; j < mcusPerColumn; j++)
+ for (int i = 0; i < mcusPerLine; i++)
{
- for (int i = 0; i < mcusPerLine; i++)
+ // Scan an interleaved mcu... process components in order
+ for (int k = 0; k < this.componentsLength; k++)
{
- // Scan an interleaved mcu... process components in order
- for (int k = 0; k < this.componentsLength; k++)
+ PdfJsFrameComponent component = this.components[k];
+ ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(component.SpectralBlocks.Span));
+ ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
+ ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
+ ReadOnlySpan fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId);
+ int h = component.HorizontalSamplingFactor;
+ int v = component.VerticalSamplingFactor;
+
+ // Scan out an mcu's worth of this component; that's just determined
+ // by the basic H and V specified for the component
+ for (int y = 0; y < v; y++)
{
- PdfJsFrameComponent component = this.components[k];
- ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(component.SpectralBlocks.Span));
- ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
- ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
- ReadOnlySpan fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId);
- int h = component.HorizontalSamplingFactor;
- int v = component.VerticalSamplingFactor;
-
- // Scan out an mcu's worth of this component; that's just determined
- // by the basic H and V specified for the component
- for (int y = 0; y < v; y++)
+ for (int x = 0; x < h; x++)
{
- for (int x = 0; x < h; x++)
+ if (this.eof)
{
- if (this.eof)
- {
- continue;
- }
-
- int mcuRow = mcu / mcusPerLine;
- int mcuCol = mcu % mcusPerLine;
- int blockRow = (mcuRow * v) + y;
- int blockCol = (mcuCol * h) + x;
- int offset = component.GetBlockBufferOffset(blockRow, blockCol);
- this.DecodeBlock(component, ref Unsafe.Add(ref blockDataRef, offset), ref dcHuffmanTable, ref acHuffmanTable, fastAC);
+ return;
}
+
+ int mcuRow = mcu / mcusPerLine;
+ int mcuCol = mcu % mcusPerLine;
+ int blockRow = (mcuRow * v) + y;
+ int blockCol = (mcuCol * h) + x;
+ int offset = component.GetBlockBufferOffset(blockRow, blockCol);
+ this.DecodeBlock(component, ref Unsafe.Add(ref blockDataRef, offset), ref dcHuffmanTable, ref acHuffmanTable, fastAC);
}
}
+ }
- // After all interleaved components, that's an interleaved MCU,
- // so now count down the restart interval
- mcu++;
- if (--this.todo <= 0)
+ // After all interleaved components, that's an interleaved MCU,
+ // so now count down the restart interval
+ mcu++;
+ if (--this.todo <= 0)
+ {
+ if (this.codeBits < 24)
{
- if (this.codeBits < 24)
- {
- this.GrowBufferUnsafe();
- }
-
- // If it's NOT a restart, then just bail, so we get corrupt data
- // rather than no data
- if (!this.IsRestartMarker(this.marker))
- {
- return 1;
- }
+ this.GrowBufferUnsafe();
+ }
- this.Reset();
+ // If it's NOT a restart, then just bail, so we get corrupt data
+ // rather than no data
+ if (!this.ContinueOnRestart())
+ {
+ return;
}
+
+ this.Reset();
}
}
}
}
- else
+ }
+
+ private void ParseProgressiveData(
+ PdfJsFrame frame,
+ PdfJsHuffmanTables dcHuffmanTables,
+ PdfJsHuffmanTables acHuffmanTables,
+ FastACTables fastACTables)
+ {
+ if (this.componentsLength == 1)
{
- if (this.componentsLength == 1)
+ PdfJsFrameComponent component = this.components[this.componentIndex];
+
+ // Non-interleaved data, we just need to process one block at a time,
+ // in trivial scanline order
+ // number of blocks to do just depends on how many actual "pixels" this
+ // component has, independent of interleaved MCU blocking and such
+ int w = component.WidthInBlocks;
+ int h = component.HeightInBlocks;
+ ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(component.SpectralBlocks.Span));
+ ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
+ ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
+ ReadOnlySpan fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId);
+
+ int mcu = 0;
+ for (int j = 0; j < h; j++)
{
- PdfJsFrameComponent component = this.components[this.componentIndex];
-
- // Non-interleaved data, we just need to process one block at a time,
- // in trivial scanline order
- // number of blocks to do just depends on how many actual "pixels" this
- // component has, independent of interleaved MCU blocking and such
- int w = component.WidthInBlocks;
- int h = component.HeightInBlocks;
- ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(component.SpectralBlocks.Span));
- ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
- ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
- ReadOnlySpan fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId);
-
- int mcu = 0;
- for (int j = 0; j < h; j++)
+ for (int i = 0; i < w; i++)
{
- for (int i = 0; i < w; i++)
+ if (this.eof)
{
- if (this.eof)
- {
- continue;
- }
+ return;
+ }
- int blockRow = mcu / w;
- int blockCol = mcu % w;
- int offset = component.GetBlockBufferOffset(blockRow, blockCol);
+ int blockRow = mcu / w;
+ int blockCol = mcu % w;
+ int offset = component.GetBlockBufferOffset(blockRow, blockCol);
- if (this.spectralStart == 0)
- {
- this.DecodeBlockProgressiveDC(component, ref Unsafe.Add(ref blockDataRef, offset), ref dcHuffmanTable);
- }
- else
- {
- this.DecodeBlockProgressiveAC(ref Unsafe.Add(ref blockDataRef, offset), ref acHuffmanTable, fastAC);
- }
+ if (this.spectralStart == 0)
+ {
+ this.DecodeBlockProgressiveDC(component, ref Unsafe.Add(ref blockDataRef, offset), ref dcHuffmanTable);
+ }
+ else
+ {
+ this.DecodeBlockProgressiveAC(ref Unsafe.Add(ref blockDataRef, offset), ref acHuffmanTable, fastAC);
+ }
- mcu++;
+ mcu++;
- // Every data block is an MCU, so countdown the restart interval
- if (--this.todo <= 0)
+ // Every data block is an MCU, so countdown the restart interval
+ if (--this.todo <= 0)
+ {
+ if (this.codeBits < 24)
{
- if (this.codeBits < 24)
- {
- this.GrowBufferUnsafe();
- }
-
- // If it's NOT a restart, then just bail, so we get corrupt data
- // rather than no data
- if (!this.IsRestartMarker(this.marker))
- {
- return 1;
- }
+ this.GrowBufferUnsafe();
+ }
- this.Reset();
+ // If it's NOT a restart, then just bail, so we get corrupt data
+ // rather than no data
+ if (!this.ContinueOnRestart())
+ {
+ return;
}
+
+ this.Reset();
}
}
}
- else
+ }
+ else
+ {
+ // Interleaved
+ int mcu = 0;
+ int mcusPerColumn = frame.McusPerColumn;
+ int mcusPerLine = frame.McusPerLine;
+ for (int j = 0; j < mcusPerColumn; j++)
{
- // Interleaved
- int mcu = 0;
- int mcusPerColumn = frame.McusPerColumn;
- int mcusPerLine = frame.McusPerLine;
- for (int j = 0; j < mcusPerColumn; j++)
+ for (int i = 0; i < mcusPerLine; i++)
{
- for (int i = 0; i < mcusPerLine; i++)
+ // Scan an interleaved mcu... process components in order
+ for (int k = 0; k < this.componentsLength; k++)
{
- // Scan an interleaved mcu... process components in order
- for (int k = 0; k < this.componentsLength; k++)
+ PdfJsFrameComponent component = this.components[k];
+ ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(component.SpectralBlocks.Span));
+ ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
+ ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
+ ReadOnlySpan fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId);
+ int h = component.HorizontalSamplingFactor;
+ int v = component.VerticalSamplingFactor;
+
+ // Scan out an mcu's worth of this component; that's just determined
+ // by the basic H and V specified for the component
+ for (int y = 0; y < v; y++)
{
- PdfJsFrameComponent component = this.components[k];
- ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(component.SpectralBlocks.Span));
- ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
- ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
- ReadOnlySpan fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId);
- int h = component.HorizontalSamplingFactor;
- int v = component.VerticalSamplingFactor;
-
- // Scan out an mcu's worth of this component; that's just determined
- // by the basic H and V specified for the component
- for (int y = 0; y < v; y++)
+ for (int x = 0; x < h; x++)
{
- for (int x = 0; x < h; x++)
+ if (this.eof)
{
- if (this.eof)
- {
- continue;
- }
-
- int mcuRow = mcu / mcusPerLine;
- int mcuCol = mcu % mcusPerLine;
- int blockRow = (mcuRow * v) + y;
- int blockCol = (mcuCol * h) + x;
- int offset = component.GetBlockBufferOffset(blockRow, blockCol);
- this.DecodeBlockProgressiveDC(component, ref Unsafe.Add(ref blockDataRef, offset), ref dcHuffmanTable);
+ return;
}
+
+ int mcuRow = mcu / mcusPerLine;
+ int mcuCol = mcu % mcusPerLine;
+ int blockRow = (mcuRow * v) + y;
+ int blockCol = (mcuCol * h) + x;
+ int offset = component.GetBlockBufferOffset(blockRow, blockCol);
+ this.DecodeBlockProgressiveDC(component, ref Unsafe.Add(ref blockDataRef, offset), ref dcHuffmanTable);
}
}
+ }
- // After all interleaved components, that's an interleaved MCU,
- // so now count down the restart interval
- mcu++;
- if (--this.todo <= 0)
+ // After all interleaved components, that's an interleaved MCU,
+ // so now count down the restart interval
+ mcu++;
+ if (--this.todo <= 0)
+ {
+ if (this.codeBits < 24)
{
- if (this.codeBits < 24)
- {
- this.GrowBufferUnsafe();
- }
-
- // If it's NOT a restart, then just bail, so we get corrupt data
- // rather than no data
- if (!this.IsRestartMarker(this.marker))
- {
- return 1;
- }
+ this.GrowBufferUnsafe();
+ }
- this.Reset();
+ // If it's NOT a restart, then just bail, so we get corrupt data
+ // rather than no data
+ if (!this.ContinueOnRestart())
+ {
+ return;
}
+
+ this.Reset();
}
}
}
}
-
- if (this.badMarker)
- {
- this.stream.Position = this.markerPosition;
- }
-
- return 1;
}
private int DecodeBlock(
@@ -696,7 +711,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
do
{
- // TODO: EOF
int b = this.nomore ? 0 : this.stream.ReadByte();
if (b == -1)
@@ -725,7 +739,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
this.marker = (byte)c;
this.nomore = true;
- if (!this.IsRestartMarker(this.marker))
+ if (!this.HasRestart())
{
this.badMarker = true;
}
@@ -831,21 +845,27 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private int PeekBits()
- {
- return (int)((this.codeBuffer >> (32 - FastBits)) & ((1 << FastBits) - 1));
- }
+ private int PeekBits() => (int)((this.codeBuffer >> (32 - FastBits)) & ((1 << FastBits) - 1));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private uint LRot(uint x, int y)
+ private uint LRot(uint x, int y) => (x << y) | (x >> (32 - y));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private bool ContinueOnRestart()
{
- return (x << y) | (x >> (32 - y));
+ if (this.badMarker)
+ {
+ this.stream.Position = this.markerPosition;
+ }
+
+ return this.HasRestart();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private bool IsRestartMarker(byte x)
+ private bool HasRestart()
{
- return x >= JpegConstants.Markers.RST0 && x <= JpegConstants.Markers.RST7;
+ byte m = this.marker;
+ return m >= JpegConstants.Markers.RST0 && m <= JpegConstants.Markers.RST7;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]