Browse Source

Implement libjpeg LUT and add TODO notes for fast Huffman.

af/merge-core
James Jackson-South 8 years ago
parent
commit
792b93686a
  1. 41
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs
  2. 49
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs

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

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
@ -51,7 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
GenerateSizeTable(lengths, ref huffsizeRef); GenerateSizeTable(lengths, ref huffsizeRef);
GenerateCodeTable(ref huffsizeRef, ref huffcodeRef, length); GenerateCodeTable(ref huffsizeRef, ref huffcodeRef, length);
this.GenerateDecoderTables(lengths, ref huffcodeRef); this.GenerateDecoderTables(lengths, ref huffcodeRef);
this.GenerateLookaheadTables(lengths, values); this.GenerateLookaheadTables(lengths, values, ref huffcodeRef);
} }
fixed (byte* huffValRef = this.HuffVal.Data) fixed (byte* huffValRef = this.HuffVal.Data)
@ -145,33 +146,33 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// </summary> /// </summary>
/// <param name="lengths">The code lengths</param> /// <param name="lengths">The code lengths</param>
/// <param name="huffval">The huffman value array</param> /// <param name="huffval">The huffman value array</param>
private void GenerateLookaheadTables(byte[] lengths, byte[] huffval) /// <param name="huffcodeRef">The huffman code span ref</param>
private void GenerateLookaheadTables(byte[] lengths, byte[] huffval, ref short huffcodeRef)
{ {
// TODO: This generation code matches the libJpeg code but the lookahead table is not actually used yet.
// To use it we need to implement fast lookup path in PdfJsScanDecoder.DecodeHuffman
// This should yield much faster scan decoding as usually, more than 95% of the Huffman codes
// will be 8 or fewer bits long and can be handled without looping.
fixed (short* lookaheadRef = this.Lookahead.Data) fixed (short* lookaheadRef = this.Lookahead.Data)
{ {
int x = 0, code = 0; for (int i = 0; i < 256; i++)
for (int i = 0; i < 8; i++)
{ {
code <<= 1; lookaheadRef[i] = 2034; // 9 << 8;
}
for (int j = 0; j < lengths[i + 1]; j++) int p = 0;
for (int l = 1; l <= 8; l++)
{
for (int i = 1; i <= lengths[l]; i++, p++)
{ {
// The codeLength is 1+i, so shift code by 8-(1+i) to // l = current code's length, p = its index in huffcode[] & huffval[].
// calculate the high bits for every 8-bit sequence // Generate left-justified code followed by all possible bit sequences
// whose codeLength's high bits matches code. int lookBits = Unsafe.Add(ref huffcodeRef, p) << (8 - l);
// The high 8 bits of lutValue are the encoded value. for (int ctr = 1 << (8 - l); ctr > 0; ctr--)
// 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; lookaheadRef[lookBits] = (short)((l << 8) | huffval[p]);
lookBits++;
} }
code++;
x++;
} }
} }
} }

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

@ -25,12 +25,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
private int bitsCount; private int bitsCount;
#pragma warning disable 414
private int bitsUnRead;
private int accumulator;
#pragma warning restore 414
private int specStart; private int specStart;
private int specEnd; private int specEnd;
@ -128,8 +122,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
// Find marker // Find marker
this.bitsCount = 0; this.bitsCount = 0;
this.accumulator = 0;
this.bitsUnRead = 0;
fileMarker = PdfJsJpegDecoderCore.FindNextFileMarker(this.markerBuffer, stream); fileMarker = PdfJsJpegDecoderCore.FindNextFileMarker(this.markerBuffer, stream);
// Some bad images seem to pad Scan blocks with e.g. zero bytes, skip past // Some bad images seem to pad Scan blocks with e.g. zero bytes, skip past
@ -481,44 +473,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private short DecodeHuffman(ref PdfJsHuffmanTable tree, Stream stream) private short DecodeHuffman(ref PdfJsHuffmanTable tree, Stream stream)
{ {
short code = -1; // TODO: Implement fast Huffman decoding.
// TODO: Adding this code introduces error into the decoder.
// NOTES # During investigation of the libjpeg implementation it appears that they pull 32bits at a time and operate on those bits // NOTES # During investigation of the libjpeg implementation it appears that they pull 32bits at a time and operate on those bits
// using 3 methods: FillBits, PeekBits, and ReadBits. We should attempt to do the same. // using 3 methods: FillBits, PeekBits, and ReadBits. We should attempt to do the same.
// It doesn't appear to speed anything up either. short code = (short)this.ReadBit(stream);
// if (this.bitsUnRead < 8) if (this.endOfStreamReached || this.unexpectedMarkerReached)
// {
// if (this.bitsCount <= 0)
// {
// code = (short)this.ReadBit(stream);
// if (this.endOfStreamReached || this.unexpectedMarkerReached)
// {
// return -1;
// }
//
// this.bitsUnRead += 8;
// }
//
// this.accumulator = (this.accumulator << 8) | this.bitsData;
// int lutIndex = (this.accumulator >> (8 - this.bitsUnRead)) & 0xFF;
// int v = tree.Lookahead[lutIndex];
// if (v != 0)
// {
// int nb = (v & 0xFF) - 1;
// this.bitsCount -= nb - 1;
// this.bitsUnRead -= nb;
// v = v >> 8;
// return (short)v;
// }
// }
if (code == -1)
{ {
code = (short)this.ReadBit(stream); return -1;
if (this.endOfStreamReached || this.unexpectedMarkerReached)
{
return -1;
}
} }
// "DECODE", section F.2.2.3, figure F.16, page 109 of T.81 // "DECODE", section F.2.2.3, figure F.16, page 109 of T.81

Loading…
Cancel
Save