Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
285f8dd
Begin porting stb_image
JimBobSquarePants May 8, 2018
71903c5
Minor cleanup
JimBobSquarePants May 9, 2018
5516bfb
Merge branch 'master' into js/new-jpeg-scan-decoder
JimBobSquarePants May 9, 2018
c8a9b30
Wire up huffman tables. (doesn't work)
JimBobSquarePants May 9, 2018
6d928f6
Meh
JimBobSquarePants May 11, 2018
f064d95
Baseline decoding seems to work
JimBobSquarePants May 31, 2018
31d5fa4
Merge branch 'master' into js/new-jpeg-scan-decoder
JimBobSquarePants May 31, 2018
bdd3291
Update reference types
JimBobSquarePants May 31, 2018
f597321
Merge branch 'master' into js/new-jpeg-scan-decoder
JimBobSquarePants Jun 8, 2018
9e59ac1
6/10 baseline images now pass.
JimBobSquarePants Jun 30, 2018
5716dbe
Merge branch 'master' into js/new-jpeg-scan-decoder
JimBobSquarePants Jun 30, 2018
588e423
9/10 baseline now pass!
JimBobSquarePants Jun 30, 2018
681f99f
Can now decode baseline + progressive
JimBobSquarePants Jun 30, 2018
c69c3ac
Split decode method.
JimBobSquarePants Jul 1, 2018
1a79cfb
void methods
JimBobSquarePants Jul 1, 2018
f2e05bf
Minor perf changes.
JimBobSquarePants Jul 1, 2018
d8f4b25
Remove unused huffman table code.
JimBobSquarePants Jul 1, 2018
b5e2401
Delete unused code.
JimBobSquarePants Jul 1, 2018
cfe5b5c
Update reference images from master
JimBobSquarePants Jul 1, 2018
43c818f
Add descriptive comments, remove unused, and make method static.
JimBobSquarePants Jul 2, 2018
1e493ab
Split progressive AC method and rename GrowBufferUnsafe
JimBobSquarePants Jul 2, 2018
8370d4f
Fix updated struct name
JimBobSquarePants Jul 2, 2018
6360a8a
Update name reference
JimBobSquarePants Jul 2, 2018
fcabcdd
Refactor FastACTables and reduce trivial duplication.
JimBobSquarePants Jul 2, 2018
69f228b
private static ordering.
JimBobSquarePants Jul 2, 2018
9cb8c15
Rename struct
JimBobSquarePants Jul 2, 2018
bd79c84
Update Huffman table property
JimBobSquarePants Jul 2, 2018
d4fc8a0
Move method where it belongs.
JimBobSquarePants Jul 2, 2018
65a0504
add regression test for #624
antonfirsov Jul 2, 2018
c21e971
ParseStream -only benchmark
antonfirsov Jul 2, 2018
d04611e
Introduce InliningOptions
antonfirsov Jul 2, 2018
468797f
use JpegThrowHelper
antonfirsov Jul 2, 2018
b9a6804
separate Interleaved / Non-Interleaved code path
antonfirsov Jul 2, 2018
ff1a24c
simplify + uniformize blockDataRef retrieval
antonfirsov Jul 2, 2018
df557c9
ScanDecoder: refactor parameters to members
antonfirsov Jul 2, 2018
2277896
temporal vortex attacked again
antonfirsov Jul 2, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/ImageSharp/Common/Helpers/InliningOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

// Uncomment this for verbose profiler results:
// #define PROFILING
using System.Runtime.CompilerServices;

namespace SixLabors.ImageSharp
{
/// <summary>
/// Global inlining options. Helps temporarily disable inling for better profiler output.
/// </summary>
internal static class InliningOptions
{
#if PROFILING
public const MethodImplOptions ShortMethod = 0;
#else
public const MethodImplOptions ShortMethod = MethodImplOptions.AggressiveInlining;
#endif
public const MethodImplOptions ColdPath = MethodImplOptions.NoInlining;
}
}
26 changes: 26 additions & 0 deletions src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System.Runtime.CompilerServices;

namespace SixLabors.ImageSharp.Formats.Jpeg
{
internal static class JpegThrowHelper
{
/// <summary>
/// Cold path optimization for throwing <see cref="ImageFormatException"/>-s
/// </summary>
/// <param name="errorMessage">The error message for the exception</param>
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowImageFormatException(string errorMessage)
{
throw new ImageFormatException(errorMessage);
}

[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowBadHuffmanCode()
{
throw new ImageFormatException("Bad Huffman code.");
}
}
}
96 changes: 96 additions & 0 deletions src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/FastACTables.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Runtime.CompilerServices;
using SixLabors.Memory;

namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
/// <summary>
/// The collection of lookup tables used for fast AC entropy scan decoding.
/// </summary>
internal sealed class FastACTables : IDisposable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we really need this class in it's current form. Either we should hide the Table property and encapsulate actual logic (initialization, retrieval of rows) inside the class, or we should drop it and define a helper method that creates Buffer2d<short>.

Copy link
Member Author

@JimBobSquarePants JimBobSquarePants Jul 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like having a class but I think you're right about the tables property. I'll hide that away and introduce a GetTableSpan() method.

{
private Buffer2D<short> tables;

/// <summary>
/// Initializes a new instance of the <see cref="FastACTables"/> class.
/// </summary>
/// <param name="memoryAllocator">The memory allocator used to allocate memory for image processing operations.</param>
public FastACTables(MemoryAllocator memoryAllocator)
{
this.tables = memoryAllocator.AllocateClean2D<short>(512, 4);
}

/// <summary>
/// Gets the <see cref="Span{Int16}"/> representing the table at the index in the collection.
/// </summary>
/// <param name="index">The table index.</param>
/// <returns><see cref="Span{Int16}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<short> GetTableSpan(int index)
{
return this.tables.GetRowSpan(index);
}

/// <summary>
/// Gets a reference to the first element of the AC table indexed by <see cref="PdfJsFrameComponent.ACHuffmanTableId"/>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref short GetAcTableReference(PdfJsFrameComponent component)
{
return ref this.tables.GetRowSpan(component.ACHuffmanTableId)[0];
}

/// <summary>
/// Builds a lookup table for fast AC entropy scan decoding.
/// </summary>
/// <param name="index">The table index.</param>
/// <param name="acHuffmanTables">The collection of AC Huffman tables.</param>
public void BuildACTableLut(int index, PdfJsHuffmanTables acHuffmanTables)
{
const int FastBits = ScanDecoder.FastBits;
Span<short> fastAC = this.tables.GetRowSpan(index);
ref PdfJsHuffmanTable huffman = ref acHuffmanTables[index];

int i;
for (i = 0; i < (1 << FastBits); i++)
{
byte fast = huffman.Lookahead[i];
fastAC[i] = 0;
if (fast < byte.MaxValue)
{
int rs = huffman.Values[fast];
int run = (rs >> 4) & 15;
int magbits = rs & 15;
int len = huffman.Sizes[fast];

if (magbits > 0 && len + magbits <= FastBits)
{
// Magnitude code followed by receive_extend code
int k = ((i << len) & ((1 << FastBits) - 1)) >> (FastBits - magbits);
int m = 1 << (magbits - 1);
if (k < m)
{
k += (int)((~0U << magbits) + 1);
}

// if the result is small enough, we can fit it in fastAC table
if (k >= -128 && k <= 127)
{
fastAC[i] = (short)((k * 256) + (run * 16) + (len + magbits));
}
}
}
}
}

/// <inheritdoc />
public void Dispose()
{
this.tables?.Dispose();
this.tables = null;
}
}
}
Original file line number Diff line number Diff line change
@@ -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 FixedByteBuffer512
{
public fixed byte Data[1 << ScanDecoder.FastBits];

public byte this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ref byte self = ref Unsafe.As<FixedByteBuffer512, byte>(ref this);
return Unsafe.Add(ref self, idx);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct FixedInt16Buffer256
internal unsafe struct FixedInt16Buffer257
{
public fixed short Data[256];
public fixed short Data[257];

public short this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ref short self = ref Unsafe.As<FixedInt16Buffer256, short>(ref this);
ref short self = ref Unsafe.As<FixedInt16Buffer257, short>(ref this);
return Unsafe.Add(ref self, idx);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct FixedInt64Buffer18
internal unsafe struct FixedInt32Buffer18
{
public fixed long Data[18];
public fixed int Data[18];

public long this[int idx]
public int this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ref long self = ref Unsafe.As<FixedInt64Buffer18, long>(ref this);
ref int self = ref Unsafe.As<FixedInt32Buffer18, int>(ref this);
return Unsafe.Add(ref self, idx);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct FixedInt16Buffer18
internal unsafe struct FixedUInt32Buffer18
{
public fixed short Data[18];
public fixed uint Data[18];

public short this[int idx]
public uint this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ref short self = ref Unsafe.As<FixedInt16Buffer18, short>(ref this);
ref uint self = ref Unsafe.As<FixedUInt32Buffer18, uint>(ref this);
return Unsafe.Add(ref self, idx);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public void Init()
this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);
}

this.SpectralBlocks = this.memoryAllocator.Allocate2D<Block8x8>(blocksPerColumnForMcu, blocksPerLineForMcu + 1, true);
this.SpectralBlocks = this.memoryAllocator.AllocateClean2D<Block8x8>(blocksPerColumnForMcu, blocksPerLineForMcu + 1);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand All @@ -144,5 +144,13 @@ public int GetBlockBufferOffset(int row, int col)
{
return 64 * (((this.WidthInBlocks + 1) * row) + col);
}

// TODO: we need consistence in (row, col) VS (col, row) ordering
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref short GetBlockDataReference(int row, int col)
{
ref Block8x8 blockRef = ref this.GetBlockReference(col, row);
return ref Unsafe.As<Block8x8, short>(ref blockRef);
}
}
}
Loading