Browse Source

Faster scan decoder

pull/525/head
James Jackson-South 8 years ago
parent
commit
28facaf98d
  1. 24
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/FixedByteBuffer256.cs
  2. 24
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/FixedInt16Buffer18.cs
  3. 24
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/FixedInt16Buffer256.cs
  4. 24
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/FixedInt64Buffer18.cs
  5. 176
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs
  6. 14
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTables.cs
  7. 132
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs
  8. 14
      src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs

24
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/FixedByteBuffer256.cs

@ -0,0 +1,24 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct FixedByteBuffer256
{
public fixed byte Data[256];
public byte this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ref byte self = ref Unsafe.As<FixedByteBuffer256, byte>(ref this);
return Unsafe.Add(ref self, idx);
}
}
}
}

24
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/FixedInt16Buffer18.cs

@ -0,0 +1,24 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct FixedInt16Buffer18
{
public fixed short Data[18];
public short this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ref short self = ref Unsafe.As<FixedInt16Buffer18, short>(ref this);
return Unsafe.Add(ref self, idx);
}
}
}
}

24
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/FixedInt16Buffer256.cs

@ -0,0 +1,24 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct FixedInt16Buffer256
{
public fixed short Data[256];
public short this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ref short self = ref Unsafe.As<FixedInt16Buffer256, short>(ref this);
return Unsafe.Add(ref self, idx);
}
}
}
}

24
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/FixedInt64Buffer18.cs

@ -0,0 +1,24 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct FixedInt64Buffer18
{
public fixed long Data[18];
public long this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ref long self = ref Unsafe.As<FixedInt64Buffer18, long>(ref this);
return Unsafe.Add(ref self, idx);
}
}
}
}

