diff --git a/src/ImageSharp/Formats/Jpg/Components/Decoder/DecoderScanProcessor.cs b/src/ImageSharp/Formats/Jpg/Components/Decoder/JpegScanDecoder.cs
similarity index 79%
rename from src/ImageSharp/Formats/Jpg/Components/Decoder/DecoderScanProcessor.cs
rename to src/ImageSharp/Formats/Jpg/Components/Decoder/JpegScanDecoder.cs
index a601d521b..664219b9b 100644
--- a/src/ImageSharp/Formats/Jpg/Components/Decoder/DecoderScanProcessor.cs
+++ b/src/ImageSharp/Formats/Jpg/Components/Decoder/JpegScanDecoder.cs
@@ -1,11 +1,22 @@
-namespace ImageSharp.Formats.Jpg
+// ReSharper disable InconsistentNaming
+namespace ImageSharp.Formats.Jpg
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
- internal unsafe struct DecoderScanProcessor
+ internal unsafe struct JpegScanDecoder
{
+ ///
+ /// The AC table index
+ ///
+ internal const int AcTableIndex = 1;
+
+ ///
+ /// The DC table index
+ ///
+ internal const int DcTableIndex = 0;
+
[StructLayout(LayoutKind.Sequential)]
public struct ComponentData
{
@@ -19,9 +30,9 @@
public UnzigData Unzig;
- //public fixed byte ScanData [3 * JpegDecoderCore.MaxComponents];
+ public fixed byte ScanData [3 * JpegDecoderCore.MaxComponents];
- //public fixed int Dc [JpegDecoderCore.MaxComponents];
+ public fixed int Dc [JpegDecoderCore.MaxComponents];
public static ComponentData Create()
{
@@ -43,9 +54,9 @@
public int* Unzig;
- //public Scan* Scan;
+ public Scan* Scan;
- //public int* Dc;
+ public int* Dc;
public ComponentPointers(ComponentData* basePtr)
{
@@ -54,46 +65,67 @@
this.Temp2 = &basePtr->Temp2;
this.QuantiazationTable = &basePtr->QuantiazationTable;
this.Unzig = basePtr->Unzig.Data;
- //this.Scan = (Scan*) basePtr->ScanData;
- //this.Dc = basePtr->Dc;
+ this.Scan = (Scan*)basePtr->ScanData;
+ this.Dc = basePtr->Dc;
}
}
- //private void ResetDc()
- //{
- // Unsafe.InitBlock(this.Pointers.Dc, default(byte), sizeof(int) * JpegDecoderCore.MaxComponents);
- //}
+ private void ResetDc()
+ {
+ Unsafe.InitBlock(this.Pointers.Dc, default(byte), sizeof(int) * JpegDecoderCore.MaxComponents);
+ }
+
+
+ // bx and by are the location of the current block, in units of 8x8
+ // blocks: the third block in the first row has (bx, by) = (2, 0).
+
+ private int bx;
+
+ private int by;
- public int bx;
+ // zigStart and zigEnd are the spectral selection bounds.
+ // ah and al are the successive approximation high and low values.
+ // The spec calls these values Ss, Se, Ah and Al.
+ // For progressive JPEGs, these are the two more-or-less independent
+ // aspects of progression. Spectral selection progression is when not
+ // all of a block's 64 DCT coefficients are transmitted in one pass.
+ // For example, three passes could transmit coefficient 0 (the DC
+ // component), coefficients 1-5, and coefficients 6-63, in zig-zag
+ // order. Successive approximation is when not all of the bits of a
+ // band of coefficients are transmitted in one pass. For example,
+ // three passes could transmit the 6 most significant bits, followed
+ // by the second-least significant bit, followed by the least
+ // significant bit.
+ // For baseline JPEGs, these parameters are hard-coded to 0/63/0/0.
- public int by;
+ private int zigStart;
- public int zigStart;
+ private int zigEnd;
- public int zigEnd;
+ private int ah;
- public int ah;
+ private int al;
- public int al;
+ // XNumberOfMCUs and YNumberOfMCUs are the number of MCUs (Minimum Coded Units) in the image.
- public int mxx;
+ public int XNumberOfMCUs;
- public int myy;
+ public int YNumberOfMCUs;
- public int scanComponentCount;
+ private int scanComponentCount;
- public ComponentData Data;
+ private ComponentData Data;
- public ComponentPointers Pointers;
+ private ComponentPointers Pointers;
- public static void Init(DecoderScanProcessor* p, JpegDecoderCore decoder, int remaining, Scan[] scan)
+ public static void Init(JpegScanDecoder* p, JpegDecoderCore decoder, int remaining)
{
p->Data = ComponentData.Create();
p->Pointers = new ComponentPointers(&p->Data);
- p->InitImpl(decoder, remaining, scan);
+ p->InitImpl(decoder, remaining);
}
- private void InitImpl(JpegDecoderCore decoder, int remaining, Scan[] scan)
+ private void InitImpl(JpegDecoderCore decoder, int remaining)
{
if (decoder.ComponentCount == 0)
{
@@ -118,7 +150,7 @@
for (int i = 0; i < this.scanComponentCount; i++)
{
- this.ProcessScanImpl(decoder, i, ref scan[i], ref totalHv, scan);
+ this.ProcessScanImpl(decoder, i, ref this.Pointers.Scan[i], ref totalHv);
}
// Section B.2.3 states that if there is more than one component then the
// total H*V values in a scan must be <= 10.
@@ -153,20 +185,20 @@
}
}
- // mxx and myy are the number of MCUs (Minimum Coded Units) in the image.
+ // XNumberOfMCUs and YNumberOfMCUs are the number of MCUs (Minimum Coded Units) in the image.
int h0 = decoder.ComponentArray[0].HorizontalFactor;
int v0 = decoder.ComponentArray[0].VerticalFactor;
- this.mxx = (decoder.ImageWidth + (8 * h0) - 1) / (8 * h0);
- this.myy = (decoder.ImageHeight + (8 * v0) - 1) / (8 * v0);
+ this.XNumberOfMCUs = (decoder.ImageWidth + (8 * h0) - 1) / (8 * h0);
+ this.YNumberOfMCUs = (decoder.ImageHeight + (8 * v0) - 1) / (8 * v0);
if (decoder.IsProgressive)
{
for (int i = 0; i < this.scanComponentCount; i++)
{
- int compIndex = scan[i].Index;
+ int compIndex = this.Pointers.Scan[i].Index;
if (decoder.ProgCoeffs[compIndex] == null)
{
- int size = this.mxx * this.myy * decoder.ComponentArray[compIndex].HorizontalFactor
+ int size = this.XNumberOfMCUs * this.YNumberOfMCUs * decoder.ComponentArray[compIndex].HorizontalFactor
* decoder.ComponentArray[compIndex].VerticalFactor;
decoder.ProgCoeffs[compIndex] = new Block8x8F[size];
@@ -175,7 +207,7 @@
}
}
- private void ProcessScanImpl(JpegDecoderCore decoder, int i, ref Scan currentScan, ref int totalHv, Scan[] scan)
+ private void ProcessScanImpl(JpegDecoderCore decoder, int i, ref Scan currentScan, ref int totalHv)
{
// Component selector.
int cs = decoder.Temp[1 + (2 * i)];
@@ -196,7 +228,7 @@
currentScan.Index = (byte)compIndex;
- this.ProcessComponentImpl(decoder, i, ref currentScan, ref totalHv, ref decoder.ComponentArray[compIndex], scan);
+ this.ProcessComponentImpl(decoder, i, ref currentScan, ref totalHv, ref decoder.ComponentArray[compIndex]);
}
@@ -205,7 +237,7 @@
int i,
ref Scan currentScan,
ref int totalHv,
- ref Component currentComponent, Scan[] scan)
+ ref Component currentComponent)
{
// Section B.2.3 states that "the value of Cs_j shall be different from
// the values of Cs_1 through Cs_(j-1)". Since we have previously
@@ -214,7 +246,7 @@
// into comp are unique.
for (int j = 0; j < i; j++)
{
- if (currentScan.Index == scan[j].Index)
+ if (currentScan.Index == this.Pointers.Scan[j].Index)
{
throw new ImageFormatException("Repeated component selector");
}
@@ -235,19 +267,19 @@
}
}
- public void ProcessBlocks(JpegDecoderCore decoder, Scan[] scan, ref int[] dc)
+ public void ProcessBlocks(JpegDecoderCore decoder)
{
int blockCount = 0;
int mcu = 0;
byte expectedRst = JpegConstants.Markers.RST0;
- for (int my = 0; my < this.myy; my++)
+ for (int my = 0; my < this.YNumberOfMCUs; my++)
{
- for (int mx = 0; mx < this.mxx; mx++)
+ for (int mx = 0; mx < this.XNumberOfMCUs; mx++)
{
for (int i = 0; i < this.scanComponentCount; i++)
{
- int compIndex = scan[i].Index;
+ int compIndex = this.Pointers.Scan[i].Index;
int hi = decoder.ComponentArray[compIndex].HorizontalFactor;
int vi = decoder.ComponentArray[compIndex].VerticalFactor;
@@ -282,7 +314,7 @@
}
else
{
- int q = this.mxx * hi;
+ int q = this.XNumberOfMCUs * hi;
this.bx = blockCount % q;
this.by = blockCount / q;
blockCount++;
@@ -301,7 +333,7 @@
//Load the previous partially decoded coefficients, if applicable.
if (decoder.IsProgressive)
{
- int blockIndex = ((this.by * this.mxx) * hi) + this.bx;
+ int blockIndex = ((this.by * this.XNumberOfMCUs) * hi) + this.bx;
this.Data.Block = decoder.ProgCoeffs[compIndex][blockIndex];
}
else
@@ -309,7 +341,7 @@
this.Data.Block.Clear();
}
- this.ProcessBlockImpl(decoder, i, compIndex, hi, scan, ref dc);
+ this.ProcessBlockImpl(decoder, i, compIndex, hi);
}
// for j
@@ -318,7 +350,7 @@
// for i
mcu++;
- if (decoder.RestartInterval > 0 && mcu % decoder.RestartInterval == 0 && mcu < this.mxx * this.myy)
+ if (decoder.RestartInterval > 0 && mcu % decoder.RestartInterval == 0 && mcu < this.XNumberOfMCUs * this.YNumberOfMCUs)
{
// A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input,
// but this one assumes well-formed input, and hence the restart marker follows immediately.
@@ -338,9 +370,8 @@
decoder.Bits = default(Bits);
// Reset the DC components, as per section F.2.1.3.1.
- //this.ResetDc();
- dc = new int[JpegDecoderCore.MaxComponents];
-
+ this.ResetDc();
+
// Reset the progressive decoder state, as per section G.1.2.2.
decoder.EobRun = 0;
}
@@ -351,15 +382,11 @@
}
///
- /// The AC table index
+ /// Decodes a successive approximation refinement block, as specified in section G.1.2.
///
- internal const int AcTable = 1;
-
- ///
- /// The DC table index
- ///
- internal const int DcTable = 0;
-
+ /// The Huffman tree
+ /// The low transform offset
+ /// The decoder instance
private void Refine(JpegDecoderCore decoder, ref HuffmanTree h, int delta)
{
Block8x8F* b = this.Pointers.Block;
@@ -430,9 +457,7 @@
{
break;
}
-
- int blah = zig;
-
+
zig = this.RefineNonZeroes(decoder, zig, val0, delta);
if (zig > this.zigEnd)
{
@@ -453,11 +478,20 @@
this.RefineNonZeroes(decoder, zig,-1, delta);
}
}
-
+
+ ///
+ /// Refines non-zero entries of b in zig-zag order.
+ /// If >= 0, the first zero entries are skipped over.
+ ///
+ /// The decoder
+ /// The zig-zag start index
+ /// The non-zero entry
+ /// The low transform offset
+ /// The
private int RefineNonZeroes(JpegDecoderCore decoder, int zig, int nz, int delta)
{
var b = this.Pointers.Block;
- for (; zig <= zigEnd; zig++)
+ for (; zig <= this.zigEnd; zig++)
{
int u = this.Pointers.Unzig[zig];
float bu = Block8x8F.GetScalarAt(b, u);
@@ -495,18 +529,18 @@
return zig;
}
- private void ProcessBlockImpl(JpegDecoderCore decoder, int i, int compIndex, int hi, Scan[] scan, ref int[] dc)
+ private void ProcessBlockImpl(JpegDecoderCore decoder, int i, int compIndex, int hi)
{
var b = this.Pointers.Block;
//var dc = this.Pointers.Dc;
- int huffmannIdx = (AcTable * HuffmanTree.ThRowSize) + scan[i].AcTableSelector;
+ int huffmannIdx = (AcTableIndex * HuffmanTree.ThRowSize) + this.Pointers.Scan[i].AcTableSelector;
if (this.ah != 0)
{
this.Refine(decoder, ref decoder.HuffmanTrees[huffmannIdx], 1 << this.al);
}
else
{
- int zig = zigStart;
+ int zig = this.zigStart;
if (zig == 0)
{
zig++;
@@ -514,17 +548,17 @@
// Decode the DC coefficient, as specified in section F.2.2.1.
byte value =
decoder.DecodeHuffman(
- ref decoder.HuffmanTrees[(DcTable * HuffmanTree.ThRowSize) + scan[i].DcTableSelector]);
+ ref decoder.HuffmanTrees[(DcTableIndex * HuffmanTree.ThRowSize) + this.Pointers.Scan[i].DcTableSelector]);
if (value > 16)
{
throw new ImageFormatException("Excessive DC component");
}
int deltaDC = decoder.Bits.ReceiveExtend(value, decoder);
- dc[compIndex] += deltaDC;
+ this.Pointers.Dc[compIndex] += deltaDC;
// b[0] = dc[compIndex] << al;
- Block8x8F.SetScalarAt(b, 0, dc[compIndex] << al);
+ Block8x8F.SetScalarAt(b, 0, this.Pointers.Dc[compIndex] << al);
}
if (zig <= this.zigEnd && decoder.EobRun > 0)
@@ -534,7 +568,6 @@
else
{
// Decode the AC coefficients, as specified in section F.2.2.2.
- // Huffman huffv = ;
for (; zig <= this.zigEnd; zig++)
{
byte value = decoder.DecodeHuffman(ref decoder.HuffmanTrees[huffmannIdx]);
@@ -578,8 +611,8 @@
if (this.zigEnd != Block8x8F.ScalarCount - 1 || this.al != 0)
{
// We haven't completely decoded this 8x8 block. Save the coefficients.
- // this.ProgCoeffs[compIndex][((@by * mxx) * hi) + bx] = b.Clone();
- decoder.ProgCoeffs[compIndex][((this.by * this.mxx) * hi) + this.bx] = *b;
+ // this.ProgCoeffs[compIndex][((@by * XNumberOfMCUs) * hi) + bx] = b.Clone();
+ decoder.ProgCoeffs[compIndex][((this.by * this.XNumberOfMCUs) * hi) + this.bx] = *b;
// At this point, we could execute the rest of the loop body to dequantize and
// perform the inverse DCT, to save early stages of a progressive image to the
diff --git a/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs
index 22d4f1ca8..4b3b26da9 100644
--- a/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs
@@ -17,16 +17,6 @@ namespace ImageSharp.Formats
///
internal unsafe class JpegDecoderCore : IDisposable
{
- ///
- /// The AC table index
- ///
- internal const int AcTable = 1;
-
- ///
- /// The DC table index
- ///
- internal const int DcTable = 0;
-
///
/// The maximum number of color components
///
@@ -334,7 +324,7 @@ namespace ImageSharp.Formats
return;
}
- this.ProcessStartOfScan22(remaining);
+ this.ProcessStartOfScan(remaining);
break;
case JpegConstants.Markers.DRI:
if (configOnly)
@@ -1090,164 +1080,6 @@ namespace ImageSharp.Formats
}
}
- internal void ProcessBlockImpl(
- int ah,
- Block8x8F* b,
- Block8x8F* temp1,
- Block8x8F* temp2,
- int* unzigPtr,
- Scan[] scan,
- int i,
- int zigStart,
- int zigEnd,
- int al,
- int[] dc,
- int compIndex,
- int @by,
- int mxx,
- int hi,
- int bx,
- Block8x8F* qt)
- {
- int huffmannIdx = (AcTable * HuffmanTree.ThRowSize) + scan[i].AcTableSelector;
- if (ah != 0)
- {
- this.Refine(b, ref this.HuffmanTrees[huffmannIdx], unzigPtr, zigStart, zigEnd, 1 << al);
- }
- else
- {
- int zig = zigStart;
- if (zig == 0)
- {
- zig++;
-
- // Decode the DC coefficient, as specified in section F.2.2.1.
- byte value =
- this.DecodeHuffman(
- ref this.HuffmanTrees[(DcTable * HuffmanTree.ThRowSize) + scan[i].DcTableSelector]);
- if (value > 16)
- {
- throw new ImageFormatException("Excessive DC component");
- }
-
- int deltaDC = this.Bits.ReceiveExtend(value, this);
- dc[compIndex] += deltaDC;
-
- // b[0] = dc[compIndex] << al;
- Block8x8F.SetScalarAt(b, 0, dc[compIndex] << al);
- }
-
- if (zig <= zigEnd && this.EobRun > 0)
- {
- this.EobRun--;
- }
- else
- {
- // Decode the AC coefficients, as specified in section F.2.2.2.
- // Huffman huffv = ;
- for (; zig <= zigEnd; zig++)
- {
- byte value = this.DecodeHuffman(ref this.HuffmanTrees[huffmannIdx]);
- byte val0 = (byte)(value >> 4);
- byte val1 = (byte)(value & 0x0f);
- if (val1 != 0)
- {
- zig += val0;
- if (zig > zigEnd)
- {
- break;
- }
-
- int ac = this.Bits.ReceiveExtend(val1, this);
-
- // b[Unzig[zig]] = ac << al;
- Block8x8F.SetScalarAt(b, unzigPtr[zig], ac << al);
- }
- else
- {
- if (val0 != 0x0f)
- {
- this.EobRun = (ushort)(1 << val0);
- if (val0 != 0)
- {
- this.EobRun |= (ushort)this.DecodeBits(val0);
- }
-
- this.EobRun--;
- break;
- }
-
- zig += 0x0f;
- }
- }
- }
- }
-
- if (this.IsProgressive)
- {
- if (zigEnd != Block8x8F.ScalarCount - 1 || al != 0)
- {
- // We haven't completely decoded this 8x8 block. Save the coefficients.
-
- // TODO!!!
- // throw new NotImplementedException();
- // this.ProgCoeffs[compIndex][((@by * mxx) * hi) + bx] = b.Clone();
- this.ProgCoeffs[compIndex][((@by * mxx) * hi) + bx] = *b;
-
- // At this point, we could execute the rest of the loop body to dequantize and
- // perform the inverse DCT, to save early stages of a progressive image to the
- // *image.YCbCr buffers (the whole point of progressive encoding), but in Go,
- // the jpeg.Decode function does not return until the entire image is decoded,
- // so we "continue" here to avoid wasted computation.
- return;
- }
- }
-
- // Dequantize, perform the inverse DCT and store the block to the image.
- Block8x8F.UnZig(b, qt, unzigPtr);
-
- DCT.TransformIDCT(ref *b, ref *temp1, ref *temp2);
-
- var destChannel = this.GetDestinationChannel(compIndex);
- var destArea = destChannel.GetOffsetedSubAreaForBlock(bx, by);
- destArea.LoadColorsFrom(temp1, temp2);
- }
-
- private void ProcessComponentImpl(
- int i,
- ref Scan currentScan,
- Scan[] scan,
- ref int totalHv,
- ref Component currentComponent)
- {
- // Section B.2.3 states that "the value of Cs_j shall be different from
- // the values of Cs_1 through Cs_(j-1)". Since we have previously
- // verified that a frame's component identifiers (C_i values in section
- // B.2.2) are unique, it suffices to check that the implicit indexes
- // into comp are unique.
- for (int j = 0; j < i; j++)
- {
- if (currentScan.Index == scan[j].Index)
- {
- throw new ImageFormatException("Repeated component selector");
- }
- }
-
- totalHv += currentComponent.HorizontalFactor * currentComponent.VerticalFactor;
-
- currentScan.DcTableSelector = (byte)(this.Temp[2 + (2 * i)] >> 4);
- if (currentScan.DcTableSelector > HuffmanTree.MaxTh)
- {
- throw new ImageFormatException("Bad DC table selector value");
- }
-
- currentScan.AcTableSelector = (byte)(this.Temp[2 + (2 * i)] & 0x0f);
- if (currentScan.AcTableSelector > HuffmanTree.MaxTh)
- {
- throw new ImageFormatException("Bad AC table selector value");
- }
- }
-
///
/// Processes a Define Huffman Table marker, and initializes a huffman
/// struct from its contents. Specified in section B.2.4.2.
@@ -1368,30 +1200,6 @@ namespace ImageSharp.Formats
}
}
- private void ProcessScanImpl(int i, ref Scan currentScan, Scan[] scan, ref int totalHv)
- {
- // Component selector.
- int cs = this.Temp[1 + (2 * i)];
- int compIndex = -1;
- for (int j = 0; j < this.ComponentCount; j++)
- {
- // Component compv = ;
- if (cs == this.ComponentArray[j].Identifier)
- {
- compIndex = j;
- }
- }
-
- if (compIndex < 0)
- {
- throw new ImageFormatException("Unknown component selector");
- }
-
- currentScan.Index = (byte)compIndex;
-
- this.ProcessComponentImpl(i, ref currentScan, scan, ref totalHv, ref this.ComponentArray[compIndex]);
- }
-
///
/// Processes the Start of Frame marker. Specified in section B.2.2.
///
@@ -1583,438 +1391,21 @@ namespace ImageSharp.Formats
}
}
- private void ProcessStartOfScan22(int remaining)
- {
- Scan[] scan = new Scan[MaxComponents];
- int[] dc = new int[MaxComponents];
-
- DecoderScanProcessor p = default(DecoderScanProcessor);
- DecoderScanProcessor.Init(&p, this, remaining, scan);
- this.Bits = default(Bits);
- this.MakeImage(p.mxx, p.myy);
- p.ProcessBlocks(this, scan, ref dc);
-
- }
-
///
- /// Processes the SOS (Start of scan marker).
+ /// Processes the SOS (Start of scan marker).
///
- ///
- /// TODO: This also needs some significant refactoring to follow a more OO format.
- ///
/// The remaining bytes in the segment block.
///
- /// Missing SOF Marker
- /// SOS has wrong length
+ /// Missing SOF Marker
+ /// SOS has wrong length
///
private void ProcessStartOfScan(int remaining)
{
- if (this.ComponentCount == 0)
- {
- throw new ImageFormatException("Missing SOF marker");
- }
-
- if (remaining < 6 || 4 + (2 * this.ComponentCount) < remaining || remaining % 2 != 0)
- {
- throw new ImageFormatException("SOS has wrong length");
- }
-
- this.ReadFull(this.Temp, 0, remaining);
- byte scanComponentCount = this.Temp[0];
-
- int scanComponentCountX2 = 2 * scanComponentCount;
- if (remaining != 4 + scanComponentCountX2)
- {
- throw new ImageFormatException("SOS length inconsistent with number of components");
- }
-
- Scan[] scan = new Scan[MaxComponents];
- int totalHv = 0;
-
- for (int i = 0; i < scanComponentCount; i++)
- {
- this.ProcessScanImpl(i, ref scan[i], scan, ref totalHv);
- }
-
- // Section B.2.3 states that if there is more than one component then the
- // total H*V values in a scan must be <= 10.
- if (this.ComponentCount > 1 && totalHv > 10)
- {
- throw new ImageFormatException("Total sampling factors too large.");
- }
-
- // zigStart and zigEnd are the spectral selection bounds.
- // ah and al are the successive approximation high and low values.
- // The spec calls these values Ss, Se, Ah and Al.
- // For progressive JPEGs, these are the two more-or-less independent
- // aspects of progression. Spectral selection progression is when not
- // all of a block's 64 DCT coefficients are transmitted in one pass.
- // For example, three passes could transmit coefficient 0 (the DC
- // component), coefficients 1-5, and coefficients 6-63, in zig-zag
- // order. Successive approximation is when not all of the bits of a
- // band of coefficients are transmitted in one pass. For example,
- // three passes could transmit the 6 most significant bits, followed
- // by the second-least significant bit, followed by the least
- // significant bit.
- // For baseline JPEGs, these parameters are hard-coded to 0/63/0/0.
- int zigStart = 0;
- int zigEnd = Block8x8F.ScalarCount - 1;
- int ah = 0;
- int al = 0;
-
- if (this.IsProgressive)
- {
- zigStart = this.Temp[1 + scanComponentCountX2];
- zigEnd = this.Temp[2 + scanComponentCountX2];
- ah = this.Temp[3 + scanComponentCountX2] >> 4;
- al = this.Temp[3 + scanComponentCountX2] & 0x0f;
-
- if ((zigStart == 0 && zigEnd != 0) || zigStart > zigEnd || zigEnd >= Block8x8F.ScalarCount)
- {
- throw new ImageFormatException("Bad spectral selection bounds");
- }
-
- if (zigStart != 0 && scanComponentCount != 1)
- {
- throw new ImageFormatException("Progressive AC coefficients for more than one component");
- }
-
- if (ah != 0 && ah != al + 1)
- {
- throw new ImageFormatException("Bad successive approximation values");
- }
- }
-
- // mxx and myy are the number of MCUs (Minimum Coded Units) in the image.
- int h0 = this.ComponentArray[0].HorizontalFactor;
- int v0 = this.ComponentArray[0].VerticalFactor;
- int mxx = (this.ImageWidth + (8 * h0) - 1) / (8 * h0);
- int myy = (this.ImageHeight + (8 * v0) - 1) / (8 * v0);
-
- if (this.IsProgressive)
- {
- for (int i = 0; i < scanComponentCount; i++)
- {
- int compIndex = scan[i].Index;
- if (this.ProgCoeffs[compIndex] == null)
- {
- int size = mxx * myy * this.ComponentArray[compIndex].HorizontalFactor
- * this.ComponentArray[compIndex].VerticalFactor;
-
- this.ProgCoeffs[compIndex] = new Block8x8F[size];
- }
- }
- }
-
+ JpegScanDecoder scan = default(JpegScanDecoder);
+ JpegScanDecoder.Init(&scan, this, remaining);
this.Bits = default(Bits);
-
- int mcu = 0;
- byte expectedRst = JpegConstants.Markers.RST0;
-
- // b is the decoded coefficients block, in natural (not zig-zag) order.
- // Block b;
- int[] dc = new int[MaxComponents];
-
- // bx and by are the location of the current block, in units of 8x8
- // blocks: the third block in the first row has (bx, by) = (2, 0).
- int bx, by, blockCount = 0;
-
- // TODO: A DecoderScanProcessor struct could clean up this mess
- Block8x8F b = default(Block8x8F);
- Block8x8F temp1 = default(Block8x8F);
- Block8x8F temp2 = default(Block8x8F);
-
- UnzigData unzig = UnzigData.Create();
-
- int* unzigPtr = unzig.Data;
-
-
- this.MakeImage(mxx, myy);
-
-
- for (int my = 0; my < myy; my++)
- {
- for (int mx = 0; mx < mxx; mx++)
- {
- for (int i = 0; i < scanComponentCount; i++)
- {
- int compIndex = scan[i].Index;
- int hi = this.ComponentArray[compIndex].HorizontalFactor;
- int vi = this.ComponentArray[compIndex].VerticalFactor;
-
- for (int j = 0; j < hi * vi; j++)
- {
- // The blocks are traversed one MCU at a time. For 4:2:0 chroma
- // subsampling, there are four Y 8x8 blocks in every 16x16 MCU.
- // For a baseline 32x16 pixel image, the Y blocks visiting order is:
- // 0 1 4 5
- // 2 3 6 7
- // For progressive images, the interleaved scans (those with component count > 1)
- // are traversed as above, but non-interleaved scans are traversed left
- // to right, top to bottom:
- // 0 1 2 3
- // 4 5 6 7
- // Only DC scans (zigStart == 0) can be interleave AC scans must have
- // only one component.
- // To further complicate matters, for non-interleaved scans, there is no
- // data for any blocks that are inside the image at the MCU level but
- // outside the image at the pixel level. For example, a 24x16 pixel 4:2:0
- // progressive image consists of two 16x16 MCUs. The interleaved scans
- // will process 8 Y blocks:
- // 0 1 4 5
- // 2 3 6 7
- // The non-interleaved scans will process only 6 Y blocks:
- // 0 1 2
- // 3 4 5
- if (scanComponentCount != 1)
- {
- bx = (hi * mx) + (j % hi);
- by = (vi * my) + (j / hi);
- }
- else
- {
- int q = mxx * hi;
- bx = blockCount % q;
- by = blockCount / q;
- blockCount++;
- if (bx * 8 >= this.ImageWidth || by * 8 >= this.ImageHeight)
- {
- continue;
- }
- }
-
- int qtIndex = this.ComponentArray[compIndex].Selector;
-
- // TODO: A DecoderScanProcessor struct could clean up this mess
- // TODO: Reading & processing blocks should be done in 2 separate loops. The second one could be parallelized. The first one could be async.
- fixed (Block8x8F* qtp = &this.QuantizationTables[qtIndex])
- {
- // Load the previous partially decoded coefficients, if applicable.
- if (this.IsProgressive)
- {
- int blockIndex = ((@by * mxx) * hi) + bx;
-
- fixed (Block8x8F* bp = &this.ProgCoeffs[compIndex][blockIndex])
- {
- Unsafe.CopyBlock(&b, bp, (uint) sizeof(Block8x8F) );
- }
- }
- else
- {
- b.Clear();
- }
-
- this.ProcessBlockImpl(
- ah,
- &b,
- &temp1,
- &temp2,
- unzigPtr,
- scan,
- i,
- zigStart,
- zigEnd,
- al,
- dc,
- compIndex,
- @by,
- mxx,
- hi,
- bx,
- qtp);
- }
- }
-
- // for j
- }
-
- // for i
- mcu++;
-
- if (this.RestartInterval > 0 && mcu % this.RestartInterval == 0 && mcu < mxx * myy)
- {
- // A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input,
- // but this one assumes well-formed input, and hence the restart marker follows immediately.
- this.ReadFull(this.Temp, 0, 2);
- if (this.Temp[0] != 0xff || this.Temp[1] != expectedRst)
- {
- throw new ImageFormatException("Bad RST marker");
- }
-
- expectedRst++;
- if (expectedRst == JpegConstants.Markers.RST7 + 1)
- {
- expectedRst = JpegConstants.Markers.RST0;
- }
-
- // Reset the Huffman decoder.
- this.Bits = default(Bits);
-
- // Reset the DC components, as per section F.2.1.3.1.
- dc = new int[MaxComponents];
-
- // Reset the progressive decoder state, as per section G.1.2.2.
- this.EobRun = 0;
- }
- }
-
- // for mx
- }
-
- // for my
- }
-
- ///
- /// Decodes a successive approximation refinement block, as specified in section G.1.2.
- ///
- /// The block of coefficients
- /// The Huffman tree
- /// Unzig ptr
- /// The zig-zag start index
- /// The zig-zag end index
- /// The low transform offset
- private void Refine(Block8x8F* b, ref HuffmanTree h, int* unzigPtr, int zigStart, int zigEnd, int delta)
- {
- // Refining a DC component is trivial.
- if (zigStart == 0)
- {
- if (zigEnd != 0)
- {
- throw new ImageFormatException("Invalid state for zig DC component");
- }
-
- bool bit = this.DecodeBit();
- if (bit)
- {
- int stuff = (int)Block8x8F.GetScalarAt(b, 0);
-
- // int stuff = (int)b[0];
- stuff |= delta;
-
- // b[0] = stuff;
- Block8x8F.SetScalarAt(b, 0, stuff);
- }
-
- return;
- }
-
- // Refining AC components is more complicated; see sections G.1.2.2 and G.1.2.3.
- int zig = zigStart;
- if (this.EobRun == 0)
- {
- for (; zig <= zigEnd; zig++)
- {
- bool done = false;
- int z = 0;
- byte val = this.DecodeHuffman(ref h);
- int val0 = val >> 4;
- int val1 = val & 0x0f;
-
- switch (val1)
- {
- case 0:
- if (val0 != 0x0f)
- {
- this.EobRun = (ushort)(1 << val0);
- if (val0 != 0)
- {
- this.EobRun |= (ushort)this.DecodeBits(val0);
- }
-
- done = true;
- }
-
- break;
- case 1:
- z = delta;
- bool bit = this.DecodeBit();
- if (!bit)
- {
- z = -z;
- }
-
- break;
- default:
- throw new ImageFormatException("Unexpected Huffman code");
- }
-
- if (done)
- {
- break;
- }
-
- int blah = zig;
-
- zig = this.RefineNonZeroes(b, zig, zigEnd, val0, delta, unzigPtr);
- if (zig > zigEnd)
- {
- throw new ImageFormatException($"Too many coefficients {zig} > {zigEnd}");
- }
-
- if (z != 0)
- {
- // b[Unzig[zig]] = z;
- Block8x8F.SetScalarAt(b, unzigPtr[zig], z);
- }
- }
- }
-
- if (this.EobRun > 0)
- {
- this.EobRun--;
- this.RefineNonZeroes(b, zig, zigEnd, -1, delta, unzigPtr);
- }
- }
-
- ///
- /// Refines non-zero entries of b in zig-zag order.
- /// If >= 0, the first zero entries are skipped over.
- ///
- /// The block of coefficients
- /// The zig-zag start index
- /// The zig-zag end index
- /// The non-zero entry
- /// The low transform offset
- /// Pointer to the Jpeg Unzig data (data part of )
- /// The
- private int RefineNonZeroes(Block8x8F* b, int zig, int zigEnd, int nz, int delta, int* unzigPtr)
- {
- for (; zig <= zigEnd; zig++)
- {
- int u = unzigPtr[zig];
- float bu = Block8x8F.GetScalarAt(b, u);
-
- // TODO: Are the equality comparsions OK with floating point values? Isn't an epsilon value necessary?
- if (bu == 0)
- {
- if (nz == 0)
- {
- break;
- }
-
- nz--;
- continue;
- }
-
- bool bit = this.DecodeBit();
- if (!bit)
- {
- continue;
- }
-
- if (bu >= 0)
- {
- // b[u] += delta;
- Block8x8F.SetScalarAt(b, u, bu + delta);
- }
- else
- {
- // b[u] -= delta;
- Block8x8F.SetScalarAt(b, u, bu - delta);
- }
- }
-
- return zig;
+ this.MakeImage(scan.XNumberOfMCUs, scan.YNumberOfMCUs);
+ scan.ProcessBlocks(this);
}
///