Browse Source

Split decode method.

pull/643/head
James Jackson-South 8 years ago
parent
commit
c69c3aca13
  1. 426
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/ScanDecoder.cs

426
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/ScanDecoder.cs

@ -84,8 +84,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// <param name="dcHuffmanTables">The DC Huffman tables.</param> /// <param name="dcHuffmanTables">The DC Huffman tables.</param>
/// <param name="acHuffmanTables">The AC Huffman tables.</param> /// <param name="acHuffmanTables">The AC Huffman tables.</param>
/// <param name="fastACTables">The fast AC decoding tables.</param> /// <param name="fastACTables">The fast AC decoding tables.</param>
/// <returns>The <see cref="int"/></returns> public void ParseEntropyCodedData(
public int ParseEntropyCodedData(
PdfJsFrame frame, PdfJsFrame frame,
PdfJsHuffmanTables dcHuffmanTables, PdfJsHuffmanTables dcHuffmanTables,
PdfJsHuffmanTables acHuffmanTables, PdfJsHuffmanTables acHuffmanTables,
@ -95,256 +94,272 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (!frame.Progressive) 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<Block8x8, short>(component.SpectralBlocks.Span));
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
ReadOnlySpan<short> fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId);
int mcu = 0;
for (int j = 0; j < h; j++)
{ {
PdfJsFrameComponent component = this.components[this.componentIndex]; for (int i = 0; i < w; i++)
// 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<Block8x8, short>(component.SpectralBlocks.Span));
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
ReadOnlySpan<short> fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId);
int mcu = 0;
for (int j = 0; j < h; j++)
{ {
for (int i = 0; i < w; i++) if (this.eof)
{ {
if (this.eof) return;
{ }
continue;
}
int blockRow = mcu / w; int blockRow = mcu / w;
int blockCol = mcu % w; int blockCol = mcu % w;
int offset = component.GetBlockBufferOffset(blockRow, blockCol); int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeBlock(component, ref Unsafe.Add(ref blockDataRef, offset), ref dcHuffmanTable, ref acHuffmanTable, fastAC); this.DecodeBlock(component, ref Unsafe.Add(ref blockDataRef, offset), ref dcHuffmanTable, ref acHuffmanTable, fastAC);
mcu++; mcu++;
// Every data block is an MCU, so countdown the restart interval // Every data block is an MCU, so countdown the restart interval
if (--this.todo <= 0) if (--this.todo <= 0)
{
if (this.codeBits < 24)
{ {
if (this.codeBits < 24) this.GrowBufferUnsafe();
{ }
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.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 for (int i = 0; i < mcusPerLine; i++)
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++) // Scan an interleaved mcu... process components in order
for (int k = 0; k < this.componentsLength; k++)
{ {
// Scan an interleaved mcu... process components in order PdfJsFrameComponent component = this.components[k];
for (int k = 0; k < this.componentsLength; k++) ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.Span));
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
ReadOnlySpan<short> 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]; for (int x = 0; x < h; x++)
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.Span));
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
ReadOnlySpan<short> 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++) if (this.eof)
{ {
if (this.eof) return;
{
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);
} }
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, // After all interleaved components, that's an interleaved MCU,
// so now count down the restart interval // so now count down the restart interval
mcu++; mcu++;
if (--this.todo <= 0) if (--this.todo <= 0)
{
if (this.codeBits < 24)
{ {
if (this.codeBits < 24) this.GrowBufferUnsafe();
{ }
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.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<Block8x8, short>(component.SpectralBlocks.Span));
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
ReadOnlySpan<short> fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId);
int mcu = 0;
for (int j = 0; j < h; j++)
{ {
PdfJsFrameComponent component = this.components[this.componentIndex]; for (int i = 0; i < w; i++)
// 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<Block8x8, short>(component.SpectralBlocks.Span));
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
ReadOnlySpan<short> fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId);
int mcu = 0;
for (int j = 0; j < h; j++)
{ {
for (int i = 0; i < w; i++) if (this.eof)
{ {
if (this.eof) return;
{ }
continue;
}
int blockRow = mcu / w; int blockRow = mcu / w;
int blockCol = mcu % w; int blockCol = mcu % w;
int offset = component.GetBlockBufferOffset(blockRow, blockCol); int offset = component.GetBlockBufferOffset(blockRow, blockCol);
if (this.spectralStart == 0) if (this.spectralStart == 0)
{ {
this.DecodeBlockProgressiveDC(component, ref Unsafe.Add(ref blockDataRef, offset), ref dcHuffmanTable); this.DecodeBlockProgressiveDC(component, ref Unsafe.Add(ref blockDataRef, offset), ref dcHuffmanTable);
} }
else else
{ {
this.DecodeBlockProgressiveAC(ref Unsafe.Add(ref blockDataRef, offset), ref acHuffmanTable, fastAC); this.DecodeBlockProgressiveAC(ref Unsafe.Add(ref blockDataRef, offset), ref acHuffmanTable, fastAC);
} }
mcu++; mcu++;
// Every data block is an MCU, so countdown the restart interval // Every data block is an MCU, so countdown the restart interval
if (--this.todo <= 0) if (--this.todo <= 0)
{
if (this.codeBits < 24)
{ {
if (this.codeBits < 24) this.GrowBufferUnsafe();
{ }
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.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 for (int i = 0; i < mcusPerLine; i++)
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++) // Scan an interleaved mcu... process components in order
for (int k = 0; k < this.componentsLength; k++)
{ {
// Scan an interleaved mcu... process components in order PdfJsFrameComponent component = this.components[k];
for (int k = 0; k < this.componentsLength; k++) ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.Span));
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
ReadOnlySpan<short> 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]; for (int x = 0; x < h; x++)
ref short blockDataRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<Block8x8, short>(component.SpectralBlocks.Span));
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
ReadOnlySpan<short> 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++) if (this.eof)
{ {
if (this.eof) return;
{
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);
} }
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, // After all interleaved components, that's an interleaved MCU,
// so now count down the restart interval // so now count down the restart interval
mcu++; mcu++;
if (--this.todo <= 0) if (--this.todo <= 0)
{
if (this.codeBits < 24)
{ {
if (this.codeBits < 24) this.GrowBufferUnsafe();
{ }
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.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( private int DecodeBlock(
@ -696,7 +711,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{ {
do do
{ {
// TODO: EOF
int b = this.nomore ? 0 : this.stream.ReadByte(); int b = this.nomore ? 0 : this.stream.ReadByte();
if (b == -1) if (b == -1)
@ -725,7 +739,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{ {
this.marker = (byte)c; this.marker = (byte)c;
this.nomore = true; this.nomore = true;
if (!this.IsRestartMarker(this.marker)) if (!this.HasRestart())
{ {
this.badMarker = true; this.badMarker = true;
} }
@ -831,21 +845,27 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private int PeekBits() private int PeekBits() => (int)((this.codeBuffer >> (32 - FastBits)) & ((1 << FastBits) - 1));
{
return (int)((this.codeBuffer >> (32 - FastBits)) & ((1 << FastBits) - 1));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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)] [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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

Loading…
Cancel
Save