176
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
@ -10,92 +9,52 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// <summary>
/// Represents a Huffman Table
/// </summary>
internal struct PdfJsHuffmanTable : IDisposable
internal unsafe struct PdfJsHuffmanTable
{
private BasicArrayBuffer<short> lookahead;
private BasicArrayBuffer<short> valOffset;
private BasicArrayBuffer<long> maxcode;
private IManagedByteBuffer huffval;
/// <summary>
/// Initializes a new instance of the <see cref="PdfJsHuffmanTable"/> struct.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="lengths">The code lengths</param>
/// <param name="values">The huffman values</param>
public PdfJsHuffmanTable(MemoryManager memoryManager, byte[] lengths, byte[] values)
{
// TODO: Replace FakeBuffer<T> usages with standard or array orfixed-sized arrays
this.lookahead = memoryManager.AllocateFake<short>(256);
this.valOffset = memoryManager.AllocateFake<short>(18);
this.maxcode = memoryManager.AllocateFake<long>(18);
using (IBuffer<short> huffsize = memoryManager.Allocate<short>(257))
using (IBuffer<short> huffcode = memoryManager.Allocate<short>(257))
{
GenerateSizeTable(lengths, huffsize.Span);
GenerateCodeTable(huffsize.Span, huffcode.Span);
GenerateDecoderTables(lengths, huffcode.Span, this.valOffset.Span, this.maxcode.Span);
GenerateLookaheadTables(lengths, values, this.lookahead.Span);
}
this.huffval = memoryManager.AllocateManagedByteBuffer(values.Length, true);
Buffer.BlockCopy(values, 0, this.huffval.Array, 0, values.Length);
this.MaxCode = this.maxcode.Array;
this.ValOffset = this.valOffset.Array;
this.HuffVal = this.huffval.Array;
this.Lookahead = this.lookahead.Array;
}
/// <summary>
/// Gets the max code array
/// </summary>
public long[] MaxCode
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public FixedInt64Buffer18 MaxCode;
/// <summary>
/// Gets the value offset array
/// </summary>
public short[] ValOffset
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public FixedInt16Buffer18 ValOffset;
/// <summary>
/// Gets the huffman value array
/// </summary>
public byte[] HuffVal
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public FixedByteBuffer256 HuffVal;
/// <summary>
/// Gets the lookahead array
/// </summary>
public short[] Lookahead
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public FixedInt16Buffer256 Lookahead;
/// <inheritdoc/>
public void Dispose()
/// <summary>
/// Initializes a new instance of the <see cref="PdfJsHuffmanTable"/> struct.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="lengths">The code lengths</param>
/// <param name="values">The huffman values</param>
public PdfJsHuffmanTable(MemoryManager memoryManager, byte[] lengths, byte[] values)
{
this.lookahead?.Dispose();
this.valOffset?.Dispose();
this.maxcode?.Dispose();
this.huffval?.Dispose();
this.lookahead = null;
this.valOffset = null;
this.maxcode = null;
this.huffval = null;
using (IBuffer<short> huffsize = memoryManager.Allocate<short>(257))
using (IBuffer<short> huffcode = memoryManager.Allocate<short>(257))
{
GenerateSizeTable(lengths, huffsize.Span);
GenerateCodeTable(huffsize.Span, huffcode.Span);
this.GenerateDecoderTables(lengths, huffcode.Span);
this.GenerateLookaheadTables(lengths, values);
}
fixed (byte* huffValRef = this.HuffVal.Data)
{
for (int i = 0; i < values.Length; i++)
{
huffValRef[i] = values[i];
}
}
}
/// <summary>
@ -148,29 +107,30 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// </summary>
/// <param name="lengths">The code lengths</param>
/// <param name="huffcode">The huffman code span</param>
/// <param name="valOffset">The value offset span</param>
/// <param name="maxcode">The max code span</param>
private static void GenerateDecoderTables(byte[] lengths, Span<short> huffcode, Span<short> valOffset, Span<long> maxcode)
private void GenerateDecoderTables(byte[] lengths, Span<short> huffcode)
{
short bitcount = 0;
for (int i = 1; i <= 16; i++)
fixed (short* valOffsetRef = this.ValOffset.Data)
fixed (long* maxcodeRef = this.MaxCode.Data)
{
if (lengths[i] != 0)
{
// valoffset[l] = huffval[] index of 1st symbol of code length i,
// minus the minimum code of length i
valOffset[i] = (short)(bitcount - huffcode[bitcount]);
bitcount += lengths[i];
maxcode[i] = huffcode[bitcount - 1]; // maximum code of length i
}
else
short bitcount = 0;
for (int i = 1; i <= 16; i++)
{
maxcode[i] = -1; // -1 if no codes of this length
if (lengths[i] != 0)
{
// valOffsetRef[l] = huffval[] index of 1st symbol of code length i, minus the minimum code of length i
valOffsetRef[i] = (short)(bitcount - huffcode[bitcount]);
bitcount += lengths[i];
maxcodeRef[i] = huffcode[bitcount - 1]; // maximum code of length i
}
else
{
maxcodeRef[i] = -1; // -1 if no codes of this length
}
}
}
valOffset[17] = 0;
maxcode[17] = 0xFFFFFL;
valOffsetRef[17] = 0;
maxcodeRef[17] = 0xFFFFFL;
}
}
/// <summary>
@ -178,32 +138,34 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// </summary>
/// <param name="lengths">The code lengths</param>
/// <param name="huffval">The huffman value array</param>
/// <param name="lookahead">The lookahead span</param>
private static void GenerateLookaheadTables(byte[] lengths, byte[] huffval, Span<short> lookahead)
private void GenerateLookaheadTables(byte[] lengths, byte[] huffval)
{
int x = 0, code = 0;
for (int i = 0; i < 8; i++)
fixed (short* lookaheadRef = this.Lookahead.Data)
{
code <<= 1;
int x = 0, code = 0;
for (int j = 0; j < lengths[i + 1]; j++)
for (int i = 0; i < 8; i++)
{
// The codeLength is 1+i, so shift code by 8-(1+i) to
// calculate the high bits for every 8-bit sequence
// whose codeLength's high bits matches code.
// The high 8 bits of lutValue are the encoded value.
// The low 8 bits are 1 plus the codeLength.
byte base2 = (byte)(code << (7 - i));
short lutValue = (short)((short)(huffval[x] << 8) | (short)(2 + i));
for (int k = 0; k < 1 << (7 - i); k++)
code <<= 1;
for (int j = 0; j < lengths[i + 1]; j++)
{
lookahead[base2 | k] = lutValue;
// The codeLength is 1+i, so shift code by 8-(1+i) to
// calculate the high bits for every 8-bit sequence
// whose codeLength's high bits matches code.
// The high 8 bits of lutValue are the encoded value.
// The low 8 bits are 1 plus the codeLength.
byte base2 = (byte)(code << (7 - i));
short lutValue = (short)((short)(huffval[x] << 8) | (short)(2 + i));
for (int k = 0; k < 1 << (7 - i); k++)
{
lookaheadRef[base2 | k] = lutValue;
}
code++;
x++;
}
code++;
x++;
}
}
}

