mirror of https://github.com/SixLabors/ImageSharp
8 changed files with 798 additions and 40 deletions
@ -0,0 +1,34 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using SixLabors.ImageSharp.Memory; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The collection of tables used for fast AC entropy scan decoding.
|
||||
|
/// </summary>
|
||||
|
internal sealed class FastACTables : IDisposable |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="FastACTables"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="memoryManager">The memory manager used to allocate memory for image processing operations.</param>
|
||||
|
public FastACTables(MemoryManager memoryManager) |
||||
|
{ |
||||
|
this.Tables = memoryManager.AllocateClean2D<short>(512, 4); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the collection of tables.
|
||||
|
/// </summary>
|
||||
|
public Buffer2D<short> Tables { get; } |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
this.Tables?.Dispose(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 FixedInt16Buffer257 |
||||
|
{ |
||||
|
public fixed short Data[257]; |
||||
|
|
||||
|
public short this[int idx] |
||||
|
{ |
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
get |
||||
|
{ |
||||
|
ref short self = ref Unsafe.As<FixedInt16Buffer257, short>(ref this); |
||||
|
return Unsafe.Add(ref self, idx); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,628 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
using SixLabors.ImageSharp.Formats.Jpeg.Common; |
||||
|
using SixLabors.ImageSharp.Memory; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components |
||||
|
{ |
||||
|
internal class ScanDecoder |
||||
|
{ |
||||
|
public const int FastBits = 9; |
||||
|
|
||||
|
// bmask[n] = (1 << n) - 1
|
||||
|
private static readonly uint[] stbi__bmask = { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535 }; |
||||
|
|
||||
|
// bias[n] = (-1 << n) + 1
|
||||
|
private static readonly int[] stbi__jbias = { 0, -1, -3, -7, -15, -31, -63, -127, -255, -511, -1023, -2047, -4095, -8191, -16383, -32767 }; |
||||
|
|
||||
|
private readonly DoubleBufferedStreamReader stream; |
||||
|
private readonly PdfJsFrameComponent[] components; |
||||
|
private readonly ZigZag dctZigZag; |
||||
|
private int codeBits; |
||||
|
private uint codeBuffer; |
||||
|
private bool nomore; |
||||
|
private byte marker; |
||||
|
|
||||
|
private int todo; |
||||
|
private int restartInterval; |
||||
|
private int componentIndex; |
||||
|
private int componentsLength; |
||||
|
private int eobrun; |
||||
|
private int spectralStart; |
||||
|
private int spectralEnd; |
||||
|
private int successiveHigh; |
||||
|
private int successiveLow; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="ScanDecoder"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="stream">The input stream</param>
|
||||
|
/// <param name="components">The scan components</param>
|
||||
|
/// <param name="componentIndex">The component index within the array</param>
|
||||
|
/// <param name="componentsLength">The length of the components. Different to the array length</param>
|
||||
|
/// <param name="restartInterval">The reset interval</param>
|
||||
|
/// <param name="spectralStart">The spectral selection start</param>
|
||||
|
/// <param name="spectralEnd">The spectral selection end</param>
|
||||
|
/// <param name="successiveHigh">The successive approximation bit high end</param>
|
||||
|
/// <param name="successiveLow">The successive approximation bit low end</param>
|
||||
|
public ScanDecoder( |
||||
|
DoubleBufferedStreamReader stream, |
||||
|
PdfJsFrameComponent[] components, |
||||
|
int componentIndex, |
||||
|
int componentsLength, |
||||
|
int restartInterval, |
||||
|
int spectralStart, |
||||
|
int spectralEnd, |
||||
|
int successiveHigh, |
||||
|
int successiveLow) |
||||
|
{ |
||||
|
this.dctZigZag = ZigZag.CreateUnzigTable(); |
||||
|
this.stream = stream; |
||||
|
this.components = components; |
||||
|
this.marker = PdfJsJpegConstants.Markers.Prefix; |
||||
|
this.componentIndex = componentIndex; |
||||
|
this.componentsLength = componentsLength; |
||||
|
this.restartInterval = restartInterval; |
||||
|
this.spectralStart = spectralStart; |
||||
|
this.spectralEnd = spectralEnd; |
||||
|
this.successiveHigh = successiveHigh; |
||||
|
this.successiveLow = successiveLow; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Decodes the entropy coded data.
|
||||
|
/// </summary>
|
||||
|
/// <param name="frame">The image frame.</param>
|
||||
|
/// <param name="dcHuffmanTables">The DC Huffman tables.</param>
|
||||
|
/// <param name="acHuffmanTables">The AC Huffman tables.</param>
|
||||
|
/// <param name="fastACTables">The fast AC decoding tables.</param>
|
||||
|
/// <returns>The <see cref="int"/></returns>
|
||||
|
public int ParseEntropyCodedData( |
||||
|
PdfJsFrame frame, |
||||
|
PdfJsHuffmanTables dcHuffmanTables, |
||||
|
PdfJsHuffmanTables acHuffmanTables, |
||||
|
FastACTables fastACTables) |
||||
|
{ |
||||
|
this.Reset(); |
||||
|
|
||||
|
if (!frame.Progressive) |
||||
|
{ |
||||
|
if (this.componentsLength == 1) |
||||
|
{ |
||||
|
int i, j; |
||||
|
int n = this.componentIndex; |
||||
|
PdfJsFrameComponent component = this.components[n]; |
||||
|
|
||||
|
// 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]; |
||||
|
Span<short> fastAC = fastACTables.Tables.GetRowSpan(component.ACHuffmanTableId); |
||||
|
|
||||
|
int mcu = 0; |
||||
|
for (j = 0; j < h; j++) |
||||
|
{ |
||||
|
for (i = 0; i < w; i++) |
||||
|
{ |
||||
|
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++; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
private int DecodeBlock( |
||||
|
PdfJsFrameComponent component, |
||||
|
ref short blockDataRef, |
||||
|
ref PdfJsHuffmanTable dcTable, |
||||
|
ref PdfJsHuffmanTable acTable, |
||||
|
Span<short> fac) |
||||
|
{ |
||||
|
if (this.codeBits < 16) |
||||
|
{ |
||||
|
this.GrowBufferUnsafe(); |
||||
|
} |
||||
|
|
||||
|
int t = this.DecodeHuffman(ref dcTable); |
||||
|
|
||||
|
if (t < 0) |
||||
|
{ |
||||
|
throw new ImageFormatException("Bad Huffman code"); |
||||
|
} |
||||
|
|
||||
|
int diff = t > 0 ? this.ExtendReceive(t) : 0; |
||||
|
int dc = component.DcPredictor + diff; |
||||
|
component.DcPredictor = dc; |
||||
|
blockDataRef = (short)dc; |
||||
|
|
||||
|
// Decode AC Components, See Jpeg Spec
|
||||
|
int k = 1; |
||||
|
do |
||||
|
{ |
||||
|
int zig; |
||||
|
int s; |
||||
|
|
||||
|
this.CheckBits(); |
||||
|
int c = this.PeekBits(); |
||||
|
int r = fac[c]; |
||||
|
|
||||
|
if (r > 0) |
||||
|
{ |
||||
|
// Fast AC path
|
||||
|
k += (r >> 4) & 15; // Run
|
||||
|
s = r & 15; // Combined Length
|
||||
|
this.codeBuffer <<= s; |
||||
|
this.codeBits -= s; |
||||
|
|
||||
|
// Decode into unzigzag location
|
||||
|
zig = this.dctZigZag[k++]; |
||||
|
Unsafe.Add(ref blockDataRef, zig) = (short)(r >> 8); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
int rs = this.DecodeHuffman(ref acTable); |
||||
|
|
||||
|
if (rs < 0) |
||||
|
{ |
||||
|
throw new ImageFormatException("Bad Huffman code"); |
||||
|
} |
||||
|
|
||||
|
s = rs & 15; |
||||
|
r = rs >> 4; |
||||
|
|
||||
|
if (s == 0) |
||||
|
{ |
||||
|
if (rs != 0xF0) |
||||
|
{ |
||||
|
break; // End block
|
||||
|
} |
||||
|
|
||||
|
k += 16; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
k += r; |
||||
|
|
||||
|
// Decode into unzigzag location
|
||||
|
zig = this.dctZigZag[k++]; |
||||
|
Unsafe.Add(ref blockDataRef, zig) = (short)this.ExtendReceive(s); |
||||
|
} |
||||
|
} |
||||
|
} while (k < 64); |
||||
|
|
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
private int DecodeBlockProgressiveDC( |
||||
|
PdfJsFrameComponent component, |
||||
|
ref short blockDataRef, |
||||
|
ref PdfJsHuffmanTable dcTable) |
||||
|
{ |
||||
|
if (this.spectralEnd != 0) |
||||
|
{ |
||||
|
throw new ImageFormatException("Can't merge DC and AC."); |
||||
|
} |
||||
|
|
||||
|
this.CheckBits(); |
||||
|
|
||||
|
if (this.successiveHigh == 0) |
||||
|
{ |
||||
|
// First scan for DC coefficient, must be first
|
||||
|
int t = this.DecodeHuffman(ref dcTable); |
||||
|
int diff = t > 0 ? this.ExtendReceive(t) : 0; |
||||
|
|
||||
|
int dc = component.DcPredictor + diff; |
||||
|
component.DcPredictor = dc; |
||||
|
|
||||
|
blockDataRef = (short)(dc << this.successiveLow); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// Refinement scan for DC coefficient
|
||||
|
if (this.GetBit() > 0) |
||||
|
{ |
||||
|
blockDataRef += (short)(1 << this.successiveLow); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
private int DecodeBlockProgressiveAC( |
||||
|
PdfJsFrameComponent component, |
||||
|
ref short blockDataRef, |
||||
|
ref PdfJsHuffmanTable acTable, |
||||
|
Span<short> fac) |
||||
|
{ |
||||
|
int k; |
||||
|
|
||||
|
if (this.spectralStart == 0) |
||||
|
{ |
||||
|
throw new ImageFormatException("Can't merge DC and AC."); |
||||
|
} |
||||
|
|
||||
|
if (this.successiveHigh == 0) |
||||
|
{ |
||||
|
int shift = this.successiveLow; |
||||
|
|
||||
|
if (this.eobrun > 0) |
||||
|
{ |
||||
|
this.eobrun--; |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
k = this.spectralStart; |
||||
|
do |
||||
|
{ |
||||
|
int zig; |
||||
|
int s; |
||||
|
|
||||
|
this.CheckBits(); |
||||
|
int c = this.PeekBits(); |
||||
|
int r = fac[c]; |
||||
|
|
||||
|
if (r > 0) |
||||
|
{ |
||||
|
// Fast AC path
|
||||
|
k += (r >> 4) & 15; // Run
|
||||
|
s = r & 15; // Combined length
|
||||
|
this.codeBuffer <<= s; |
||||
|
this.codeBits -= s; |
||||
|
|
||||
|
// Decode into unzigzag location
|
||||
|
zig = this.dctZigZag[k++]; |
||||
|
Unsafe.Add(ref blockDataRef, zig) = (short)((r >> 8) << shift); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
int rs = this.DecodeHuffman(ref acTable); |
||||
|
|
||||
|
if (rs < 0) |
||||
|
{ |
||||
|
throw new ImageFormatException("Bad Huffman code."); |
||||
|
} |
||||
|
|
||||
|
s = rs & 15; |
||||
|
r = rs >> 4; |
||||
|
|
||||
|
if (s == 0) |
||||
|
{ |
||||
|
if (r < 15) |
||||
|
{ |
||||
|
this.eobrun = 1 << r; |
||||
|
if (r > 0) |
||||
|
{ |
||||
|
this.eobrun += this.GetBits(r); |
||||
|
} |
||||
|
|
||||
|
this.eobrun--; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
k += 16; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
k += r; |
||||
|
zig = this.dctZigZag[k++]; |
||||
|
Unsafe.Add(ref blockDataRef, zig) = (short)(this.ExtendReceive(s) << shift); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
while (k <= this.spectralEnd); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// 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++) |
||||
|
{ |
||||
|
ref short p = ref Unsafe.Add(ref blockDataRef, this.dctZigZag[k]); |
||||
|
if (p != 0) |
||||
|
{ |
||||
|
if (this.GetBit() > 0) |
||||
|
{ |
||||
|
if ((p & bit) == 0) |
||||
|
{ |
||||
|
if (p > 0) |
||||
|
{ |
||||
|
p += bit; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
p -= bit; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
k = this.spectralStart; |
||||
|
do |
||||
|
{ |
||||
|
int rs = this.DecodeHuffman(ref acTable); |
||||
|
if (rs < 0) |
||||
|
{ |
||||
|
throw new ImageFormatException("Bad Huffman code."); |
||||
|
} |
||||
|
|
||||
|
int s = rs & 15; |
||||
|
int r = rs >> 4; |
||||
|
|
||||
|
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) |
||||
|
{ |
||||
|
this.eobrun = (1 << r) - 1; |
||||
|
|
||||
|
if (r > 0) |
||||
|
{ |
||||
|
this.eobrun += this.GetBits(r); |
||||
|
} |
||||
|
|
||||
|
r = 64; // Force end of block
|
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (s != 1) |
||||
|
{ |
||||
|
throw new ImageFormatException("Bad Huffman code."); |
||||
|
} |
||||
|
|
||||
|
// Sign bit
|
||||
|
if (this.GetBit() > 0) |
||||
|
{ |
||||
|
s = bit; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
s -= bit; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Advance by r
|
||||
|
while (k <= this.spectralEnd) |
||||
|
{ |
||||
|
ref short p = ref Unsafe.Add(ref blockDataRef, this.dctZigZag[k++]); |
||||
|
if (p != 0) |
||||
|
{ |
||||
|
if (this.GetBit() > 0) |
||||
|
{ |
||||
|
if ((p & bit) == 0) |
||||
|
{ |
||||
|
if (p > 0) |
||||
|
{ |
||||
|
p += bit; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
p -= bit; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (r == 0) |
||||
|
{ |
||||
|
p = (short)s; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
r--; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
while (k <= this.spectralEnd); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
private int GetBits(int n) |
||||
|
{ |
||||
|
if (this.codeBits < n) |
||||
|
{ |
||||
|
this.GrowBufferUnsafe(); |
||||
|
} |
||||
|
|
||||
|
uint k = this.Lrot(this.codeBuffer, n); |
||||
|
this.codeBuffer = k & ~stbi__bmask[n]; |
||||
|
k &= stbi__bmask[n]; |
||||
|
this.codeBits -= n; |
||||
|
return (int)k; |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
private int GetBit() |
||||
|
{ |
||||
|
if (this.codeBits < 1) |
||||
|
{ |
||||
|
this.GrowBufferUnsafe(); |
||||
|
} |
||||
|
|
||||
|
uint k = this.codeBuffer; |
||||
|
this.codeBuffer <<= 1; |
||||
|
this.codeBits--; |
||||
|
|
||||
|
return (int)(k & 0x80000000); |
||||
|
} |
||||
|
|
||||
|
private void GrowBufferUnsafe() |
||||
|
{ |
||||
|
do |
||||
|
{ |
||||
|
// TODO: EOF
|
||||
|
uint b = (uint)(this.nomore ? 0 : this.stream.ReadByte()); |
||||
|
if (b == PdfJsJpegConstants.Markers.Prefix) |
||||
|
{ |
||||
|
long position = this.stream.Position - 1; |
||||
|
int c = this.stream.ReadByte(); |
||||
|
while (c == PdfJsJpegConstants.Markers.Prefix) |
||||
|
{ |
||||
|
if (c != 0) |
||||
|
{ |
||||
|
this.marker = (byte)c; |
||||
|
this.nomore = true; |
||||
|
this.stream.Position = position; |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
this.codeBuffer |= b << (24 - this.codeBits); |
||||
|
this.codeBits += 8; |
||||
|
} |
||||
|
while (this.codeBits <= 24); |
||||
|
} |
||||
|
|
||||
|
private int DecodeHuffman(ref PdfJsHuffmanTable table) |
||||
|
{ |
||||
|
this.CheckBits(); |
||||
|
|
||||
|
// Look at the top FastBits and determine what symbol ID it is,
|
||||
|
// if the code is <= FastBits.
|
||||
|
int c = this.PeekBits(); |
||||
|
int k = table.Lookahead[c]; |
||||
|
if (k < byte.MaxValue) |
||||
|
{ |
||||
|
int s = table.Sizes[k]; |
||||
|
if (s > this.codeBits) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
this.codeBuffer <<= s; |
||||
|
this.codeBits -= s; |
||||
|
return table.Values[k]; |
||||
|
} |
||||
|
|
||||
|
// Naive test is to shift the code_buffer down so k bits are
|
||||
|
// valid, then test against MaxCode. To speed this up, we've
|
||||
|
// preshifted maxcode left so that it has (16-k) 0s at the
|
||||
|
// end; in other words, regardless of the number of bits, it
|
||||
|
// wants to be compared against something shifted to have 16;
|
||||
|
// that way we don't need to shift inside the loop.
|
||||
|
uint temp = this.codeBuffer >> 16; |
||||
|
for (k = FastBits + 1; ; ++k) |
||||
|
{ |
||||
|
if (temp < table.MaxCode[k]) |
||||
|
{ |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (k == 17) |
||||
|
{ |
||||
|
// Error! code not found
|
||||
|
this.codeBits -= 16; |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
if (k > this.codeBits) |
||||
|
{ |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
// Convert the huffman code to the symbol id
|
||||
|
c = (int)((this.codeBuffer >> (32 - k)) & stbi__bmask[k]) + table.ValOffset[k]; |
||||
|
|
||||
|
// Convert the id to a symbol
|
||||
|
this.codeBits -= k; |
||||
|
this.codeBuffer <<= k; |
||||
|
return table.Values[c]; |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
private int ExtendReceive(int n) |
||||
|
{ |
||||
|
if (this.codeBits < n) |
||||
|
{ |
||||
|
this.GrowBufferUnsafe(); |
||||
|
} |
||||
|
|
||||
|
int sgn = (int)(this.codeBuffer >> 31); |
||||
|
uint k = this.Lrot(this.codeBuffer, n); |
||||
|
this.codeBuffer = k & ~stbi__bmask[n]; |
||||
|
k &= stbi__bmask[n]; |
||||
|
this.codeBits -= n; |
||||
|
return (int)(k + (stbi__jbias[n] & ~sgn)); |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
private void CheckBits() |
||||
|
{ |
||||
|
if (this.codeBuffer < 16) |
||||
|
{ |
||||
|
this.GrowBufferUnsafe(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
private int PeekBits() |
||||
|
{ |
||||
|
return (int)(this.codeBuffer >> ((32 - FastBits) & ((1 << FastBits) - 1))); |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
private uint Lrot(uint x, int y) |
||||
|
{ |
||||
|
return (x << y) | (x >> (32 - y)); |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
private bool IsRestartMarker(byte x) |
||||
|
{ |
||||
|
return x >= PdfJsJpegConstants.Markers.RST0 && x <= PdfJsJpegConstants.Markers.RST7; |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
private void Reset() |
||||
|
{ |
||||
|
this.codeBits = 0; |
||||
|
this.codeBuffer = 0; |
||||
|
this.nomore = false; |
||||
|
|
||||
|
for (int i = 0; i < this.components.Length; i++) |
||||
|
{ |
||||
|
PdfJsFrameComponent c = this.components[i]; |
||||
|
c.DcPredictor = 0; |
||||
|
} |
||||
|
|
||||
|
this.marker = PdfJsJpegConstants.Markers.Prefix; |
||||
|
this.todo = this.restartInterval > 0 ? this.restartInterval : 0x7FFFFFFF; |
||||
|
this.eobrun = 0; |
||||
|
|
||||
|
// No more than 1<<31 MCUs if no restartInterval? that's plenty safe,
|
||||
|
// since we don't even allow 1<<30 pixels
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue