diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/ScanDecoder.cs
index 42cf38f2a..4fdac5373 100644
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/ScanDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/ScanDecoder.cs
@@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
// The number of bits that can be read via a LUT.
public const int FastBits = 9;
- // LUT Bmask[n] = (1 << n) - 1
+ // LUT mask for n rightmost bits. Bmask[n] = (1 << n) - 1
private static readonly uint[] Bmask = { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535 };
// LUT Bias[n] = (-1 << n) + 1
@@ -22,8 +22,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
private readonly DoubleBufferedStreamReader stream;
private readonly PdfJsFrameComponent[] components;
private readonly ZigZag dctZigZag;
+
+ // The restart interval.
private readonly int restartInterval;
+
+ // The current component index.
private readonly int componentIndex;
+
+ // The number of interleaved components.
private readonly int componentsLength;
// The spectral selection start.
@@ -53,7 +59,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
// The current, if any, marker in the input stream.
private byte marker;
- // Whether we have a bad marker, ie. one that is not between RST0 and RST7
+ // Whether we have a bad marker, I.E. One that is not between RST0 and RST7
private bool badMarker;
// The opening position of an identified marker.
@@ -68,15 +74,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
///
/// Initializes a new instance of the class.
///
- /// The input stream
- /// The scan components
- /// The component index within the array
- /// The length of the components. Different to the array length
- /// The reset interval
- /// The spectral selection start
- /// The spectral selection end
- /// The successive approximation bit high end
- /// The successive approximation bit low end
+ /// The input stream.
+ /// The scan components.
+ /// The component index within the array.
+ /// The length of the components. Different to the array length.
+ /// The reset interval.
+ /// The spectral selection start.
+ /// The spectral selection end.
+ /// The successive approximation bit high end.
+ /// The successive approximation bit low end.
public ScanDecoder(
DoubleBufferedStreamReader stream,
PdfJsFrameComponent[] components,
@@ -174,7 +180,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
if (this.codeBits < 24)
{
- this.GrowBufferUnsafe();
+ this.FillBuffer();
}
// If it's NOT a restart, then just bail, so we get corrupt data
@@ -238,7 +244,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
if (this.codeBits < 24)
{
- this.GrowBufferUnsafe();
+ this.FillBuffer();
}
// If it's NOT a restart, then just bail, so we get corrupt data
@@ -309,7 +315,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
if (this.codeBits < 24)
{
- this.GrowBufferUnsafe();
+ this.FillBuffer();
}
// If it's NOT a restart, then just bail, so we get corrupt data
@@ -371,7 +377,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
if (this.codeBits < 24)
{
- this.GrowBufferUnsafe();
+ this.FillBuffer();
}
// If it's NOT a restart, then just bail, so we get corrupt data
@@ -502,8 +508,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
ref PdfJsHuffmanTable acTable,
ref short fastACRef)
{
- int k;
-
if (this.spectralStart == 0)
{
throw new ImageFormatException("Can't merge DC and AC.");
@@ -511,6 +515,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (this.successiveHigh == 0)
{
+ // MCU decoding for AC initial scan (either spectral selection,
+ // or first pass of successive approximation).
int shift = this.successiveLow;
if (this.eobrun != 0)
@@ -519,7 +525,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
return;
}
- k = this.spectralStart;
+ int k = this.spectralStart;
do
{
int zig;
@@ -582,117 +588,125 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
else
{
// Refinement scan for these AC coefficients
- short bit = (short)(1 << this.successiveLow);
+ this.DecodeBlockProgressiveACRefined(ref blockDataRef, ref acTable);
+ }
+ }
- if (this.eobrun != 0)
+ private void DecodeBlockProgressiveACRefined(ref short blockDataRef, ref PdfJsHuffmanTable acTable)
+ {
+ int k;
+
+ // Refinement scan for these AC coefficients
+ short bit = (short)(1 << this.successiveLow);
+
+ if (this.eobrun != 0)
+ {
+ this.eobrun--;
+ for (k = this.spectralStart; k <= this.spectralEnd; k++)
{
- this.eobrun--;
- for (k = this.spectralStart; k <= this.spectralEnd; k++)
+ ref short p = ref Unsafe.Add(ref blockDataRef, this.dctZigZag[k]);
+ if (p != 0)
{
- ref short p = ref Unsafe.Add(ref blockDataRef, this.dctZigZag[k]);
- if (p != 0)
+ if (this.GetBit() != 0)
{
- if (this.GetBit() != 0)
+ if ((p & bit) == 0)
{
- if ((p & bit) == 0)
+ if (p > 0)
{
- if (p > 0)
- {
- p += bit;
- }
- else
- {
- p -= bit;
- }
+ p += bit;
+ }
+ else
+ {
+ p -= bit;
}
}
}
}
}
- else
+ }
+ else
+ {
+ k = this.spectralStart;
+ do
{
- k = this.spectralStart;
- do
+ int rs = this.DecodeHuffman(ref acTable);
+ if (rs < 0)
{
- int rs = this.DecodeHuffman(ref acTable);
- if (rs < 0)
- {
- throw new ImageFormatException("Bad Huffman code.");
- }
+ throw new ImageFormatException("Bad Huffman code.");
+ }
- int s = rs & 15;
- int r = rs >> 4;
+ int s = rs & 15;
+ int r = rs >> 4;
- if (s == 0)
+ if (s == 0)
+ {
+ // r=15 s=0 should write 16 0s, so we just do
+ // a run of 15 0s and then write s (which is 0),
+ // so we don't have to do anything special here
+ if (r < 15)
{
- // r=15 s=0 should write 16 0s, so we just do
- // a run of 15 0s and then write s (which is 0),
- // so we don't have to do anything special here
- if (r < 15)
+ this.eobrun = (1 << r) - 1;
+
+ if (r != 0)
{
- this.eobrun = (1 << r) - 1;
+ this.eobrun += this.GetBits(r);
+ }
- if (r != 0)
- {
- this.eobrun += this.GetBits(r);
- }
+ r = 64; // Force end of block
+ }
+ }
+ else
+ {
+ if (s != 1)
+ {
+ throw new ImageFormatException("Bad Huffman code.");
+ }
- r = 64; // Force end of block
- }
+ // Sign bit
+ if (this.GetBit() != 0)
+ {
+ s = bit;
}
else
{
- if (s != 1)
- {
- throw new ImageFormatException("Bad Huffman code.");
- }
-
- // Sign bit
- if (this.GetBit() != 0)
- {
- s = bit;
- }
- else
- {
- s = -bit;
- }
+ s = -bit;
}
+ }
- // Advance by r
- while (k <= this.spectralEnd)
+ // Advance by r
+ while (k <= this.spectralEnd)
+ {
+ ref short p = ref Unsafe.Add(ref blockDataRef, this.dctZigZag[k++]);
+ if (p != 0)
{
- ref short p = ref Unsafe.Add(ref blockDataRef, this.dctZigZag[k++]);
- if (p != 0)
+ if (this.GetBit() != 0)
{
- if (this.GetBit() != 0)
+ if ((p & bit) == 0)
{
- if ((p & bit) == 0)
+ if (p > 0)
+ {
+ p += bit;
+ }
+ else
{
- if (p > 0)
- {
- p += bit;
- }
- else
- {
- p -= bit;
- }
+ p -= bit;
}
}
}
- else
+ }
+ else
+ {
+ if (r == 0)
{
- if (r == 0)
- {
- p = (short)s;
- break;
- }
-
- r--;
+ p = (short)s;
+ break;
}
+
+ r--;
}
}
- while (k <= this.spectralEnd);
}
+ while (k <= this.spectralEnd);
}
}
@@ -701,7 +715,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
if (this.codeBits < n)
{
- this.GrowBufferUnsafe();
+ this.FillBuffer();
}
uint k = LRot(this.codeBuffer, n);
@@ -716,7 +730,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
if (this.codeBits < 1)
{
- this.GrowBufferUnsafe();
+ this.FillBuffer();
}
uint k = this.codeBuffer;
@@ -727,18 +741,23 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
}
[MethodImpl(MethodImplOptions.NoInlining)]
- private void GrowBufferUnsafe()
+ private void FillBuffer()
{
+ // Attempt to load at least the minimum nbumber of required bits into the buffer.
+ // We fail to do so only if we hit a marker or reach the end of the input stream.
do
{
int b = this.nomore ? 0 : this.stream.ReadByte();
if (b == -1)
{
+ // We've encountered the end of the file stream which means there's no EOI marker in the image
+ // or the SOS marker has the wrong dimensions set.
this.eof = true;
b = 0;
}
+ // Found a marker.
if (b == JpegConstants.Markers.XFF)
{
this.markerPosition = this.stream.Position - 1;
@@ -844,7 +863,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
if (this.codeBits < n)
{
- this.GrowBufferUnsafe();
+ this.FillBuffer();
}
int sgn = (int)this.codeBuffer >> 31;
@@ -860,7 +879,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
if (this.codeBits < 16)
{
- this.GrowBufferUnsafe();
+ this.FillBuffer();
}
}