14
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTables.cs

@ -1,16 +1,15 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
/// <summary>
/// Defines a pair of huffman tables
/// Defines a 2 pairs of huffman tables
/// </summary>
internal sealed class PdfJsHuffmanTables : IDisposable
internal sealed class PdfJsHuffmanTables
{
private readonly PdfJsHuffmanTable[] tables = new PdfJsHuffmanTable[4];
@ -27,14 +26,5 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
return ref this.tables[index];
}
}
/// <inheritdoc/>
public void Dispose()
{
for (int i = 0; i < this.tables.Length; i++)
{
this.tables[i].Dispose();
}
}
}
}

132
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs

@ -5,6 +5,7 @@ using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
@ -172,7 +173,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
fileMarker = PdfJsJpegDecoderCore.FindNextFileMarker(this.markerBuffer, stream);
// Some images include more Scan blocks than expected, skip past those and
// attempt to find the next valid marker (fixes issue8182.pdf) in original code.
// attempt to find the next valid marker (fixes issue8182.pdf) ref original code.
if (fileMarker.Invalid)
{
#if DEBUG
@ -201,6 +202,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (componentsLength == 1)
{
PdfJsFrameComponent component = components[this.compIndex];
ref short blockDataRef = ref MemoryMarshal.GetReference(component.BlockData.Span);
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
@ -211,7 +213,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
continue;
}
this.DecodeBlockBaseline(ref dcHuffmanTable, ref acHuffmanTable, component, mcu, stream);
this.DecodeBlockBaseline(ref dcHuffmanTable, ref acHuffmanTable, component, ref blockDataRef, mcu, stream);
mcu++;
}
}
@ -222,6 +224,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
for (int i = 0; i < componentsLength; i++)
{
PdfJsFrameComponent component = components[i];
ref short blockDataRef = ref MemoryMarshal.GetReference(component.BlockData.Span);
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
int h = component.HorizontalSamplingFactor;
@ -236,7 +239,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
continue;
}
this.DecodeMcuBaseline(ref dcHuffmanTable, ref acHuffmanTable, component, mcusPerLine, mcu, j, k, stream);
this.DecodeMcuBaseline(ref dcHuffmanTable, ref acHuffmanTable, component, ref blockDataRef, mcusPerLine, mcu, j, k, stream);
}
}
}
@ -259,6 +262,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (componentsLength == 1)
{
PdfJsFrameComponent component = components[this.compIndex];
ref short blockDataRef = ref MemoryMarshal.GetReference(component.BlockData.Span);
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
for (int n = 0; n < mcuToRead; n++)
@ -268,7 +272,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
continue;
}
this.DecodeBlockDCFirst(ref dcHuffmanTable, component, mcu, stream);
this.DecodeBlockDCFirst(ref dcHuffmanTable, component, ref blockDataRef, mcu, stream);
mcu++;
}
}
@ -279,6 +283,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
for (int i = 0; i < componentsLength; i++)
{
PdfJsFrameComponent component = components[i];
ref short blockDataRef = ref MemoryMarshal.GetReference(component.BlockData.Span);
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;
@ -292,7 +297,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
continue;
}
this.DecodeMcuDCFirst(ref dcHuffmanTable, component, mcusPerLine, mcu, j, k, stream);
this.DecodeMcuDCFirst(ref dcHuffmanTable, component, ref blockDataRef, mcusPerLine, mcu, j, k, stream);
}
}
}
@ -314,6 +319,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (componentsLength == 1)
{
PdfJsFrameComponent component = components[this.compIndex];
ref short blockDataRef = ref MemoryMarshal.GetReference(component.BlockData.Span);
for (int n = 0; n < mcuToRead; n++)
{
if (this.endOfStreamReached || this.unexpectedMarkerReached)
@ -321,7 +328,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
continue;
}
this.DecodeBlockDCSuccessive(component, mcu, stream);
this.DecodeBlockDCSuccessive(component, ref blockDataRef, mcu, stream);
mcu++;
}
}
@ -334,6 +341,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
PdfJsFrameComponent component = components[i];
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;
ref short blockDataRef = ref MemoryMarshal.GetReference(component.BlockData.Span);
for (int j = 0; j < v; j++)
{
for (int k = 0; k < h; k++)
@ -343,7 +352,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
continue;
}
this.DecodeMcuDCSuccessive(component, mcusPerLine, mcu, j, k, stream);
this.DecodeMcuDCSuccessive(component, ref blockDataRef, mcusPerLine, mcu, j, k, stream);
}
}
}
@ -366,6 +375,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (componentsLength == 1)
{
PdfJsFrameComponent component = components[this.compIndex];
ref short blockDataRef = ref MemoryMarshal.GetReference(component.BlockData.Span);
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
for (int n = 0; n < mcuToRead; n++)
@ -375,7 +385,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
continue;
}
this.DecodeBlockACFirst(ref acHuffmanTable, component, mcu, stream);
this.DecodeBlockACFirst(ref acHuffmanTable, component, ref blockDataRef, mcu, stream);
mcu++;
}
}
@ -386,6 +396,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
for (int i = 0; i < componentsLength; i++)
{
PdfJsFrameComponent component = components[i];
ref short blockDataRef = ref MemoryMarshal.GetReference(component.BlockData.Span);
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;
@ -399,7 +410,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
continue;
}
this.DecodeMcuACFirst(ref acHuffmanTable, component, mcusPerLine, mcu, j, k, stream);
this.DecodeMcuACFirst(ref acHuffmanTable, component, ref blockDataRef, mcusPerLine, mcu, j, k, stream);
}
}
}
@ -422,6 +433,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (componentsLength == 1)
{
PdfJsFrameComponent component = components[this.compIndex];
ref short blockDataRef = ref MemoryMarshal.GetReference(component.BlockData.Span);
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
for (int n = 0; n < mcuToRead; n++)
@ -431,7 +443,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
continue;
}
this.DecodeBlockACSuccessive(ref acHuffmanTable, component, mcu, stream);
this.DecodeBlockACSuccessive(ref acHuffmanTable, component, ref blockDataRef, mcu, stream);
mcu++;
}
}
@ -442,6 +454,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
for (int i = 0; i < componentsLength; i++)
{
PdfJsFrameComponent component = components[i];
ref short blockDataRef = ref MemoryMarshal.GetReference(component.BlockData.Span);
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;
@ -455,7 +468,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
continue;
}
this.DecodeMcuACSuccessive(ref acHuffmanTable, component, mcusPerLine, mcu, j, k, stream);
this.DecodeMcuACSuccessive(ref acHuffmanTable, component, ref blockDataRef, mcusPerLine, mcu, j, k, stream);
}
}
}
@ -466,103 +479,103 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeBlockBaseline(ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, int mcu, Stream stream)
private void DecodeBlockBaseline(ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcu, Stream stream)
{
int blockRow = mcu / component.WidthInBlocks;
int blockCol = mcu % component.WidthInBlocks;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeBaseline(component, offset, ref dcHuffmanTable, ref acHuffmanTable, stream);
this.DecodeBaseline(component, ref blockDataRef, offset, ref dcHuffmanTable, ref acHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeMcuBaseline(ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, int mcusPerLine, int mcu, int row, int col, Stream stream)
private void DecodeMcuBaseline(ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcusPerLine, int mcu, int row, int col, Stream stream)
{
int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeBaseline(component, offset, ref dcHuffmanTable, ref acHuffmanTable, stream);
this.DecodeBaseline(component, ref blockDataRef, offset, ref dcHuffmanTable, ref acHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeBlockDCFirst(ref PdfJsHuffmanTable dcHuffmanTable, PdfJsFrameComponent component, int mcu, Stream stream)
private void DecodeBlockDCFirst(ref PdfJsHuffmanTable dcHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcu, Stream stream)
{
int blockRow = mcu / component.WidthInBlocks;
int blockCol = mcu % component.WidthInBlocks;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeDCFirst(component, offset, ref dcHuffmanTable, stream);
this.DecodeDCFirst(component, ref blockDataRef, offset, ref dcHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeMcuDCFirst(ref PdfJsHuffmanTable dcHuffmanTable, PdfJsFrameComponent component, int mcusPerLine, int mcu, int row, int col, Stream stream)
private void DecodeMcuDCFirst(ref PdfJsHuffmanTable dcHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcusPerLine, int mcu, int row, int col, Stream stream)
{
int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeDCFirst(component, offset, ref dcHuffmanTable, stream);
this.DecodeDCFirst(component, ref blockDataRef, offset, ref dcHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeBlockDCSuccessive(PdfJsFrameComponent component, int mcu, Stream stream)
private void DecodeBlockDCSuccessive(PdfJsFrameComponent component, ref short blockDataRef, int mcu, Stream stream)
{
int blockRow = mcu / component.WidthInBlocks;
int blockCol = mcu % component.WidthInBlocks;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeDCSuccessive(component, offset, stream);
this.DecodeDCSuccessive(component, ref blockDataRef, offset, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeMcuDCSuccessive(PdfJsFrameComponent component, int mcusPerLine, int mcu, int row, int col, Stream stream)
private void DecodeMcuDCSuccessive(PdfJsFrameComponent component, ref short blockDataRef, int mcusPerLine, int mcu, int row, int col, Stream stream)
{
int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeDCSuccessive(component, offset, stream);
this.DecodeDCSuccessive(component, ref blockDataRef, offset, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeBlockACFirst(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, int mcu, Stream stream)
private void DecodeBlockACFirst(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcu, Stream stream)
{
int blockRow = mcu / component.WidthInBlocks;
int blockCol = mcu % component.WidthInBlocks;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeACFirst(component, offset, ref acHuffmanTable, stream);
this.DecodeACFirst(component, ref blockDataRef, offset, ref acHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeMcuACFirst(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, int mcusPerLine, int mcu, int row, int col, Stream stream)
private void DecodeMcuACFirst(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcusPerLine, int mcu, int row, int col, Stream stream)
{
int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeACFirst(component, offset, ref acHuffmanTable, stream);
this.DecodeACFirst(component, ref blockDataRef, offset, ref acHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeBlockACSuccessive(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, int mcu, Stream stream)
private void DecodeBlockACSuccessive(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcu, Stream stream)
{
int blockRow = mcu / component.WidthInBlocks;
int blockCol = mcu % component.WidthInBlocks;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeACSuccessive(component, offset, ref acHuffmanTable, stream);
this.DecodeACSuccessive(component, ref blockDataRef, offset, ref acHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeMcuACSuccessive(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, int mcusPerLine, int mcu, int row, int col, Stream stream)
private void DecodeMcuACSuccessive(ref PdfJsHuffmanTable acHuffmanTable, PdfJsFrameComponent component, ref short blockDataRef, int mcusPerLine, int mcu, int row, int col, Stream stream)
{
int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeACSuccessive(component, offset, ref acHuffmanTable, stream);
this.DecodeACSuccessive(component, ref blockDataRef, offset, ref acHuffmanTable, stream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -579,7 +592,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
if (this.bitsData == -0x1)
{
// We've encountered the end of the file stream which means there's no EOI marker in the image
// We've encountered the end of the file stream which means there's no EOI marker ref the image
this.endOfStreamReached = true;
}
@ -705,23 +718,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeBaseline(PdfJsFrameComponent component, int offset, ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, Stream stream)
private void DecodeBaseline(PdfJsFrameComponent component, ref short blockDataRef, int offset, ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, Stream stream)
{
Span<short> blockDataSpan = component.BlockData.Span;
int t = this.DecodeHuffman(ref dcHuffmanTable, stream);
short t = this.DecodeHuffman(ref dcHuffmanTable, stream);
if (this.endOfStreamReached || this.unexpectedMarkerReached)
{
return;
}
int diff = t == 0 ? 0 : this.ReceiveAndExtend(t, stream);
blockDataSpan[offset] = (short)(component.Pred += diff);
Unsafe.Add(ref blockDataRef, offset) = (short)(component.Pred += diff);
int k = 1;
while (k < 64)
{
int rs = this.DecodeHuffman(ref acHuffmanTable, stream);
short rs = this.DecodeHuffman(ref acHuffmanTable, stream);
if (this.endOfStreamReached || this.unexpectedMarkerReached)
{
return;
@ -750,42 +761,38 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
byte z = PdfJsQuantizationTables.DctZigZag[k];
short re = (short)this.ReceiveAndExtend(s, stream);
blockDataSpan[offset + z] = re;
Unsafe.Add(ref blockDataRef, offset + z) = re;
k++;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeDCFirst(PdfJsFrameComponent component, int offset, ref PdfJsHuffmanTable dcHuffmanTable, Stream stream)
private void DecodeDCFirst(PdfJsFrameComponent component, ref short blockDataRef, int offset, ref PdfJsHuffmanTable dcHuffmanTable, Stream stream)
{
Span<short> blockDataSpan = component.BlockData.Span;
int t = this.DecodeHuffman(ref dcHuffmanTable, stream);
short t = this.DecodeHuffman(ref dcHuffmanTable, stream);
if (this.endOfStreamReached || this.unexpectedMarkerReached)
{
return;
}
int diff = t == 0 ? 0 : this.ReceiveAndExtend(t, stream) << this.successiveState;
blockDataSpan[offset] = (short)(component.Pred += diff);
Unsafe.Add(ref blockDataRef, offset) = (short)(component.Pred += diff);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeDCSuccessive(PdfJsFrameComponent component, int offset, Stream stream)
private void DecodeDCSuccessive(PdfJsFrameComponent component, ref short blockDataRef, int offset, Stream stream)
{
Span<short> blockDataSpan = component.BlockData.Span;
int bit = this.ReadBit(stream);
if (this.endOfStreamReached || this.unexpectedMarkerReached)
{
return;
}
blockDataSpan[offset] |= (short)(bit << this.successiveState);
Unsafe.Add(ref blockDataRef, offset) |= (short)(bit << this.successiveState);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeACFirst(PdfJsFrameComponent component, int offset, ref PdfJsHuffmanTable acHuffmanTable, Stream stream)
private void DecodeACFirst(PdfJsFrameComponent component, ref short blockDataRef, int offset, ref PdfJsHuffmanTable acHuffmanTable, Stream stream)
{
if (this.eobrun > 0)
{
@ -793,7 +800,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
return;
}
Span<short> componentBlockDataSpan = component.BlockData.Span;
int k = this.specStart;
int e = this.specEnd;
while (k <= e)
@ -820,19 +826,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
}
k += r;
byte z = PdfJsQuantizationTables.DctZigZag[k];
componentBlockDataSpan[offset + z] = (short)(this.ReceiveAndExtend(s, stream) * (1 << this.successiveState));
ref byte z = ref PdfJsQuantizationTables.DctZigZag[k];
Unsafe.Add(ref blockDataRef, offset + z) = (short)(this.ReceiveAndExtend(s, stream) * (1 << this.successiveState));
k++;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeACSuccessive(PdfJsFrameComponent component, int offset, ref PdfJsHuffmanTable acHuffmanTable, Stream stream)
private void DecodeACSuccessive(PdfJsFrameComponent component, ref short blockDataRef, int offset, ref PdfJsHuffmanTable acHuffmanTable, Stream stream)
{
int k = this.specStart;
int e = this.specEnd;
int r = 0;
Span<short> componentBlockDataSpan = component.BlockData.Span;
while (k <= e)
{
byte z = PdfJsQuantizationTables.DctZigZag[k];
@ -874,7 +881,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
continue;
case 1: // Skipping r zero items
case 2:
if (componentBlockDataSpan[offset + z] != 0)
ref short blockRef = ref Unsafe.Add(ref blockDataRef, offset + z);
if (blockRef != 0)
{
int bit = this.ReadBit(stream);
if (this.endOfStreamReached || this.unexpectedMarkerReached)
@ -882,7 +890,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
return;
}
componentBlockDataSpan[offset + z] += (short)(bit << this.successiveState);
blockRef += (short)(bit << this.successiveState);
}
else
{
@ -895,7 +903,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
break;
case 3: // Set value for a zero item
if (componentBlockDataSpan[offset + z] != 0)
ref short blockRef2 = ref Unsafe.Add(ref blockDataRef, offset + z);
if (blockRef2 != 0)
{
int bit = this.ReadBit(stream);
if (this.endOfStreamReached || this.unexpectedMarkerReached)
@ -903,17 +912,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
return;
}
componentBlockDataSpan[offset + z] += (short)(bit << this.successiveState);
blockRef2 += (short)(bit << this.successiveState);
}
else
{
componentBlockDataSpan[offset + z] = (short)(this.successiveACNextValue << this.successiveState);
blockRef2 = (short)(this.successiveACNextValue << this.successiveState);
this.successiveACState = 0;
}
break;
case 4: // Eob
if (componentBlockDataSpan[offset + z] != 0)
ref short blockRef3 = ref Unsafe.Add(ref blockDataRef, offset + z);
if (blockRef3 != 0)
{
int bit = this.ReadBit(stream);
if (this.endOfStreamReached || this.unexpectedMarkerReached)
@ -921,7 +931,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
return;
}
componentBlockDataSpan[offset + z] += (short)(bit << this.successiveState);
blockRef3 += (short)(bit << this.successiveState);
}
break;

14
src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers.Binary;
using System.IO;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
@ -123,7 +124,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
if (value == 0)
{
return new PdfJsFileMarker(PdfJsJpegConstants.Markers.EOI, (int)stream.Length - 2);
return new PdfJsFileMarker(PdfJsJpegConstants.Markers.EOI, stream.Length - 2);
}
if (marker[0] == PdfJsJpegConstants.Markers.Prefix)
@ -135,16 +136,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
int suffix = stream.ReadByte();
if (suffix == -1)
{
return new PdfJsFileMarker(PdfJsJpegConstants.Markers.EOI, (int)stream.Length - 2);
return new PdfJsFileMarker(PdfJsJpegConstants.Markers.EOI, stream.Length - 2);
}
marker[1] = (byte)suffix;
}
return new PdfJsFileMarker((ushort)((marker[0] << 8) | marker[1]), (int)(stream.Position - 2));
return new PdfJsFileMarker(BinaryPrimitives.ReadUInt16BigEndian(marker), stream.Position - 2);
}
return new PdfJsFileMarker((ushort)((marker[0] << 8) | marker[1]), (int)(stream.Position - 2), true);
return new PdfJsFileMarker(BinaryPrimitives.ReadUInt16BigEndian(marker), stream.Position - 2, true);
}
/// <summary>
@ -172,8 +173,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
this.Frame?.Dispose();
this.components?.Dispose();
this.quantizationTables?.Dispose();
this.dcHuffmanTables?.Dispose();
this.acHuffmanTables?.Dispose();
this.pixelArea.Dispose();
// Set large fields to null.
@ -827,6 +826,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// <param name="index">The table index</param>
/// <param name="codeLengths">The codelengths</param>
/// <param name="values">The values</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void BuildHuffmanTable(PdfJsHuffmanTables tables, int index, byte[] codeLengths, byte[] values)
{
tables[index] = new PdfJsHuffmanTable(this.configuration.MemoryManager, codeLengths, values);
@ -938,7 +938,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
private ushort ReadUint16()
{
this.InputStream.Read(this.markerBuffer, 0, 2);
return (ushort)((this.markerBuffer[0] << 8) | this.markerBuffer[1]);
return BinaryPrimitives.ReadUInt16BigEndian(this.markerBuffer);
}
}
}
Loading…
Cancel
Save