diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsAdobe.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsAdobe.cs
deleted file mode 100644
index 542272044..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsAdobe.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-// ReSharper disable InconsistentNaming
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System;
-
- ///
- /// Provides information about the Adobe marker segment
- ///
- internal struct PdfJsAdobe : IEquatable
- {
- ///
- /// The DCT Encode Version
- ///
- public short DCTEncodeVersion;
-
- ///
- /// 0x0 : (none)
- /// Bit 15 : Encoded with Blend=1 downsampling
- ///
- public short APP14Flags0;
-
- ///
- /// 0x0 : (none)
- ///
- public short APP14Flags1;
-
- ///
- /// Determines the colorspace transform
- /// 00 : Unknown (RGB or CMYK)
- /// 01 : YCbCr
- /// 02 : YCCK
- ///
- public byte ColorTransform;
-
- ///
- public bool Equals(PdfJsAdobe other)
- {
- return this.DCTEncodeVersion == other.DCTEncodeVersion
- && this.APP14Flags0 == other.APP14Flags0
- && this.APP14Flags1 == other.APP14Flags1
- && this.ColorTransform == other.ColorTransform;
- }
-
- ///
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj))
- {
- return false;
- }
-
- return obj is PdfJsAdobe && this.Equals((PdfJsAdobe)obj);
- }
-
- ///
- public override int GetHashCode()
- {
- unchecked
- {
- // TODO: Merge and use HashCodeHelpers
- int hashCode = this.DCTEncodeVersion.GetHashCode();
- hashCode = (hashCode * 397) ^ this.APP14Flags0.GetHashCode();
- hashCode = (hashCode * 397) ^ this.APP14Flags1.GetHashCode();
- hashCode = (hashCode * 397) ^ this.ColorTransform.GetHashCode();
- return hashCode;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponent.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponent.cs
deleted file mode 100644
index 12e11a86e..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponent.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System;
- using System.Numerics;
- using ImageSharp.Memory;
-
- ///
- /// Represents a component block
- ///
- internal struct PdfJsComponent : IDisposable
- {
- ///
- /// Gets or sets the output
- ///
- public Buffer Output;
-
- ///
- /// Gets or sets the scaling factors
- ///
- public Vector2 Scale;
-
- ///
- /// Gets or sets the number of blocks per line
- ///
- public int BlocksPerLine;
-
- ///
- /// Gets or sets the number of blocks per column
- ///
- public int BlocksPerColumn;
-
- ///
- public void Dispose()
- {
- this.Output?.Dispose();
- this.Output = null;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponentBlocks.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponentBlocks.cs
deleted file mode 100644
index 6a879b4e5..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsComponentBlocks.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System;
-
- ///
- /// Contains all the decoded component blocks
- ///
- internal sealed class PdfJsComponentBlocks : IDisposable
- {
- ///
- /// Gets or sets the component blocks
- ///
- public PdfJsComponent[] Components { get; set; }
-
- ///
- public void Dispose()
- {
- if (this.Components != null)
- {
- for (int i = 0; i < this.Components.Length; i++)
- {
- this.Components[i].Dispose();
- }
-
- this.Components = null;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFileMarker.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFileMarker.cs
deleted file mode 100644
index 5e2555a9b..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFileMarker.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- ///
- /// Represents a jpeg file marker
- ///
- internal struct PdfJsFileMarker
- {
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The marker
- /// The position within the stream
- public PdfJsFileMarker(ushort marker, long position)
- {
- this.Marker = marker;
- this.Position = position;
- this.Invalid = false;
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The marker
- /// The position within the stream
- /// Whether the current marker is invalid
- public PdfJsFileMarker(ushort marker, long position, bool invalid)
- {
- this.Marker = marker;
- this.Position = position;
- this.Invalid = invalid;
- }
-
- ///
- /// Gets or sets a value indicating whether the current marker is invalid
- ///
- public bool Invalid { get; set; }
-
- ///
- /// Gets the position of the marker within a stream
- ///
- public ushort Marker { get; }
-
- ///
- /// Gets the position of the marker within a stream
- ///
- public long Position { get; }
-
- ///
- public override string ToString()
- {
- return this.Marker.ToString("X");
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrame.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrame.cs
deleted file mode 100644
index ff25ee154..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrame.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System;
-
- ///
- /// Represent a single jpeg frame
- ///
- internal sealed class PdfJsFrame : IDisposable
- {
- ///
- /// Gets or sets a value indicating whether the frame uses the extended specification
- ///
- public bool Extended { get; set; }
-
- ///
- /// Gets or sets a value indicating whether the frame uses the progressive specification
- ///
- public bool Progressive { get; set; }
-
- ///
- /// Gets or sets the precision
- ///
- public byte Precision { get; set; }
-
- ///
- /// Gets or sets the number of scanlines within the frame
- ///
- public short Scanlines { get; set; }
-
- ///
- /// Gets or sets the number of samples per scanline
- ///
- public short SamplesPerLine { get; set; }
-
- ///
- /// Gets or sets the number of components within a frame. In progressive frames this value can range from only 1 to 4
- ///
- public byte ComponentCount { get; set; }
-
- ///
- /// Gets or sets the component id collection
- ///
- public byte[] ComponentIds { get; set; }
-
- ///
- /// Gets or sets the frame component collection
- ///
- public PdfJsFrameComponent[] Components { get; set; }
-
- ///
- /// Gets or sets the maximum horizontal sampling factor
- ///
- public int MaxHorizontalFactor { get; set; }
-
- ///
- /// Gets or sets the maximum vertical sampling factor
- ///
- public int MaxVerticalFactor { get; set; }
-
- ///
- /// Gets or sets the number of MCU's per line
- ///
- public int McusPerLine { get; set; }
-
- ///
- /// Gets or sets the number of MCU's per column
- ///
- public int McusPerColumn { get; set; }
-
- ///
- public void Dispose()
- {
- if (this.Components != null)
- {
- for (int i = 0; i < this.Components.Length; i++)
- {
- this.Components[i].Dispose();
- }
-
- this.Components = null;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs
deleted file mode 100644
index b999d86f1..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System;
-
- using ImageSharp.Memory;
-
- ///
- /// Represents a single frame component
- ///
- internal struct PdfJsFrameComponent : IDisposable
- {
- ///
- /// Gets or sets the component Id
- ///
- public byte Id;
-
- ///
- /// TODO: What does pred stand for?
- ///
- public int Pred;
-
- ///
- /// Gets or sets the horizontal sampling factor.
- ///
- public int HorizontalFactor;
-
- ///
- /// Gets or sets the vertical sampling factor.
- ///
- public int VerticalFactor;
-
- ///
- /// Gets or sets the identifier
- ///
- public byte QuantizationIdentifier;
-
- ///
- /// Gets or sets the block data
- ///
- public Buffer BlockData;
-
- ///
- /// Gets or sets the number of blocks per line
- ///
- public int BlocksPerLine;
-
- ///
- /// Gets or sets the number of blocks per column
- ///
- public int BlocksPerColumn;
-
- ///
- /// Gets the index for the DC Huffman table
- ///
- public int DCHuffmanTableId;
-
- ///
- /// Gets the index for the AC Huffman table
- ///
- public int ACHuffmanTableId;
-
- ///
- public void Dispose()
- {
- this.BlockData?.Dispose();
- this.BlockData = null;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs
deleted file mode 100644
index 745dc6361..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTable.cs
+++ /dev/null
@@ -1,212 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System;
- using System.Runtime.CompilerServices;
-
- using ImageSharp.Memory;
-
- ///
- /// Represents a Huffman Table
- ///
- internal struct PdfJsHuffmanTable : IDisposable
- {
- private Buffer lookahead;
- private Buffer valOffset;
- private Buffer maxcode;
- private Buffer huffval;
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The code lengths
- /// The huffman values
- public PdfJsHuffmanTable(byte[] lengths, byte[] values)
- {
- this.lookahead = Buffer.CreateClean(256);
- this.valOffset = Buffer.CreateClean(18);
- this.maxcode = Buffer.CreateClean(18);
-
- using (var huffsize = Buffer.CreateClean(257))
- using (var huffcode = Buffer.CreateClean(257))
- {
- GenerateSizeTable(lengths, huffsize);
- GenerateCodeTable(huffsize, huffcode);
- GenerateDecoderTables(lengths, huffcode, this.valOffset, this.maxcode);
- GenerateLookaheadTables(lengths, values, this.lookahead);
- }
-
- this.huffval = Buffer.CreateClean(values.Length);
- 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;
- }
-
- ///
- /// Gets the max code array
- ///
- public long[] MaxCode
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get;
- }
-
- ///
- /// Gets the value offset array
- ///
- public short[] ValOffset
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get;
- }
-
- ///
- /// Gets the huffman value array
- ///
- public byte[] HuffVal
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get;
- }
-
- ///
- /// Gets the lookahead array
- ///
- public short[] Lookahead
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get;
- }
-
- ///
- public void Dispose()
- {
- this.lookahead?.Dispose();
- this.valOffset?.Dispose();
- this.maxcode?.Dispose();
- this.huffval?.Dispose();
-
- this.lookahead = null;
- this.valOffset = null;
- this.maxcode = null;
- this.huffval = null;
- }
-
- ///
- /// Figure C.1: make table of Huffman code length for each symbol
- ///
- /// The code lengths
- /// The huffman size span
- private static void GenerateSizeTable(byte[] lengths, Span huffsize)
- {
- short index = 0;
- for (short l = 1; l <= 16; l++)
- {
- byte i = lengths[l];
- for (short j = 0; j < i; j++)
- {
- huffsize[index] = l;
- index++;
- }
- }
-
- huffsize[index] = 0;
- }
-
- ///
- /// Figure C.2: generate the codes themselves
- ///
- /// The huffman size span
- /// The huffman code span
- private static void GenerateCodeTable(Span huffsize, Span huffcode)
- {
- short k = 0;
- short si = huffsize[0];
- short code = 0;
- for (short i = 0; i < huffsize.Length; i++)
- {
- while (huffsize[k] == si)
- {
- huffcode[k] = code;
- code++;
- k++;
- }
-
- code <<= 1;
- si++;
- }
- }
-
- ///
- /// Figure F.15: generate decoding tables for bit-sequential decoding
- ///
- /// The code lengths
- /// The huffman code span
- /// The value offset span
- /// The max code span
- private static void GenerateDecoderTables(byte[] lengths, Span huffcode, Span valOffset, Span maxcode)
- {
- short bitcount = 0;
- for (int i = 1; i <= 16; i++)
- {
- 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
- {
- maxcode[i] = -1; // -1 if no codes of this length
- }
- }
-
- valOffset[17] = 0;
- maxcode[17] = 0xFFFFFL;
- }
-
- ///
- /// Generates lookup tables to speed up decoding
- ///
- /// The code lengths
- /// The huffman value array
- /// The lookahead span
- private static void GenerateLookaheadTables(byte[] lengths, byte[] huffval, Span lookahead)
- {
- int x = 0, code = 0;
-
- for (int i = 0; i < 8; i++)
- {
- code <<= 1;
-
- for (int j = 0; j < lengths[i + 1]; j++)
- {
- // 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++)
- {
- lookahead[base2 | k] = lutValue;
- }
-
- code++;
- x++;
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTables.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTables.cs
deleted file mode 100644
index 5d00fe7f6..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsHuffmanTables.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System;
- using System.Collections.Generic;
- using System.Runtime.CompilerServices;
-
- ///
- /// Defines a pair of huffman tables
- ///
- internal sealed class PdfJsHuffmanTables : IDisposable
- {
- private readonly PdfJsHuffmanTable[] tables = new PdfJsHuffmanTable[4];
-
- ///
- /// Gets or sets the table at the given index.
- ///
- /// The index
- /// The
- public ref PdfJsHuffmanTable this[int index]
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- return ref this.tables[index];
- }
- }
-
- ///
- public void Dispose()
- {
- for (int i = 0; i < this.tables.Length; i++)
- {
- this.tables[i].Dispose();
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsIDCT.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsIDCT.cs
deleted file mode 100644
index c509d4357..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsIDCT.cs
+++ /dev/null
@@ -1,511 +0,0 @@
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System;
- using System.Runtime.CompilerServices;
-
- using ImageSharp.Memory;
-
- ///
- /// Performs the inverse Descrete Cosine Transform on each frame component.
- ///
- internal static class PdfJsIDCT
- {
- ///
- /// Precomputed values scaled up by 14 bits
- ///
- public static readonly short[] Aanscales =
- {
- 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, 22725, 31521, 29692, 26722, 22725, 17855,
- 12299, 6270, 21407, 29692, 27969, 25172, 21407, 16819, 11585,
- 5906, 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
- 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, 12873,
- 17855, 16819, 15137, 12873, 10114, 6967, 3552, 8867, 12299,
- 11585, 10426, 8867, 6967, 4799, 2446, 4520, 6270, 5906, 5315,
- 4520, 3552, 2446, 1247
- };
-
- private const int DctCos1 = 4017; // cos(pi/16)
- private const int DctSin1 = 799; // sin(pi/16)
- private const int DctCos3 = 3406; // cos(3*pi/16)
- private const int DctSin3 = 2276; // sin(3*pi/16)
- private const int DctCos6 = 1567; // cos(6*pi/16)
- private const int DctSin6 = 3784; // sin(6*pi/16)
- private const int DctSqrt2 = 5793; // sqrt(2)
- private const int DctSqrt1D2 = 2896; // sqrt(2) / 2
-
-#pragma warning disable SA1310 // Field names must not contain underscore
- private const int FIX_1_082392200 = 277; // FIX(1.082392200)
- private const int FIX_1_414213562 = 362; // FIX(1.414213562)
- private const int FIX_1_847759065 = 473; // FIX(1.847759065)
- private const int FIX_2_613125930 = 669; // FIX(2.613125930)
-#pragma warning restore SA1310 // Field names must not contain underscore
-
- private const int ConstBits = 8;
- private const int Pass1Bits = 2; // Factional bits in scale factors
- private const int MaxJSample = 255;
- private const int CenterJSample = 128;
- private const int RangeCenter = (MaxJSample * 2) + 2;
-
- // First segment of range limit table: limit[x] = 0 for x < 0
- // allow negative subscripts of simple table
- private const int TableOffset = 2 * (MaxJSample + 1);
- private const int LimitOffset = TableOffset - (RangeCenter - CenterJSample);
-
- // Each IDCT routine is responsible for range-limiting its results and
- // converting them to unsigned form (0..MaxJSample). The raw outputs could
- // be quite far out of range if the input data is corrupt, so a bulletproof
- // range-limiting step is required. We use a mask-and-table-lookup method
- // to do the combined operations quickly, assuming that MaxJSample+1
- // is a power of 2.
- private const int RangeMask = (MaxJSample * 4) + 3; // 2 bits wider than legal samples
-
- private static readonly byte[] Limit = new byte[5 * (MaxJSample + 1)];
-
- static PdfJsIDCT()
- {
- // Main part of range limit table: limit[x] = x
- int i;
- for (i = 0; i <= MaxJSample; i++)
- {
- Limit[TableOffset + i] = (byte)i;
- }
-
- // End of range limit table: Limit[x] = MaxJSample for x > MaxJSample
- for (; i < 3 * (MaxJSample + 1); i++)
- {
- Limit[TableOffset + i] = MaxJSample;
- }
- }
-
- ///
- /// A port of Poppler's IDCT method which in turn is taken from:
- /// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
- /// 'Practical Fast 1-D DCT Algorithms with 11 Multiplications',
- /// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, 988-991.
- ///
- /// The fram component
- /// The block buffer offset
- /// The computational buffer for holding temp values
- /// The quantization table
- public static void QuantizeAndInverse(ref PdfJsFrameComponent component, int blockBufferOffset, ref Span computationBuffer, ref Span quantizationTable)
- {
- Span blockData = component.BlockData.Slice(blockBufferOffset);
- int v0, v1, v2, v3, v4, v5, v6, v7;
- int p0, p1, p2, p3, p4, p5, p6, p7;
- int t;
-
- // inverse DCT on rows
- for (int row = 0; row < 64; row += 8)
- {
- // gather block data
- p0 = blockData[row];
- p1 = blockData[row + 1];
- p2 = blockData[row + 2];
- p3 = blockData[row + 3];
- p4 = blockData[row + 4];
- p5 = blockData[row + 5];
- p6 = blockData[row + 6];
- p7 = blockData[row + 7];
-
- // dequant p0
- p0 *= quantizationTable[row];
-
- // check for all-zero AC coefficients
- if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0)
- {
- t = ((DctSqrt2 * p0) + 512) >> 10;
- short st = (short)t;
- computationBuffer[row] = st;
- computationBuffer[row + 1] = st;
- computationBuffer[row + 2] = st;
- computationBuffer[row + 3] = st;
- computationBuffer[row + 4] = st;
- computationBuffer[row + 5] = st;
- computationBuffer[row + 6] = st;
- computationBuffer[row + 7] = st;
- continue;
- }
-
- // dequant p1 ... p7
- p1 *= quantizationTable[row + 1];
- p2 *= quantizationTable[row + 2];
- p3 *= quantizationTable[row + 3];
- p4 *= quantizationTable[row + 4];
- p5 *= quantizationTable[row + 5];
- p6 *= quantizationTable[row + 6];
- p7 *= quantizationTable[row + 7];
-
- // stage 4
- v0 = ((DctSqrt2 * p0) + 128) >> 8;
- v1 = ((DctSqrt2 * p4) + 128) >> 8;
- v2 = p2;
- v3 = p6;
- v4 = ((DctSqrt1D2 * (p1 - p7)) + 128) >> 8;
- v7 = ((DctSqrt1D2 * (p1 + p7)) + 128) >> 8;
- v5 = p3 << 4;
- v6 = p5 << 4;
-
- // stage 3
- v0 = (v0 + v1 + 1) >> 1;
- v1 = v0 - v1;
- t = ((v2 * DctSin6) + (v3 * DctCos6) + 128) >> 8;
- v2 = ((v2 * DctCos6) - (v3 * DctSin6) + 128) >> 8;
- v3 = t;
- v4 = (v4 + v6 + 1) >> 1;
- v6 = v4 - v6;
- v7 = (v7 + v5 + 1) >> 1;
- v5 = v7 - v5;
-
- // stage 2
- v0 = (v0 + v3 + 1) >> 1;
- v3 = v0 - v3;
- v1 = (v1 + v2 + 1) >> 1;
- v2 = v1 - v2;
- t = ((v4 * DctSin3) + (v7 * DctCos3) + 2048) >> 12;
- v4 = ((v4 * DctCos3) - (v7 * DctSin3) + 2048) >> 12;
- v7 = t;
- t = ((v5 * DctSin1) + (v6 * DctCos1) + 2048) >> 12;
- v5 = ((v5 * DctCos1) - (v6 * DctSin1) + 2048) >> 12;
- v6 = t;
-
- // stage 1
- computationBuffer[row] = (short)(v0 + v7);
- computationBuffer[row + 7] = (short)(v0 - v7);
- computationBuffer[row + 1] = (short)(v1 + v6);
- computationBuffer[row + 6] = (short)(v1 - v6);
- computationBuffer[row + 2] = (short)(v2 + v5);
- computationBuffer[row + 5] = (short)(v2 - v5);
- computationBuffer[row + 3] = (short)(v3 + v4);
- computationBuffer[row + 4] = (short)(v3 - v4);
- }
-
- // inverse DCT on columns
- for (int col = 0; col < 8; ++col)
- {
- p0 = computationBuffer[col];
- p1 = computationBuffer[col + 8];
- p2 = computationBuffer[col + 16];
- p3 = computationBuffer[col + 24];
- p4 = computationBuffer[col + 32];
- p5 = computationBuffer[col + 40];
- p6 = computationBuffer[col + 48];
- p7 = computationBuffer[col + 56];
-
- // check for all-zero AC coefficients
- if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0)
- {
- t = ((DctSqrt2 * p0) + 8192) >> 14;
-
- // convert to 8 bit
- t = (t < -2040) ? 0 : (t >= 2024) ? MaxJSample : (t + 2056) >> 4;
- short st = (short)t;
-
- blockData[col] = st;
- blockData[col + 8] = st;
- blockData[col + 16] = st;
- blockData[col + 24] = st;
- blockData[col + 32] = st;
- blockData[col + 40] = st;
- blockData[col + 48] = st;
- blockData[col + 56] = st;
- continue;
- }
-
- // stage 4
- v0 = ((DctSqrt2 * p0) + 2048) >> 12;
- v1 = ((DctSqrt2 * p4) + 2048) >> 12;
- v2 = p2;
- v3 = p6;
- v4 = ((DctSqrt1D2 * (p1 - p7)) + 2048) >> 12;
- v7 = ((DctSqrt1D2 * (p1 + p7)) + 2048) >> 12;
- v5 = p3;
- v6 = p5;
-
- // stage 3
- // Shift v0 by 128.5 << 5 here, so we don't need to shift p0...p7 when
- // converting to UInt8 range later.
- v0 = ((v0 + v1 + 1) >> 1) + 4112;
- v1 = v0 - v1;
- t = ((v2 * DctSin6) + (v3 * DctCos6) + 2048) >> 12;
- v2 = ((v2 * DctCos6) - (v3 * DctSin6) + 2048) >> 12;
- v3 = t;
- v4 = (v4 + v6 + 1) >> 1;
- v6 = v4 - v6;
- v7 = (v7 + v5 + 1) >> 1;
- v5 = v7 - v5;
-
- // stage 2
- v0 = (v0 + v3 + 1) >> 1;
- v3 = v0 - v3;
- v1 = (v1 + v2 + 1) >> 1;
- v2 = v1 - v2;
- t = ((v4 * DctSin3) + (v7 * DctCos3) + 2048) >> 12;
- v4 = ((v4 * DctCos3) - (v7 * DctSin3) + 2048) >> 12;
- v7 = t;
- t = ((v5 * DctSin1) + (v6 * DctCos1) + 2048) >> 12;
- v5 = ((v5 * DctCos1) - (v6 * DctSin1) + 2048) >> 12;
- v6 = t;
-
- // stage 1
- p0 = v0 + v7;
- p7 = v0 - v7;
- p1 = v1 + v6;
- p6 = v1 - v6;
- p2 = v2 + v5;
- p5 = v2 - v5;
- p3 = v3 + v4;
- p4 = v3 - v4;
-
- // convert to 8-bit integers
- p0 = (p0 < 16) ? 0 : (p0 >= 4080) ? MaxJSample : p0 >> 4;
- p1 = (p1 < 16) ? 0 : (p1 >= 4080) ? MaxJSample : p1 >> 4;
- p2 = (p2 < 16) ? 0 : (p2 >= 4080) ? MaxJSample : p2 >> 4;
- p3 = (p3 < 16) ? 0 : (p3 >= 4080) ? MaxJSample : p3 >> 4;
- p4 = (p4 < 16) ? 0 : (p4 >= 4080) ? MaxJSample : p4 >> 4;
- p5 = (p5 < 16) ? 0 : (p5 >= 4080) ? MaxJSample : p5 >> 4;
- p6 = (p6 < 16) ? 0 : (p6 >= 4080) ? MaxJSample : p6 >> 4;
- p7 = (p7 < 16) ? 0 : (p7 >= 4080) ? MaxJSample : p7 >> 4;
-
- // store block data
- blockData[col] = (short)p0;
- blockData[col + 8] = (short)p1;
- blockData[col + 16] = (short)p2;
- blockData[col + 24] = (short)p3;
- blockData[col + 32] = (short)p4;
- blockData[col + 40] = (short)p5;
- blockData[col + 48] = (short)p6;
- blockData[col + 56] = (short)p7;
- }
- }
-
- ///
- /// A port of
- /// A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
- /// on each row(or vice versa, but it's more convenient to emit a row at
- /// a time). Direct algorithms are also available, but they are much more
- /// complex and seem not to be any faster when reduced to code.
- ///
- /// This implementation is based on Arai, Agui, and Nakajima's algorithm for
- /// scaled DCT.Their original paper (Trans.IEICE E-71(11):1095) is in
- /// Japanese, but the algorithm is described in the Pennebaker & Mitchell
- /// JPEG textbook(see REFERENCES section in file README.ijg). The following
- /// code is based directly on figure 4-8 in P&M.
- /// While an 8-point DCT cannot be done in less than 11 multiplies, it is
- /// possible to arrange the computation so that many of the multiplies are
- /// simple scalings of the final outputs.These multiplies can then be
- /// folded into the multiplications or divisions by the JPEG quantization
- /// table entries. The AA&N method leaves only 5 multiplies and 29 adds
- /// to be done in the DCT itself.
- /// The primary disadvantage of this method is that with fixed-point math,
- /// accuracy is lost due to imprecise representation of the scaled
- /// quantization values.The smaller the quantization table entry, the less
- /// precise the scaled value, so this implementation does worse with high -
- /// quality - setting files than with low - quality ones.
- ///
- /// The frame component
- /// The block buffer offset
- /// The computational buffer for holding temp values
- /// The multiplier table
- public static void QuantizeAndInverseFast(ref PdfJsFrameComponent component, int blockBufferOffset, ref Span computationBuffer, ref Span multiplierTable)
- {
- Span blockData = component.BlockData.Slice(blockBufferOffset);
- int p0, p1, p2, p3, p4, p5, p6, p7;
-
- for (int col = 0; col < 8; col++)
- {
- // Gather block data
- p0 = blockData[col];
- p1 = blockData[col + 8];
- p2 = blockData[col + 16];
- p3 = blockData[col + 24];
- p4 = blockData[col + 32];
- p5 = blockData[col + 40];
- p6 = blockData[col + 48];
- p7 = blockData[col + 56];
-
- int tmp0 = p0 * multiplierTable[col];
-
- // Due to quantization, we will usually find that many of the input
- // coefficients are zero, especially the AC terms. We can exploit this
- // by short-circuiting the IDCT calculation for any column in which all
- // the AC terms are zero. In that case each output is equal to the
- // DC coefficient (with scale factor as needed).
- // With typical images and quantization tables, half or more of the
- // column DCT calculations can be simplified this way.
- if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0)
- {
- short dcval = (short)tmp0;
-
- computationBuffer[col] = dcval;
- computationBuffer[col + 8] = dcval;
- computationBuffer[col + 16] = dcval;
- computationBuffer[col + 24] = dcval;
- computationBuffer[col + 32] = dcval;
- computationBuffer[col + 40] = dcval;
- computationBuffer[col + 48] = dcval;
- computationBuffer[col + 56] = dcval;
-
- continue;
- }
-
- // Even part
- int tmp1 = p2 * multiplierTable[col + 16];
- int tmp2 = p4 * multiplierTable[col + 32];
- int tmp3 = p6 * multiplierTable[col + 48];
-
- int tmp10 = tmp0 + tmp2; // Phase 3
- int tmp11 = tmp0 - tmp2;
-
- int tmp13 = tmp1 + tmp3; // Phases 5-3
- int tmp12 = Multiply(tmp1 - tmp3, FIX_1_414213562) - tmp13; // 2*c4
-
- tmp0 = tmp10 + tmp13; // Phase 2
- tmp3 = tmp10 - tmp13;
- tmp1 = tmp11 + tmp12;
- tmp2 = tmp11 - tmp12;
-
- // Odd Part
- int tmp4 = p1 * multiplierTable[col + 8];
- int tmp5 = p3 * multiplierTable[col + 24];
- int tmp6 = p5 * multiplierTable[col + 40];
- int tmp7 = p7 * multiplierTable[col + 56];
-
- int z13 = tmp6 + tmp5; // Phase 6
- int z10 = tmp6 - tmp5;
- int z11 = tmp4 + tmp7;
- int z12 = tmp4 - tmp7;
-
- tmp7 = z11 + z13; // Phase 5
- tmp11 = Multiply(z11 - z13, FIX_1_414213562); // 2*c4
-
- int z5 = Multiply(z10 + z12, FIX_1_847759065); // 2*c2
- tmp10 = z5 - Multiply(z12, FIX_1_082392200); // 2*(c2-c6)
- tmp12 = z5 - Multiply(z10, FIX_2_613125930); // 2*(c2+c6)
-
- tmp6 = tmp12 - tmp7; // Phase 2
- tmp5 = tmp11 - tmp6;
- tmp4 = tmp10 - tmp5;
-
- computationBuffer[col] = (short)(tmp0 + tmp7);
- computationBuffer[col + 56] = (short)(tmp0 - tmp7);
- computationBuffer[col + 8] = (short)(tmp1 + tmp6);
- computationBuffer[col + 48] = (short)(tmp1 - tmp6);
- computationBuffer[col + 16] = (short)(tmp2 + tmp5);
- computationBuffer[col + 40] = (short)(tmp2 - tmp5);
- computationBuffer[col + 24] = (short)(tmp3 + tmp4);
- computationBuffer[col + 32] = (short)(tmp3 - tmp4);
- }
-
- // Pass 2: process rows from work array, store into output array.
- // Note that we must descale the results by a factor of 8 == 2**3,
- // and also undo the pass 1 bits scaling.
- for (int row = 0; row < 64; row += 8)
- {
- p1 = computationBuffer[row + 1];
- p2 = computationBuffer[row + 2];
- p3 = computationBuffer[row + 3];
- p4 = computationBuffer[row + 4];
- p5 = computationBuffer[row + 5];
- p6 = computationBuffer[row + 6];
- p7 = computationBuffer[row + 7];
-
- // Add range center and fudge factor for final descale and range-limit.
- int z5 = computationBuffer[row] + (RangeCenter << (Pass1Bits + 3)) + (1 << (Pass1Bits + 2));
-
- // Check for all-zero AC coefficients
- if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0)
- {
- byte dcval = Limit[LimitOffset + (RightShift(z5, Pass1Bits + 3) & RangeMask)];
-
- blockData[row] = dcval;
- blockData[row + 1] = dcval;
- blockData[row + 2] = dcval;
- blockData[row + 3] = dcval;
- blockData[row + 4] = dcval;
- blockData[row + 5] = dcval;
- blockData[row + 6] = dcval;
- blockData[row + 7] = dcval;
-
- continue;
- }
-
- // Even part
- int tmp10 = z5 + p4;
- int tmp11 = z5 - p4;
-
- int tmp13 = p2 + p6;
- int tmp12 = Multiply(p2 - p6, FIX_1_414213562) - tmp13; // 2*c4
-
- int tmp0 = tmp10 + tmp13;
- int tmp3 = tmp10 - tmp13;
- int tmp1 = tmp11 + tmp12;
- int tmp2 = tmp11 - tmp12;
-
- // Odd part
- int z13 = p5 + p3;
- int z10 = p5 - p3;
- int z11 = p1 + p7;
- int z12 = p1 - p7;
-
- int tmp7 = z11 + z13; // Phase 5
- tmp11 = Multiply(z11 - z13, FIX_1_414213562); // 2*c4
-
- z5 = Multiply(z10 + z12, FIX_1_847759065); // 2*c2
- tmp10 = z5 - Multiply(z12, FIX_1_082392200); // 2*(c2-c6)
- tmp12 = z5 - Multiply(z10, FIX_2_613125930); // 2*(c2+c6)
-
- int tmp6 = tmp12 - tmp7; // Phase 2
- int tmp5 = tmp11 - tmp6;
- int tmp4 = tmp10 - tmp5;
-
- // Final output stage: scale down by a factor of 8, offset, and range-limit
- blockData[row] = Limit[LimitOffset + (RightShift(tmp0 + tmp7, Pass1Bits + 3) & RangeMask)];
- blockData[row + 7] = Limit[LimitOffset + (RightShift(tmp0 - tmp7, Pass1Bits + 3) & RangeMask)];
- blockData[row + 1] = Limit[LimitOffset + (RightShift(tmp1 + tmp6, Pass1Bits + 3) & RangeMask)];
- blockData[row + 6] = Limit[LimitOffset + (RightShift(tmp1 - tmp6, Pass1Bits + 3) & RangeMask)];
- blockData[row + 2] = Limit[LimitOffset + (RightShift(tmp2 + tmp5, Pass1Bits + 3) & RangeMask)];
- blockData[row + 5] = Limit[LimitOffset + (RightShift(tmp2 - tmp5, Pass1Bits + 3) & RangeMask)];
- blockData[row + 3] = Limit[LimitOffset + (RightShift(tmp3 + tmp4, Pass1Bits + 3) & RangeMask)];
- blockData[row + 4] = Limit[LimitOffset + (RightShift(tmp3 - tmp4, Pass1Bits + 3) & RangeMask)];
- }
- }
-
- ///
- /// Descale and correctly round an int value that's scaled by bits.
- /// We assume rounds towards minus infinity, so adding
- /// the fudge factor is correct for either sign of .
- ///
- /// The value
- /// The number of bits
- /// The
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int Descale(int value, int n)
- {
- return RightShift(value + (1 << (n - 1)), n);
- }
-
- ///
- /// Multiply a variable by an int constant, and immediately descale.
- ///
- /// The value
- /// The multiplier
- /// The
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int Multiply(int val, int c)
- {
- return Descale(val * c, ConstBits);
- }
-
- ///
- /// Right-shifts the value by the given amount
- ///
- /// The value
- /// The amount to shift by
- /// The
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int RightShift(int value, int shift)
- {
- return value >> shift;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsJFif.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsJFif.cs
deleted file mode 100644
index 3c7cba989..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsJFif.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System;
-
- ///
- /// Provides information about the JFIF marker segment
- /// TODO: Thumbnail?
- ///
- internal struct PdfJsJFif : IEquatable
- {
- ///
- /// The major version
- ///
- public byte MajorVersion;
-
- ///
- /// The minor version
- ///
- public byte MinorVersion;
-
- ///
- /// Units for the following pixel density fields
- /// 00 : No units; width:height pixel aspect ratio = Ydensity:Xdensity
- /// 01 : Pixels per inch (2.54 cm)
- /// 02 : Pixels per centimeter
- ///
- public byte DensityUnits;
-
- ///
- /// Horizontal pixel density. Must not be zero.
- ///
- public short XDensity;
-
- ///
- /// Vertical pixel density. Must not be zero.
- ///
- public short YDensity;
-
- ///
- public bool Equals(PdfJsJFif other)
- {
- return this.MajorVersion == other.MajorVersion
- && this.MinorVersion == other.MinorVersion
- && this.DensityUnits == other.DensityUnits
- && this.XDensity == other.XDensity
- && this.YDensity == other.YDensity;
- }
-
- ///
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj))
- {
- return false;
- }
-
- return obj is PdfJsJFif && this.Equals((PdfJsJFif)obj);
- }
-
- ///
- public override int GetHashCode()
- {
- unchecked
- {
- int hashCode = this.MajorVersion.GetHashCode();
- hashCode = (hashCode * 397) ^ this.MinorVersion.GetHashCode();
- hashCode = (hashCode * 397) ^ this.DensityUnits.GetHashCode();
- hashCode = (hashCode * 397) ^ this.XDensity.GetHashCode();
- hashCode = (hashCode * 397) ^ this.YDensity.GetHashCode();
- return hashCode;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsJpegPixelArea.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsJpegPixelArea.cs
deleted file mode 100644
index 09677b278..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsJpegPixelArea.cs
+++ /dev/null
@@ -1,147 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System;
- using System.Diagnostics;
- using System.Numerics;
- using System.Runtime.CompilerServices;
- using ImageSharp.Memory;
-
- ///
- /// Represents a section of the jpeg component data laid out in pixel order.
- ///
- internal struct PdfJsJpegPixelArea : IDisposable
- {
- private readonly int imageWidth;
-
- private readonly int imageHeight;
-
- private Buffer componentData;
-
- private int rowStride;
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The image width
- /// The image height
- /// The number of components
- public PdfJsJpegPixelArea(int imageWidth, int imageHeight, int numberOfComponents)
- {
- this.imageWidth = imageWidth;
- this.imageHeight = imageHeight;
- this.Width = 0;
- this.Height = 0;
- this.NumberOfComponents = numberOfComponents;
- this.componentData = null;
- this.rowStride = 0;
- }
-
- ///
- /// Gets the number of components
- ///
- public int NumberOfComponents { get; }
-
- ///
- /// Gets the width
- ///
- public int Width { get; private set; }
-
- ///
- /// Gets the height
- ///
- public int Height { get; private set; }
-
- ///
- /// Organsizes the decoded jpeg components into a linear array ordered by component.
- /// This must be called before attempting to retrieve the data.
- ///
- /// The jpeg component blocks
- /// The pixel area width
- /// The pixel area height
- public void LinearizeBlockData(PdfJsComponentBlocks components, int width, int height)
- {
- this.Width = width;
- this.Height = height;
- int numberOfComponents = this.NumberOfComponents;
- this.rowStride = width * numberOfComponents;
- var scale = new Vector2(this.imageWidth / (float)width, this.imageHeight / (float)height);
-
- this.componentData = new Buffer(width * height * numberOfComponents);
- Span componentDataSpan = this.componentData;
- const uint Mask3Lsb = 0xFFFFFFF8; // Used to clear the 3 LSBs
-
- using (var xScaleBlockOffset = new Buffer(width))
- {
- Span xScaleBlockOffsetSpan = xScaleBlockOffset;
- for (int i = 0; i < numberOfComponents; i++)
- {
- ref PdfJsComponent component = ref components.Components[i];
- Vector2 componentScale = component.Scale * scale;
- int offset = i;
- Span output = component.Output;
- int blocksPerScanline = (component.BlocksPerLine + 1) << 3;
-
- // Precalculate the xScaleBlockOffset
- int j;
- for (int x = 0; x < width; x++)
- {
- j = (int)(x * componentScale.X);
- xScaleBlockOffsetSpan[x] = (int)((j & Mask3Lsb) << 3) | (j & 7);
- }
-
- // Linearize the blocks of the component
- for (int y = 0; y < height; y++)
- {
- j = (int)(y * componentScale.Y);
- int index = blocksPerScanline * (int)(j & Mask3Lsb) | ((j & 7) << 3);
- for (int x = 0; x < width; x++)
- {
- componentDataSpan[offset] = (byte)output[index + xScaleBlockOffsetSpan[x]];
- offset += numberOfComponents;
- }
- }
- }
- }
- }
-
- ///
- /// Gets a representing the row 'y' beginning from the the first byte on that row.
- ///
- /// The y-coordinate of the pixel row. Must be greater than or equal to zero and less than the height of the pixel area.
- /// The
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Span GetRowSpan(int y)
- {
- this.CheckCoordinates(y);
- return this.componentData.Slice(y * this.rowStride, this.rowStride);
- }
-
- ///
- public void Dispose()
- {
- this.componentData?.Dispose();
- this.componentData = null;
- }
-
- ///
- /// Checks the coordinates to ensure they are within bounds.
- ///
- /// The y-coordinate of the row. Must be greater than zero and less than the height of the area.
- ///
- /// Thrown if the coordinates are not within the bounds of the image.
- ///
- [Conditional("DEBUG")]
- private void CheckCoordinates(int y)
- {
- if (y < 0 || y >= this.Height)
- {
- throw new ArgumentOutOfRangeException(nameof(y), y, $"{y} is outwith the area bounds.");
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsQuantizationTables.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsQuantizationTables.cs
deleted file mode 100644
index 996752ba3..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsQuantizationTables.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System;
- using System.Runtime.CompilerServices;
-
- using ImageSharp.Memory;
-
- ///
- /// Contains the quantization tables.
- ///
- internal sealed class PdfJsQuantizationTables : IDisposable
- {
- ///
- /// Gets the ZigZag scan table
- ///
- public static byte[] DctZigZag
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get;
- }
-
- =
- {
- 0,
- 1, 8,
- 16, 9, 2,
- 3, 10, 17, 24,
- 32, 25, 18, 11, 4,
- 5, 12, 19, 26, 33, 40,
- 48, 41, 34, 27, 20, 13, 6,
- 7, 14, 21, 28, 35, 42, 49, 56,
- 57, 50, 43, 36, 29, 22, 15,
- 23, 30, 37, 44, 51, 58,
- 59, 52, 45, 38, 31,
- 39, 46, 53, 60,
- 61, 54, 47,
- 55, 62,
- 63
- };
-
- ///
- /// Gets or sets the quantization tables.
- ///
- public Buffer2D Tables
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get; set;
- }
-
- = new Buffer2D(64, 4);
-
- ///
- public void Dispose()
- {
- if (this.Tables != null)
- {
- this.Tables.Dispose();
- this.Tables = null;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs
deleted file mode 100644
index c250db4c4..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs
+++ /dev/null
@@ -1,947 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System;
-#if DEBUG
- using System.Diagnostics;
-#endif
- using System.IO;
- using System.Runtime.CompilerServices;
-
- ///
- /// Provides the means to decode a spectral scan
- ///
- internal struct PdfJsScanDecoder
- {
- private byte[] markerBuffer;
-
- private int bitsData;
-
- private int bitsCount;
-
-#pragma warning disable 414
- private int bitsUnRead;
-
- private int accumulator;
-#pragma warning restore 414
-
- private int specStart;
-
- private int specEnd;
-
- private int eobrun;
-
- private int compIndex;
-
- private int successiveState;
-
- private int successiveACState;
-
- private int successiveACNextValue;
-
- private bool endOfStreamReached;
-
- private bool unexpectedMarkerReached;
-
- ///
- /// Decodes the spectral scan
- ///
- /// The image frame
- /// The input stream
- /// The DC Huffman tables
- /// The AC Huffman tables
- /// The scan components
- /// The component index within the array
- /// The length of the components. Different to the array length
- /// The reset interval
- /// The spectral selection start
- /// The spectral selection end
- /// The successive approximation bit high end
- /// The successive approximation bit low end
- public void DecodeScan(
- PdfJsFrame frame,
- Stream stream,
- PdfJsHuffmanTables dcHuffmanTables,
- PdfJsHuffmanTables acHuffmanTables,
- PdfJsFrameComponent[] components,
- int componentIndex,
- int componentsLength,
- ushort resetInterval,
- int spectralStart,
- int spectralEnd,
- int successivePrev,
- int successive)
- {
- this.markerBuffer = new byte[2];
- this.compIndex = componentIndex;
- this.specStart = spectralStart;
- this.specEnd = spectralEnd;
- this.successiveState = successive;
- this.endOfStreamReached = false;
- this.unexpectedMarkerReached = false;
-
- bool progressive = frame.Progressive;
- int mcusPerLine = frame.McusPerLine;
-
- int mcu = 0;
- int mcuExpected;
- if (componentsLength == 1)
- {
- mcuExpected = components[this.compIndex].BlocksPerLine * components[this.compIndex].BlocksPerColumn;
- }
- else
- {
- mcuExpected = mcusPerLine * frame.McusPerColumn;
- }
-
- PdfJsFileMarker fileMarker;
- while (mcu < mcuExpected)
- {
- // Reset interval stuff
- int mcuToRead = resetInterval != 0 ? Math.Min(mcuExpected - mcu, resetInterval) : mcuExpected;
- for (int i = 0; i < components.Length; i++)
- {
- ref PdfJsFrameComponent c = ref components[i];
- c.Pred = 0;
- }
-
- this.eobrun = 0;
-
- if (!progressive)
- {
- this.DecodeScanBaseline(dcHuffmanTables, acHuffmanTables, components, componentsLength, mcusPerLine, mcuToRead, ref mcu, stream);
- }
- else
- {
- if (this.specStart == 0)
- {
- if (successivePrev == 0)
- {
- this.DecodeScanDCFirst(dcHuffmanTables, components, componentsLength, mcusPerLine, mcuToRead, ref mcu, stream);
- }
- else
- {
- this.DecodeScanDCSuccessive(components, componentsLength, mcusPerLine, mcuToRead, ref mcu, stream);
- }
- }
- else
- {
- if (successivePrev == 0)
- {
- this.DecodeScanACFirst(acHuffmanTables, components, componentsLength, mcusPerLine, mcuToRead, ref mcu, stream);
- }
- else
- {
- this.DecodeScanACSuccessive(acHuffmanTables, components, componentsLength, mcusPerLine, mcuToRead, ref mcu, stream);
- }
- }
- }
-
- // Find marker
- this.bitsCount = 0;
- this.accumulator = 0;
- this.bitsUnRead = 0;
- fileMarker = PdfJsJpegDecoderCore.FindNextFileMarker(this.markerBuffer, stream);
-
- // Some bad images seem to pad Scan blocks with e.g. zero bytes, skip past
- // those to attempt to find a valid marker (fixes issue4090.pdf) in original code.
- if (fileMarker.Invalid)
- {
-#if DEBUG
- Debug.WriteLine($"DecodeScan - Unexpected MCU data at {stream.Position}, next marker is: {fileMarker.Marker:X}");
-#endif
- }
-
- ushort marker = fileMarker.Marker;
-
- // RSTn - We've alread read the bytes and altered the position so no need to skip
- if (marker >= PdfJsJpegConstants.Markers.RST0 && marker <= PdfJsJpegConstants.Markers.RST7)
- {
- continue;
- }
-
- if (!fileMarker.Invalid)
- {
- // We've found a valid marker.
- // Rewind the stream to the position of the marker and break
- stream.Position = fileMarker.Position;
- break;
- }
- }
-
- 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.
- if (fileMarker.Invalid)
- {
-#if DEBUG
- Debug.WriteLine($"DecodeScan - Unexpected MCU data at {stream.Position}, next marker is: {fileMarker.Marker:X}");
-#endif
- }
- else
- {
- // We've found a valid marker.
- // Rewind the stream to the position of the marker
- stream.Position = fileMarker.Position;
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int GetBlockBufferOffset(PdfJsFrameComponent component, int row, int col)
- {
- return 64 * (((component.BlocksPerLine + 1) * row) + col);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeScanBaseline(
- PdfJsHuffmanTables dcHuffmanTables,
- PdfJsHuffmanTables acHuffmanTables,
- PdfJsFrameComponent[] components,
- int componentsLength,
- int mcusPerLine,
- int mcuToRead,
- ref int mcu,
- Stream stream)
- {
- if (componentsLength == 1)
- {
- ref PdfJsFrameComponent component = ref components[this.compIndex];
- ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
- ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
-
- for (int n = 0; n < mcuToRead; n++)
- {
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- continue;
- }
-
- this.DecodeBlockBaseline(ref dcHuffmanTable, ref acHuffmanTable, ref component, mcu, stream);
- mcu++;
- }
- }
- else
- {
- for (int n = 0; n < mcuToRead; n++)
- {
- for (int i = 0; i < componentsLength; i++)
- {
- ref PdfJsFrameComponent component = ref components[i];
- ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
- ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
- int h = component.HorizontalFactor;
- int v = component.VerticalFactor;
-
- for (int j = 0; j < v; j++)
- {
- for (int k = 0; k < h; k++)
- {
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- continue;
- }
-
- this.DecodeMcuBaseline(ref dcHuffmanTable, ref acHuffmanTable, ref component, mcusPerLine, mcu, j, k, stream);
- }
- }
- }
-
- mcu++;
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeScanDCFirst(
- PdfJsHuffmanTables dcHuffmanTables,
- PdfJsFrameComponent[] components,
- int componentsLength,
- int mcusPerLine,
- int mcuToRead,
- ref int mcu,
- Stream stream)
- {
- if (componentsLength == 1)
- {
- ref PdfJsFrameComponent component = ref components[this.compIndex];
- ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
-
- for (int n = 0; n < mcuToRead; n++)
- {
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- continue;
- }
-
- this.DecodeBlockDCFirst(ref dcHuffmanTable, ref component, mcu, stream);
- mcu++;
- }
- }
- else
- {
- for (int n = 0; n < mcuToRead; n++)
- {
- for (int i = 0; i < componentsLength; i++)
- {
- ref PdfJsFrameComponent component = ref components[i];
- ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
- int h = component.HorizontalFactor;
- int v = component.VerticalFactor;
-
- for (int j = 0; j < v; j++)
- {
- for (int k = 0; k < h; k++)
- {
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- continue;
- }
-
- this.DecodeMcuDCFirst(ref dcHuffmanTable, ref component, mcusPerLine, mcu, j, k, stream);
- }
- }
- }
-
- mcu++;
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeScanDCSuccessive(
- PdfJsFrameComponent[] components,
- int componentsLength,
- int mcusPerLine,
- int mcuToRead,
- ref int mcu,
- Stream stream)
- {
- if (componentsLength == 1)
- {
- ref PdfJsFrameComponent component = ref components[this.compIndex];
- for (int n = 0; n < mcuToRead; n++)
- {
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- continue;
- }
-
- this.DecodeBlockDCSuccessive(ref component, mcu, stream);
- mcu++;
- }
- }
- else
- {
- for (int n = 0; n < mcuToRead; n++)
- {
- for (int i = 0; i < componentsLength; i++)
- {
- ref PdfJsFrameComponent component = ref components[i];
- int h = component.HorizontalFactor;
- int v = component.VerticalFactor;
- for (int j = 0; j < v; j++)
- {
- for (int k = 0; k < h; k++)
- {
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- continue;
- }
-
- this.DecodeMcuDCSuccessive(ref component, mcusPerLine, mcu, j, k, stream);
- }
- }
- }
-
- mcu++;
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeScanACFirst(
- PdfJsHuffmanTables acHuffmanTables,
- PdfJsFrameComponent[] components,
- int componentsLength,
- int mcusPerLine,
- int mcuToRead,
- ref int mcu,
- Stream stream)
- {
- if (componentsLength == 1)
- {
- ref PdfJsFrameComponent component = ref components[this.compIndex];
- ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
-
- for (int n = 0; n < mcuToRead; n++)
- {
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- continue;
- }
-
- this.DecodeBlockACFirst(ref acHuffmanTable, ref component, mcu, stream);
- mcu++;
- }
- }
- else
- {
- for (int n = 0; n < mcuToRead; n++)
- {
- for (int i = 0; i < componentsLength; i++)
- {
- ref PdfJsFrameComponent component = ref components[i];
- ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
- int h = component.HorizontalFactor;
- int v = component.VerticalFactor;
-
- for (int j = 0; j < v; j++)
- {
- for (int k = 0; k < h; k++)
- {
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- continue;
- }
-
- this.DecodeMcuACFirst(ref acHuffmanTable, ref component, mcusPerLine, mcu, j, k, stream);
- }
- }
- }
-
- mcu++;
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeScanACSuccessive(
- PdfJsHuffmanTables acHuffmanTables,
- PdfJsFrameComponent[] components,
- int componentsLength,
- int mcusPerLine,
- int mcuToRead,
- ref int mcu,
- Stream stream)
- {
- if (componentsLength == 1)
- {
- ref PdfJsFrameComponent component = ref components[this.compIndex];
- ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
-
- for (int n = 0; n < mcuToRead; n++)
- {
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- continue;
- }
-
- this.DecodeBlockACSuccessive(ref acHuffmanTable, ref component, mcu, stream);
- mcu++;
- }
- }
- else
- {
- for (int n = 0; n < mcuToRead; n++)
- {
- for (int i = 0; i < componentsLength; i++)
- {
- ref PdfJsFrameComponent component = ref components[i];
- ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
- int h = component.HorizontalFactor;
- int v = component.VerticalFactor;
-
- for (int j = 0; j < v; j++)
- {
- for (int k = 0; k < h; k++)
- {
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- continue;
- }
-
- this.DecodeMcuACSuccessive(ref acHuffmanTable, ref component, mcusPerLine, mcu, j, k, stream);
- }
- }
- }
-
- mcu++;
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeBlockBaseline(ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, ref PdfJsFrameComponent component, int mcu, Stream stream)
- {
- int blockRow = mcu / component.BlocksPerLine;
- int blockCol = mcu % component.BlocksPerLine;
- int offset = GetBlockBufferOffset(component, blockRow, blockCol);
- this.DecodeBaseline(ref component, offset, ref dcHuffmanTable, ref acHuffmanTable, stream);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeMcuBaseline(ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, ref PdfJsFrameComponent component, int mcusPerLine, int mcu, int row, int col, Stream stream)
- {
- int mcuRow = mcu / mcusPerLine;
- int mcuCol = mcu % mcusPerLine;
- int blockRow = (mcuRow * component.VerticalFactor) + row;
- int blockCol = (mcuCol * component.HorizontalFactor) + col;
- int offset = GetBlockBufferOffset(component, blockRow, blockCol);
- this.DecodeBaseline(ref component, offset, ref dcHuffmanTable, ref acHuffmanTable, stream);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeBlockDCFirst(ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsFrameComponent component, int mcu, Stream stream)
- {
- int blockRow = mcu / component.BlocksPerLine;
- int blockCol = mcu % component.BlocksPerLine;
- int offset = GetBlockBufferOffset(component, blockRow, blockCol);
- this.DecodeDCFirst(ref component, offset, ref dcHuffmanTable, stream);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeMcuDCFirst(ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsFrameComponent component, int mcusPerLine, int mcu, int row, int col, Stream stream)
- {
- int mcuRow = mcu / mcusPerLine;
- int mcuCol = mcu % mcusPerLine;
- int blockRow = (mcuRow * component.VerticalFactor) + row;
- int blockCol = (mcuCol * component.HorizontalFactor) + col;
- int offset = GetBlockBufferOffset(component, blockRow, blockCol);
- this.DecodeDCFirst(ref component, offset, ref dcHuffmanTable, stream);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeBlockDCSuccessive(ref PdfJsFrameComponent component, int mcu, Stream stream)
- {
- int blockRow = mcu / component.BlocksPerLine;
- int blockCol = mcu % component.BlocksPerLine;
- int offset = GetBlockBufferOffset(component, blockRow, blockCol);
- this.DecodeDCSuccessive(ref component, offset, stream);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeMcuDCSuccessive(ref PdfJsFrameComponent component, int mcusPerLine, int mcu, int row, int col, Stream stream)
- {
- int mcuRow = mcu / mcusPerLine;
- int mcuCol = mcu % mcusPerLine;
- int blockRow = (mcuRow * component.VerticalFactor) + row;
- int blockCol = (mcuCol * component.HorizontalFactor) + col;
- int offset = GetBlockBufferOffset(component, blockRow, blockCol);
- this.DecodeDCSuccessive(ref component, offset, stream);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeBlockACFirst(ref PdfJsHuffmanTable acHuffmanTable, ref PdfJsFrameComponent component, int mcu, Stream stream)
- {
- int blockRow = mcu / component.BlocksPerLine;
- int blockCol = mcu % component.BlocksPerLine;
- int offset = GetBlockBufferOffset(component, blockRow, blockCol);
- this.DecodeACFirst(ref component, offset, ref acHuffmanTable, stream);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeMcuACFirst(ref PdfJsHuffmanTable acHuffmanTable, ref PdfJsFrameComponent component, int mcusPerLine, int mcu, int row, int col, Stream stream)
- {
- int mcuRow = mcu / mcusPerLine;
- int mcuCol = mcu % mcusPerLine;
- int blockRow = (mcuRow * component.VerticalFactor) + row;
- int blockCol = (mcuCol * component.HorizontalFactor) + col;
- int offset = GetBlockBufferOffset(component, blockRow, blockCol);
- this.DecodeACFirst(ref component, offset, ref acHuffmanTable, stream);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeBlockACSuccessive(ref PdfJsHuffmanTable acHuffmanTable, ref PdfJsFrameComponent component, int mcu, Stream stream)
- {
- int blockRow = mcu / component.BlocksPerLine;
- int blockCol = mcu % component.BlocksPerLine;
- int offset = GetBlockBufferOffset(component, blockRow, blockCol);
- this.DecodeACSuccessive(ref component, offset, ref acHuffmanTable, stream);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeMcuACSuccessive(ref PdfJsHuffmanTable acHuffmanTable, ref PdfJsFrameComponent component, int mcusPerLine, int mcu, int row, int col, Stream stream)
- {
- int mcuRow = mcu / mcusPerLine;
- int mcuCol = mcu % mcusPerLine;
- int blockRow = (mcuRow * component.VerticalFactor) + row;
- int blockCol = (mcuCol * component.HorizontalFactor) + col;
- int offset = GetBlockBufferOffset(component, blockRow, blockCol);
- this.DecodeACSuccessive(ref component, offset, ref acHuffmanTable, stream);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private int ReadBit(Stream stream)
- {
- // TODO: I wonder if we can do this two bytes at a time; libjpeg turbo seems to do that?
- if (this.bitsCount > 0)
- {
- this.bitsCount--;
- return (this.bitsData >> this.bitsCount) & 1;
- }
-
- this.bitsData = stream.ReadByte();
-
- if (this.bitsData == -0x1)
- {
- // We've encountered the end of the file stream which means there's no EOI marker in the image
- this.endOfStreamReached = true;
- }
-
- if (this.bitsData == PdfJsJpegConstants.Markers.Prefix)
- {
- int nextByte = stream.ReadByte();
- if (nextByte != 0)
- {
-#if DEBUG
- Debug.WriteLine($"DecodeScan - Unexpected marker {(this.bitsData << 8) | nextByte:X} at {stream.Position}");
-#endif
-
- // We've encountered an unexpected marker. Reverse the stream and exit.
- this.unexpectedMarkerReached = true;
- stream.Position -= 2;
- }
-
- // Unstuff 0
- }
-
- this.bitsCount = 7;
-
- return this.bitsData >> 7;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private short DecodeHuffman(ref PdfJsHuffmanTable tree, Stream stream)
- {
- short code = -1;
-
- // 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
- // using 3 methods: FillBits, PeekBits, and ReadBits. We should attempt to do the same.
- // It doesn't appear to speed anything up either.
- // if (this.bitsUnRead < 8)
- // {
- // 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);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- return -1;
- }
- }
-
- // "DECODE", section F.2.2.3, figure F.16, page 109 of T.81
- int i = 1;
-
- while (code > tree.MaxCode[i])
- {
- code <<= 1;
- code |= (short)this.ReadBit(stream);
-
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- return -1;
- }
-
- i++;
- }
-
- int j = tree.ValOffset[i];
- return tree.HuffVal[(j + code) & 0xFF];
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private int Receive(int length, Stream stream)
- {
- int n = 0;
- while (length > 0)
- {
- int bit = this.ReadBit(stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- return -1;
- }
-
- n = (n << 1) | bit;
- length--;
- }
-
- return n;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private int ReceiveAndExtend(int length, Stream stream)
- {
- if (length == 1)
- {
- return this.ReadBit(stream) == 1 ? 1 : -1;
- }
-
- int n = this.Receive(length, stream);
- if (n >= 1 << (length - 1))
- {
- return n;
- }
-
- return n + (-1 << length) + 1;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeBaseline(ref PdfJsFrameComponent component, int offset, ref PdfJsHuffmanTable dcHuffmanTable, ref PdfJsHuffmanTable acHuffmanTable, Stream stream)
- {
- int t = this.DecodeHuffman(ref dcHuffmanTable, stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- return;
- }
-
- int diff = t == 0 ? 0 : this.ReceiveAndExtend(t, stream);
- component.BlockData[offset] = (short)(component.Pred += diff);
-
- int k = 1;
- while (k < 64)
- {
- int rs = this.DecodeHuffman(ref acHuffmanTable, stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- return;
- }
-
- int s = rs & 15;
- int r = rs >> 4;
-
- if (s == 0)
- {
- if (r < 15)
- {
- break;
- }
-
- k += 16;
- continue;
- }
-
- k += r;
-
- if (k > 63)
- {
- break;
- }
-
- byte z = PdfJsQuantizationTables.DctZigZag[k];
- short re = (short)this.ReceiveAndExtend(s, stream);
- component.BlockData[offset + z] = re;
- k++;
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeDCFirst(ref PdfJsFrameComponent component, int offset, ref PdfJsHuffmanTable dcHuffmanTable, Stream stream)
- {
- int t = this.DecodeHuffman(ref dcHuffmanTable, stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- return;
- }
-
- int diff = t == 0 ? 0 : this.ReceiveAndExtend(t, stream) << this.successiveState;
- component.BlockData[offset] = (short)(component.Pred += diff);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeDCSuccessive(ref PdfJsFrameComponent component, int offset, Stream stream)
- {
- int bit = this.ReadBit(stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- return;
- }
-
- component.BlockData[offset] |= (short)(bit << this.successiveState);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeACFirst(ref PdfJsFrameComponent component, int offset, ref PdfJsHuffmanTable acHuffmanTable, Stream stream)
- {
- if (this.eobrun > 0)
- {
- this.eobrun--;
- return;
- }
-
- Span componentBlockDataSpan = component.BlockData.Span;
- int k = this.specStart;
- int e = this.specEnd;
- while (k <= e)
- {
- short rs = this.DecodeHuffman(ref acHuffmanTable, stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- return;
- }
-
- int s = rs & 15;
- int r = rs >> 4;
-
- if (s == 0)
- {
- if (r < 15)
- {
- this.eobrun = this.Receive(r, stream) + (1 << r) - 1;
- break;
- }
-
- k += 16;
- continue;
- }
-
- k += r;
- byte z = PdfJsQuantizationTables.DctZigZag[k];
- componentBlockDataSpan[offset + z] = (short)(this.ReceiveAndExtend(s, stream) * (1 << this.successiveState));
- k++;
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecodeACSuccessive(ref PdfJsFrameComponent component, int offset, ref PdfJsHuffmanTable acHuffmanTable, Stream stream)
- {
- int k = this.specStart;
- int e = this.specEnd;
- int r = 0;
- Span componentBlockDataSpan = component.BlockData.Span;
- while (k <= e)
- {
- byte z = PdfJsQuantizationTables.DctZigZag[k];
- switch (this.successiveACState)
- {
- case 0: // Initial state
- short rs = this.DecodeHuffman(ref acHuffmanTable, stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- return;
- }
-
- int s = rs & 15;
- r = rs >> 4;
- if (s == 0)
- {
- if (r < 15)
- {
- this.eobrun = this.Receive(r, stream) + (1 << r);
- this.successiveACState = 4;
- }
- else
- {
- r = 16;
- this.successiveACState = 1;
- }
- }
- else
- {
- if (s != 1)
- {
- throw new ImageFormatException("Invalid ACn encoding");
- }
-
- this.successiveACNextValue = this.ReceiveAndExtend(s, stream);
- this.successiveACState = r > 0 ? 2 : 3;
- }
-
- continue;
- case 1: // Skipping r zero items
- case 2:
- if (componentBlockDataSpan[offset + z] != 0)
- {
- int bit = this.ReadBit(stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- return;
- }
-
- componentBlockDataSpan[offset + z] += (short)(bit << this.successiveState);
- }
- else
- {
- r--;
- if (r == 0)
- {
- this.successiveACState = this.successiveACState == 2 ? 3 : 0;
- }
- }
-
- break;
- case 3: // Set value for a zero item
- if (componentBlockDataSpan[offset + z] != 0)
- {
- int bit = this.ReadBit(stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- return;
- }
-
- componentBlockDataSpan[offset + z] += (short)(bit << this.successiveState);
- }
- else
- {
- componentBlockDataSpan[offset + z] = (short)(this.successiveACNextValue << this.successiveState);
- this.successiveACState = 0;
- }
-
- break;
- case 4: // Eob
- if (componentBlockDataSpan[offset + z] != 0)
- {
- int bit = this.ReadBit(stream);
- if (this.endOfStreamReached || this.unexpectedMarkerReached)
- {
- return;
- }
-
- componentBlockDataSpan[offset + z] += (short)(bit << this.successiveState);
- }
-
- break;
- }
-
- k++;
- }
-
- if (this.successiveACState == 4)
- {
- this.eobrun--;
- if (this.eobrun == 0)
- {
- this.successiveACState = 0;
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsYCbCrToRgbTables.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsYCbCrToRgbTables.cs
deleted file mode 100644
index 07c8f9830..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsYCbCrToRgbTables.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-namespace ImageSharp.Formats.Jpeg.PdfJsPort.Components
-{
- using System.Runtime.CompilerServices;
- using ImageSharp.PixelFormats;
-
- ///
- /// Provides 8-bit lookup tables for converting from YCbCr to Rgb colorspace.
- /// Methods to build the tables are based on libjpeg implementation.
- ///
- internal struct PdfJsYCbCrToRgbTables
- {
- ///
- /// The red red-chrominance table
- ///
- public static int[] CrRTable = new int[256];
-
- ///
- /// The blue blue-chrominance table
- ///
- public static int[] CbBTable = new int[256];
-
- ///
- /// The green red-chrominance table
- ///
- public static int[] CrGTable = new int[256];
-
- ///
- /// The green blue-chrominance table
- ///
- public static int[] CbGTable = new int[256];
-
- // Speediest right-shift on some machines and gives us enough accuracy at 4 decimal places.
- private const int ScaleBits = 16;
-
- private const int Half = 1 << (ScaleBits - 1);
-
- private const int MinSample = 0;
-
- private const int HalfSample = 128;
-
- private const int MaxSample = 255;
-
- ///
- /// Initializes the YCbCr tables
- ///
- public static void Create()
- {
- for (int i = 0, x = -128; i <= 255; i++, x++)
- {
- // i is the actual input pixel value, in the range 0..255
- // The Cb or Cr value we are thinking of is x = i - 128
- // Cr=>R value is nearest int to 1.402 * x
- CrRTable[i] = RightShift((Fix(1.402F) * x) + Half);
-
- // Cb=>B value is nearest int to 1.772 * x
- CbBTable[i] = RightShift((Fix(1.772F) * x) + Half);
-
- // Cr=>G value is scaled-up -0.714136286
- CrGTable[i] = (-Fix(0.714136286F)) * x;
-
- // Cb => G value is scaled - up - 0.344136286 * x
- // We also add in Half so that need not do it in inner loop
- CbGTable[i] = ((-Fix(0.344136286F)) * x) + Half;
- }
- }
-
- ///
- /// Optimized method to pack bytes to the image from the YCbCr color space.
- ///
- /// The pixel format.
- /// The packed pixel.
- /// The y luminance component.
- /// The cb chroma component.
- /// The cr chroma component.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void PackYCbCr(ref TPixel packed, byte y, byte cb, byte cr)
- where TPixel : struct, IPixel
- {
- byte r = (byte)(y + CrRTable[cr]).Clamp(0, 255);
-
- // The values for the G calculation are left scaled up, since we must add them together before rounding.
- byte g = (byte)(y + RightShift(CbGTable[cb] + CrGTable[cr])).Clamp(0, 255);
-
- byte b = (byte)(y + CbBTable[cb]).Clamp(0, 255);
-
- packed.PackFromRgba32(new Rgba32(r, g, b, 255));
- }
-
- ///
- /// Optimized method to pack bytes to the image from the YccK color space.
- ///
- /// The pixel format.
- /// The packed pixel.
- /// The y luminance component.
- /// The cb chroma component.
- /// The cr chroma component.
- /// The keyline component.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void PackYccK(ref TPixel packed, byte y, byte cb, byte cr, byte k)
- where TPixel : struct, IPixel
- {
- int c = (MaxSample - (y + CrRTable[cr])).Clamp(0, 255);
-
- // The values for the G calculation are left scaled up, since we must add them together before rounding.
- int m = (MaxSample - (y + RightShift(CbGTable[cb] + CrGTable[cr]))).Clamp(0, 255);
-
- int cy = (MaxSample - (y + CbBTable[cb])).Clamp(0, 255);
-
- byte r = (byte)((c * k) / MaxSample);
- byte g = (byte)((m * k) / MaxSample);
- byte b = (byte)((cy * k) / MaxSample);
-
- packed.PackFromRgba32(new Rgba32(r, g, b, MaxSample));
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int Fix(float x)
- {
- return (int)((x * (1L << ScaleBits)) + 0.5F);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int RightShift(int x)
- {
- return x >> ScaleBits;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegConstants.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegConstants.cs
deleted file mode 100644
index 8b3765e6c..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegConstants.cs
+++ /dev/null
@@ -1,359 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-// ReSharper disable InconsistentNaming
-namespace ImageSharp.Formats.Jpeg.PdfJsPort
-{
- ///
- /// Contains jpeg constant values
- ///
- internal static class PdfJsJpegConstants
- {
- ///
- /// Contains marker specific constants
- ///
- public static class Markers
- {
- ///
- /// The prefix used for all markers.
- ///
- public const byte Prefix = 0xFF;
-
- ///
- /// The Start of Image marker
- ///
- public const ushort SOI = 0xFFD8;
-
- ///
- /// The End of Image marker
- ///
- public const ushort EOI = 0xFFD9;
-
- ///
- /// Application specific marker for marking the jpeg format.
- ///
- ///
- public const ushort APP0 = 0xFFE0;
-
- ///
- /// Application specific marker for marking where to store metadata.
- ///
- public const ushort APP1 = 0xFFE1;
-
- ///
- /// Application specific marker for marking where to store ICC profile information.
- ///
- public const ushort APP2 = 0xFFE2;
-
- ///
- /// Application specific marker.
- ///
- public const ushort APP3 = 0xFFE3;
-
- ///
- /// Application specific marker.
- ///
- public const ushort APP4 = 0xFFE4;
-
- ///
- /// Application specific marker.
- ///
- public const ushort APP5 = 0xFFE5;
-
- ///
- /// Application specific marker.
- ///
- public const ushort APP6 = 0xFFE6;
-
- ///
- /// Application specific marker.
- ///
- public const ushort APP7 = 0xFFE7;
-
- ///
- /// Application specific marker.
- ///
- public const ushort APP8 = 0xFFE8;
-
- ///
- /// Application specific marker.
- ///
- public const ushort APP9 = 0xFFE9;
-
- ///
- /// Application specific marker.
- ///
- public const ushort APP10 = 0xFFEA;
-
- ///
- /// Application specific marker.
- ///
- public const ushort APP11 = 0xFFEB;
-
- ///
- /// Application specific marker.
- ///
- public const ushort APP12 = 0xFFEC;
-
- ///
- /// Application specific marker.
- ///
- public const ushort APP13 = 0xFFED;
-
- ///
- /// Application specific marker used by Adobe for storing encoding information for DCT filters.
- ///
- public const ushort APP14 = 0xFFEE;
-
- ///
- /// Application specific marker used by GraphicConverter to store JPEG quality.
- ///
- public const ushort APP15 = 0xFFEF;
-
- ///
- /// The text comment marker
- ///
- public const ushort COM = 0xFFFE;
-
- ///
- /// Define Quantization Table(s) marker
- ///
- /// Specifies one or more quantization tables.
- ///
- ///
- public const ushort DQT = 0xFFDB;
-
- ///
- /// Start of Frame (baseline DCT)
- ///
- /// Indicates that this is a baseline DCT-based JPEG, and specifies the width, height, number of components,
- /// and component subsampling (e.g., 4:2:0).
- ///
- ///
- public const ushort SOF0 = 0xFFC0;
-
- ///
- /// Start Of Frame (Extended Sequential DCT)
- ///
- /// Indicates that this is a progressive DCT-based JPEG, and specifies the width, height, number of components,
- /// and component subsampling (e.g., 4:2:0).
- ///
- ///
- public const ushort SOF1 = 0xFFC1;
-
- ///
- /// Start Of Frame (progressive DCT)
- ///
- /// Indicates that this is a progressive DCT-based JPEG, and specifies the width, height, number of components,
- /// and component subsampling (e.g., 4:2:0).
- ///
- ///
- public const ushort SOF2 = 0xFFC2;
-
- ///
- /// Define Huffman Table(s)
- ///
- /// Specifies one or more Huffman tables.
- ///
- ///
- public const ushort DHT = 0xFFC4;
-
- ///
- /// Define Restart Interval
- ///
- /// Specifies the interval between RSTn markers, in macroblocks.This marker is followed by two bytes indicating the fixed size so it can be treated like any other variable size segment.
- ///
- ///
- public const ushort DRI = 0xFFDD;
-
- ///
- /// Start of Scan
- ///
- /// Begins a top-to-bottom scan of the image. In baseline DCT JPEG images, there is generally a single scan.
- /// Progressive DCT JPEG images usually contain multiple scans. This marker specifies which slice of data it
- /// will contain, and is immediately followed by entropy-coded data.
- ///
- ///
- public const ushort SOS = 0xFFDA;
-
- ///
- /// Define First Restart
- ///
- /// Inserted every r macroblocks, where r is the restart interval set by a DRI marker.
- /// Not used if there was no DRI marker. The low three bits of the marker code cycle in value from 0 to 7.
- ///
- ///
- public const ushort RST0 = 0xFFD0;
-
- ///
- /// Define Eigth Restart
- ///
- /// Inserted every r macroblocks, where r is the restart interval set by a DRI marker.
- /// Not used if there was no DRI marker. The low three bits of the marker code cycle in value from 0 to 7.
- ///
- ///
- public const ushort RST7 = 0xFFD7;
-
- ///
- /// Contains JFIF specific markers
- ///
- public static class JFif
- {
- ///
- /// Represents J in ASCII
- ///
- public const byte J = 0x4A;
-
- ///
- /// Represents F in ASCII
- ///
- public const byte F = 0x46;
-
- ///
- /// Represents I in ASCII
- ///
- public const byte I = 0x49;
-
- ///
- /// Represents the null "0" marker
- ///
- public const byte Null = 0x0;
- }
-
- ///
- /// Contains Adobe specific markers
- ///
- public static class Adobe
- {
- ///
- /// Represents A in ASCII
- ///
- public const byte A = 0x41;
-
- ///
- /// Represents d in ASCII
- ///
- public const byte D = 0x64;
-
- ///
- /// Represents b in ASCII
- ///
- public const byte O = 0x6F;
-
- ///
- /// Represents b in ASCII
- ///
- public const byte B = 0x62;
-
- ///
- /// Represents e in ASCII
- ///
- public const byte E = 0x65;
-
- ///
- /// The color transform is unknown.(RGB or CMYK)
- ///
- public const byte ColorTransformUnknown = 0;
-
- ///
- /// The color transform is YCbCr (luminance, red chroma, blue chroma)
- ///
- public const byte ColorTransformYCbCr = 1;
-
- ///
- /// The color transform is YCCK (luminance, red chroma, blue chroma, keyline)
- ///
- public const byte ColorTransformYcck = 2;
- }
-
- ///
- /// Contains EXIF specific markers
- ///
- public static class Exif
- {
- ///
- /// Represents E in ASCII
- ///
- public const byte E = 0x45;
-
- ///
- /// Represents x in ASCII
- ///
- public const byte X = 0x78;
-
- ///
- /// Represents i in ASCII
- ///
- public const byte I = 0x69;
-
- ///
- /// Represents f in ASCII
- ///
- public const byte F = 0x66;
-
- ///
- /// Represents the null "0" marker
- ///
- public const byte Null = 0x0;
- }
-
- ///
- /// Contains ICC specific markers
- ///
- public static class ICC
- {
- ///
- /// Represents I in ASCII
- ///
- public const byte I = 0x49;
-
- ///
- /// Represents C in ASCII
- ///
- public const byte C = 0x43;
-
- ///
- /// Represents _ in ASCII
- ///
- public const byte UnderScore = 0x5F;
-
- ///
- /// Represents P in ASCII
- ///
- public const byte P = 0x50;
-
- ///
- /// Represents R in ASCII
- ///
- public const byte R = 0x52;
-
- ///
- /// Represents O in ASCII
- ///
- public const byte O = 0x4F;
-
- ///
- /// Represents F in ASCII
- ///
- public const byte F = 0x46;
-
- ///
- /// Represents L in ASCII
- ///
- public const byte L = 0x4C;
-
- ///
- /// Represents E in ASCII
- ///
- public const byte E = 0x45;
-
- ///
- /// Represents the null "0" marker
- ///
- public const byte Null = 0x0;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoder.cs
deleted file mode 100644
index 25f739704..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoder.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-namespace ImageSharp.Formats.Jpeg.PdfJsPort
-{
- using System;
- using System.IO;
-
- using ImageSharp.PixelFormats;
-
- internal sealed class PdfJsJpegDecoder : IImageDecoder, IJpegDecoderOptions
- {
- public bool IgnoreMetadata { get; set; }
-
- public Image Decode(Configuration configuration, Stream stream)
- where TPixel : struct, IPixel
- {
- using (var decoder = new PdfJsJpegDecoderCore(configuration, this))
- {
- return decoder.Decode(stream);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
deleted file mode 100644
index ce90f0104..000000000
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
+++ /dev/null
@@ -1,985 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Formats.Jpeg.PdfJsPort
-{
- using System;
- using System.IO;
- using System.Runtime.CompilerServices;
-
- using ImageSharp.Formats.Jpeg.PdfJsPort.Components;
- using ImageSharp.Memory;
- using ImageSharp.PixelFormats;
-
- ///
- /// Performs the jpeg decoding operation.
- /// Ported from with additional fixes to handle common encoding errors
- ///
- internal sealed class PdfJsJpegDecoderCore : IDisposable
- {
- ///
- /// The global configuration
- ///
- private readonly Configuration configuration;
-
- ///
- /// Gets the temporary buffer used to store bytes read from the stream.
- ///
- private readonly byte[] temp = new byte[2 * 16 * 4];
-
- private readonly byte[] markerBuffer = new byte[2];
-
- private PdfJsQuantizationTables quantizationTables;
-
- private PdfJsHuffmanTables dcHuffmanTables;
-
- private PdfJsHuffmanTables acHuffmanTables;
-
- private PdfJsFrame frame;
-
- private PdfJsComponentBlocks components;
-
- private PdfJsJpegPixelArea pixelArea;
-
- private ushort resetInterval;
-
- private int imageWidth;
-
- private int imageHeight;
-
- private int numberOfComponents;
-
- ///
- /// Whether the image has a EXIF header
- ///
- private bool isExif;
-
- ///
- /// Contains information about the JFIF marker
- ///
- private PdfJsJFif jFif;
-
- ///
- /// Contains information about the Adobe marker
- ///
- private PdfJsAdobe adobe;
-
- ///
- /// Initializes static members of the class.
- ///
- static PdfJsJpegDecoderCore()
- {
- PdfJsYCbCrToRgbTables.Create();
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The configuration.
- /// The options.
- public PdfJsJpegDecoderCore(Configuration configuration, IJpegDecoderOptions options)
- {
- this.configuration = configuration ?? Configuration.Default;
- this.IgnoreMetadata = options.IgnoreMetadata;
- }
-
- ///
- /// Gets the input stream.
- ///
- public Stream InputStream { get; private set; }
-
- ///
- /// Gets a value indicating whether the metadata should be ignored when the image is being decoded.
- ///
- public bool IgnoreMetadata { get; }
-
- ///
- /// Finds the next file marker within the byte stream.
- ///
- /// The buffer to read file markers to
- /// The input stream
- /// The
- public static PdfJsFileMarker FindNextFileMarker(byte[] marker, Stream stream)
- {
- int value = stream.Read(marker, 0, 2);
-
- if (value == 0)
- {
- return new PdfJsFileMarker(PdfJsJpegConstants.Markers.EOI, (int)stream.Length - 2);
- }
-
- if (marker[0] == PdfJsJpegConstants.Markers.Prefix)
- {
- // According to Section B.1.1.2:
- // "Any marker may optionally be preceded by any number of fill bytes, which are bytes assigned code 0xFF."
- while (marker[1] == PdfJsJpegConstants.Markers.Prefix)
- {
- int suffix = stream.ReadByte();
- if (suffix == -1)
- {
- return new PdfJsFileMarker(PdfJsJpegConstants.Markers.EOI, (int)stream.Length - 2);
- }
-
- marker[1] = (byte)value;
- }
-
- return new PdfJsFileMarker((ushort)((marker[0] << 8) | marker[1]), (int)(stream.Position - 2));
- }
-
- return new PdfJsFileMarker((ushort)((marker[0] << 8) | marker[1]), (int)(stream.Position - 2), true);
- }
-
- ///
- /// Decodes the image from the specified and sets the data to image.
- ///
- /// The pixel format.
- /// The stream, where the image should be.
- /// The decoded image.
- public Image Decode(Stream stream)
- where TPixel : struct, IPixel
- {
- this.InputStream = stream;
-
- var metadata = new ImageMetaData();
- this.ParseStream(metadata, false);
-
- var image = new Image(this.configuration, this.imageWidth, this.imageHeight, metadata);
- this.FillPixelData(image);
- this.AssignResolution(image);
- return image;
- }
-
- ///
- public void Dispose()
- {
- this.frame?.Dispose();
- this.components?.Dispose();
- this.quantizationTables?.Dispose();
- this.dcHuffmanTables?.Dispose();
- this.acHuffmanTables?.Dispose();
- this.pixelArea.Dispose();
-
- // Set large fields to null.
- this.frame = null;
- this.components = null;
- this.quantizationTables = null;
- this.dcHuffmanTables = null;
- this.acHuffmanTables = null;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int GetBlockBufferOffset(ref PdfJsComponent component, int row, int col)
- {
- return 64 * (((component.BlocksPerLine + 1) * row) + col);
- }
-
- ///
- /// Parses the input stream for file markers
- ///
- /// Contains the metadata for an image
- /// Whether to decode metadata only.
- private void ParseStream(ImageMetaData metaData, bool metadataOnly)
- {
- // TODO: metadata only logic
- // Check for the Start Of Image marker.
- var fileMarker = new PdfJsFileMarker(this.ReadUint16(), 0);
- if (fileMarker.Marker != PdfJsJpegConstants.Markers.SOI)
- {
- throw new ImageFormatException("Missing SOI marker.");
- }
-
- ushort marker = this.ReadUint16();
- fileMarker = new PdfJsFileMarker(marker, (int)this.InputStream.Position - 2);
-
- this.quantizationTables = new PdfJsQuantizationTables();
- this.dcHuffmanTables = new PdfJsHuffmanTables();
- this.acHuffmanTables = new PdfJsHuffmanTables();
-
- while (fileMarker.Marker != PdfJsJpegConstants.Markers.EOI)
- {
- // Get the marker length
- int remaining = this.ReadUint16() - 2;
-
- switch (fileMarker.Marker)
- {
- case PdfJsJpegConstants.Markers.APP0:
- this.ProcessApplicationHeaderMarker(remaining);
- break;
-
- case PdfJsJpegConstants.Markers.APP1:
- this.ProcessApp1Marker(remaining, metaData);
- break;
-
- case PdfJsJpegConstants.Markers.APP2:
- this.ProcessApp2Marker(remaining, metaData);
- break;
- case PdfJsJpegConstants.Markers.APP3:
- case PdfJsJpegConstants.Markers.APP4:
- case PdfJsJpegConstants.Markers.APP5:
- case PdfJsJpegConstants.Markers.APP6:
- case PdfJsJpegConstants.Markers.APP7:
- case PdfJsJpegConstants.Markers.APP8:
- case PdfJsJpegConstants.Markers.APP9:
- case PdfJsJpegConstants.Markers.APP10:
- case PdfJsJpegConstants.Markers.APP11:
- case PdfJsJpegConstants.Markers.APP12:
- case PdfJsJpegConstants.Markers.APP13:
- this.InputStream.Skip(remaining);
- break;
-
- case PdfJsJpegConstants.Markers.APP14:
- this.ProcessApp14Marker(remaining);
- break;
-
- case PdfJsJpegConstants.Markers.APP15:
- case PdfJsJpegConstants.Markers.COM:
- this.InputStream.Skip(remaining);
- break;
-
- case PdfJsJpegConstants.Markers.DQT:
- this.ProcessDefineQuantizationTablesMarker(remaining);
- break;
-
- case PdfJsJpegConstants.Markers.SOF0:
- case PdfJsJpegConstants.Markers.SOF1:
- case PdfJsJpegConstants.Markers.SOF2:
- this.ProcessStartOfFrameMarker(remaining, fileMarker);
- break;
-
- case PdfJsJpegConstants.Markers.DHT:
- this.ProcessDefineHuffmanTablesMarker(remaining);
- break;
-
- case PdfJsJpegConstants.Markers.DRI:
- this.ProcessDefineRestartIntervalMarker(remaining);
- break;
-
- case PdfJsJpegConstants.Markers.SOS:
- this.ProcessStartOfScanMarker();
- break;
- }
-
- // Read on.
- fileMarker = FindNextFileMarker(this.markerBuffer, this.InputStream);
- }
-
- this.imageWidth = this.frame.SamplesPerLine;
- this.imageHeight = this.frame.Scanlines;
- this.components = new PdfJsComponentBlocks { Components = new PdfJsComponent[this.frame.ComponentCount] };
-
- for (int i = 0; i < this.components.Components.Length; i++)
- {
- ref var frameComponent = ref this.frame.Components[i];
- var component = new PdfJsComponent
- {
- Scale = new System.Numerics.Vector2(
- frameComponent.HorizontalFactor / (float)this.frame.MaxHorizontalFactor,
- frameComponent.VerticalFactor / (float)this.frame.MaxVerticalFactor),
- BlocksPerLine = frameComponent.BlocksPerLine,
- BlocksPerColumn = frameComponent.BlocksPerColumn
- };
-
- this.BuildComponentData(ref component, ref frameComponent);
- this.components.Components[i] = component;
- }
-
- this.numberOfComponents = this.components.Components.Length;
- }
-
- ///
- /// Fills the given image with the color data
- ///
- /// The pixel format.
- /// The image
- private void FillPixelData(Image image)
- where TPixel : struct, IPixel
- {
- if (this.numberOfComponents > 4)
- {
- throw new ImageFormatException(
- $"Unsupported color mode. Max components 4; found {this.numberOfComponents}");
- }
-
- this.pixelArea = new PdfJsJpegPixelArea(image.Width, image.Height, this.numberOfComponents);
- this.pixelArea.LinearizeBlockData(this.components, image.Width, image.Height);
-
- if (this.numberOfComponents == 1)
- {
- this.FillGrayScaleImage(image);
- return;
- }
-
- if (this.numberOfComponents == 3)
- {
- if (this.adobe.Equals(default(PdfJsAdobe))
- || this.adobe.ColorTransform == PdfJsJpegConstants.Markers.Adobe.ColorTransformYCbCr)
- {
- this.FillYCbCrImage(image);
- }
- else if (this.adobe.ColorTransform == PdfJsJpegConstants.Markers.Adobe.ColorTransformUnknown)
- {
- this.FillRgbImage(image);
- }
- }
-
- if (this.numberOfComponents == 4)
- {
- if (this.adobe.ColorTransform == PdfJsJpegConstants.Markers.Adobe.ColorTransformYcck)
- {
- this.FillYcckImage(image);
- }
- else
- {
- this.FillCmykImage(image);
- }
- }
- }
-
- ///
- /// Assigns the horizontal and vertical resolution to the image if it has a JFIF header or EXIF metadata.
- ///
- /// The pixel format.
- /// The image to assign the resolution to.
- private void AssignResolution(Image image)
- where TPixel : struct, IPixel
- {
- if (this.isExif)
- {
- ExifValue horizontal = image.MetaData.ExifProfile.GetValue(ExifTag.XResolution);
- ExifValue vertical = image.MetaData.ExifProfile.GetValue(ExifTag.YResolution);
- double horizontalValue = horizontal != null ? ((Rational)horizontal.Value).ToDouble() : 0;
- double verticalValue = vertical != null ? ((Rational)vertical.Value).ToDouble() : 0;
-
- if (horizontalValue > 0 && verticalValue > 0)
- {
- image.MetaData.HorizontalResolution = horizontalValue;
- image.MetaData.VerticalResolution = verticalValue;
- }
- }
- else if (this.jFif.XDensity > 0 && this.jFif.YDensity > 0)
- {
- image.MetaData.HorizontalResolution = this.jFif.XDensity;
- image.MetaData.VerticalResolution = this.jFif.YDensity;
- }
- }
-
- ///
- /// Processes the application header containing the JFIF identifier plus extra data.
- ///
- /// The remaining bytes in the segment block.
- private void ProcessApplicationHeaderMarker(int remaining)
- {
- if (remaining < 5)
- {
- // Skip the application header length
- this.InputStream.Skip(remaining);
- return;
- }
-
- this.InputStream.Read(this.temp, 0, 13);
- remaining -= 13;
-
- bool isJfif = this.temp[0] == PdfJsJpegConstants.Markers.JFif.J
- && this.temp[1] == PdfJsJpegConstants.Markers.JFif.F
- && this.temp[2] == PdfJsJpegConstants.Markers.JFif.I
- && this.temp[3] == PdfJsJpegConstants.Markers.JFif.F
- && this.temp[4] == PdfJsJpegConstants.Markers.JFif.Null;
-
- if (isJfif)
- {
- this.jFif = new PdfJsJFif
- {
- MajorVersion = this.temp[5],
- MinorVersion = this.temp[6],
- DensityUnits = this.temp[7],
- XDensity = (short)((this.temp[8] << 8) | this.temp[9]),
- YDensity = (short)((this.temp[10] << 8) | this.temp[11])
- };
- }
-
- // TODO: thumbnail
- if (remaining > 0)
- {
- this.InputStream.Skip(remaining);
- }
- }
-
- ///
- /// Processes the App1 marker retrieving any stored metadata
- ///
- /// The remaining bytes in the segment block.
- /// The image.
- private void ProcessApp1Marker(int remaining, ImageMetaData metadata)
- {
- if (remaining < 6 || this.IgnoreMetadata)
- {
- // Skip the application header length
- this.InputStream.Skip(remaining);
- return;
- }
-
- byte[] profile = new byte[remaining];
- this.InputStream.Read(profile, 0, remaining);
-
- if (profile[0] == PdfJsJpegConstants.Markers.Exif.E && profile[1] == PdfJsJpegConstants.Markers.Exif.X
- && profile[2] == PdfJsJpegConstants.Markers.Exif.I && profile[3] == PdfJsJpegConstants.Markers.Exif.F
- && profile[4] == PdfJsJpegConstants.Markers.Exif.Null
- && profile[5] == PdfJsJpegConstants.Markers.Exif.Null)
- {
- this.isExif = true;
- metadata.ExifProfile = new ExifProfile(profile);
- }
- }
-
- ///
- /// Processes the App2 marker retrieving any stored ICC profile information
- ///
- /// The remaining bytes in the segment block.
- /// The image.
- private void ProcessApp2Marker(int remaining, ImageMetaData metadata)
- {
- // Length is 14 though we only need to check 12.
- const int Icclength = 14;
- if (remaining < Icclength || this.IgnoreMetadata)
- {
- this.InputStream.Skip(remaining);
- return;
- }
-
- byte[] identifier = new byte[Icclength];
- this.InputStream.Read(identifier, 0, Icclength);
- remaining -= Icclength; // We have read it by this point
-
- if (identifier[0] == PdfJsJpegConstants.Markers.ICC.I && identifier[1] == PdfJsJpegConstants.Markers.ICC.C
- && identifier[2] == PdfJsJpegConstants.Markers.ICC.C
- && identifier[3] == PdfJsJpegConstants.Markers.ICC.UnderScore
- && identifier[4] == PdfJsJpegConstants.Markers.ICC.P
- && identifier[5] == PdfJsJpegConstants.Markers.ICC.R
- && identifier[6] == PdfJsJpegConstants.Markers.ICC.O
- && identifier[7] == PdfJsJpegConstants.Markers.ICC.F
- && identifier[8] == PdfJsJpegConstants.Markers.ICC.I
- && identifier[9] == PdfJsJpegConstants.Markers.ICC.L
- && identifier[10] == PdfJsJpegConstants.Markers.ICC.E
- && identifier[11] == PdfJsJpegConstants.Markers.ICC.Null)
- {
- byte[] profile = new byte[remaining];
- this.InputStream.Read(profile, 0, remaining);
-
- if (metadata.IccProfile == null)
- {
- metadata.IccProfile = new IccProfile(profile);
- }
- else
- {
- metadata.IccProfile.Extend(profile);
- }
- }
- else
- {
- // Not an ICC profile we can handle. Skip the remaining bytes so we can carry on and ignore this.
- this.InputStream.Skip(remaining);
- }
- }
-
- ///
- /// Processes the application header containing the Adobe identifier
- /// which stores image encoding information for DCT filters.
- ///
- /// The remaining bytes in the segment block.
- private void ProcessApp14Marker(int remaining)
- {
- if (remaining < 12)
- {
- // Skip the application header length
- this.InputStream.Skip(remaining);
- return;
- }
-
- this.InputStream.Read(this.temp, 0, 12);
- remaining -= 12;
-
- bool isAdobe = this.temp[0] == PdfJsJpegConstants.Markers.Adobe.A
- && this.temp[1] == PdfJsJpegConstants.Markers.Adobe.D
- && this.temp[2] == PdfJsJpegConstants.Markers.Adobe.O
- && this.temp[3] == PdfJsJpegConstants.Markers.Adobe.B
- && this.temp[4] == PdfJsJpegConstants.Markers.Adobe.E;
-
- if (isAdobe)
- {
- this.adobe = new PdfJsAdobe
- {
- DCTEncodeVersion = (short)((this.temp[5] << 8) | this.temp[6]),
- APP14Flags0 = (short)((this.temp[7] << 8) | this.temp[8]),
- APP14Flags1 = (short)((this.temp[9] << 8) | this.temp[10]),
- ColorTransform = this.temp[11]
- };
- }
-
- if (remaining > 0)
- {
- this.InputStream.Skip(remaining);
- }
- }
-
- ///
- /// Processes the Define Quantization Marker and tables. Specified in section B.2.4.1.
- ///
- /// The remaining bytes in the segment block.
- ///
- /// Thrown if the tables do not match the header
- ///
- private void ProcessDefineQuantizationTablesMarker(int remaining)
- {
- while (remaining > 0)
- {
- bool done = false;
- remaining--;
- int quantizationTableSpec = this.InputStream.ReadByte();
-
- switch (quantizationTableSpec >> 4)
- {
- case 0:
- {
- // 8 bit values
- if (remaining < 64)
- {
- done = true;
- break;
- }
-
- this.InputStream.Read(this.temp, 0, 64);
- remaining -= 64;
-
- Span tableSpan =
- this.quantizationTables.Tables.GetRowSpan(quantizationTableSpec & 15);
- for (int j = 0; j < 64; j++)
- {
- tableSpan[PdfJsQuantizationTables.DctZigZag[j]] = this.temp[j];
- }
- }
-
- break;
- case 1:
- {
- // 16 bit values
- if (remaining < 128)
- {
- done = true;
- break;
- }
-
- this.InputStream.Read(this.temp, 0, 128);
- remaining -= 128;
-
- Span tableSpan =
- this.quantizationTables.Tables.GetRowSpan(quantizationTableSpec & 15);
- for (int j = 0; j < 64; j++)
- {
- tableSpan[PdfJsQuantizationTables.DctZigZag[j]] =
- (short)((this.temp[2 * j] << 8) | this.temp[(2 * j) + 1]);
- }
- }
-
- break;
- default:
- throw new ImageFormatException("Bad Tq index value");
- }
-
- if (done)
- {
- break;
- }
- }
-
- if (remaining != 0)
- {
- throw new ImageFormatException("DQT has wrong length");
- }
- }
-
- ///
- /// Processes the Start of Frame marker. Specified in section B.2.2.
- ///
- /// The remaining bytes in the segment block.
- /// The current frame marker.
- private void ProcessStartOfFrameMarker(int remaining, PdfJsFileMarker frameMarker)
- {
- if (this.frame != null)
- {
- throw new ImageFormatException("Multiple SOF markers. Only single frame jpegs supported.");
- }
-
- this.InputStream.Read(this.temp, 0, remaining);
-
- this.frame = new PdfJsFrame
- {
- Extended = frameMarker.Marker == PdfJsJpegConstants.Markers.SOF1,
- Progressive = frameMarker.Marker == PdfJsJpegConstants.Markers.SOF2,
- Precision = this.temp[0],
- Scanlines = (short)((this.temp[1] << 8) | this.temp[2]),
- SamplesPerLine = (short)((this.temp[3] << 8) | this.temp[4]),
- ComponentCount = this.temp[5]
- };
-
- int maxH = 0;
- int maxV = 0;
- int index = 6;
-
- // No need to pool this. They max out at 4
- this.frame.ComponentIds = new byte[this.frame.ComponentCount];
- this.frame.Components = new PdfJsFrameComponent[this.frame.ComponentCount];
-
- for (int i = 0; i < this.frame.Components.Length; i++)
- {
- int h = this.temp[index + 1] >> 4;
- int v = this.temp[index + 1] & 15;
-
- if (maxH < h)
- {
- maxH = h;
- }
-
- if (maxV < v)
- {
- maxV = v;
- }
-
- ref var component = ref this.frame.Components[i];
- component.Id = this.temp[index];
- component.HorizontalFactor = h;
- component.VerticalFactor = v;
- component.QuantizationIdentifier = this.temp[index + 2];
-
- this.frame.ComponentIds[i] = component.Id;
-
- index += 3;
- }
-
- this.frame.MaxHorizontalFactor = maxH;
- this.frame.MaxVerticalFactor = maxV;
- this.PrepareComponents();
- }
-
- ///
- /// Processes a Define Huffman Table marker, and initializes a huffman
- /// struct from its contents. Specified in section B.2.4.2.
- ///
- /// The remaining bytes in the segment block.
- private void ProcessDefineHuffmanTablesMarker(int remaining)
- {
- if (remaining < 17)
- {
- throw new ImageFormatException($"DHT has wrong length: {remaining}");
- }
-
- using (var huffmanData = Buffer.CreateClean(256))
- {
- for (int i = 2; i < remaining;)
- {
- byte huffmanTableSpec = (byte)this.InputStream.ReadByte();
- this.InputStream.Read(huffmanData.Array, 0, 16);
-
- using (var codeLengths = Buffer.CreateClean(17))
- {
- int codeLengthSum = 0;
-
- for (int j = 1; j < 17; j++)
- {
- codeLengthSum += codeLengths[j] = huffmanData[j - 1];
- }
-
- using (var huffmanValues = Buffer.CreateClean(256))
- {
- this.InputStream.Read(huffmanValues.Array, 0, codeLengthSum);
-
- i += 17 + codeLengthSum;
-
- this.BuildHuffmanTable(
- huffmanTableSpec >> 4 == 0 ? this.dcHuffmanTables : this.acHuffmanTables,
- huffmanTableSpec & 15,
- codeLengths.Array,
- huffmanValues.Array);
- }
- }
- }
- }
- }
-
- ///
- /// Processes the DRI (Define Restart Interval Marker) Which specifies the interval between RSTn markers, in
- /// macroblocks
- ///
- /// The remaining bytes in the segment block.
- private void ProcessDefineRestartIntervalMarker(int remaining)
- {
- if (remaining != 2)
- {
- throw new ImageFormatException($"DRI has wrong length: {remaining}");
- }
-
- this.resetInterval = this.ReadUint16();
- }
-
- ///
- /// Processes the SOS (Start of scan marker).
- ///
- private void ProcessStartOfScanMarker()
- {
- int selectorsCount = this.InputStream.ReadByte();
- int componentIndex = -1;
- for (int i = 0; i < selectorsCount; i++)
- {
- componentIndex = -1;
- int selector = this.InputStream.ReadByte();
-
- for (int j = 0; j < this.frame.ComponentIds.Length; j++)
- {
- byte id = this.frame.ComponentIds[j];
- if (selector == id)
- {
- componentIndex = j;
- }
- }
-
- if (componentIndex < 0)
- {
- throw new ImageFormatException("Unknown component selector");
- }
-
- ref PdfJsFrameComponent component = ref this.frame.Components[componentIndex];
- int tableSpec = this.InputStream.ReadByte();
- component.DCHuffmanTableId = tableSpec >> 4;
- component.ACHuffmanTableId = tableSpec & 15;
- }
-
- this.InputStream.Read(this.temp, 0, 3);
-
- int spectralStart = this.temp[0];
- int spectralEnd = this.temp[1];
- int successiveApproximation = this.temp[2];
- var scanDecoder = default(PdfJsScanDecoder);
-
- scanDecoder.DecodeScan(
- this.frame,
- this.InputStream,
- this.dcHuffmanTables,
- this.acHuffmanTables,
- this.frame.Components,
- componentIndex,
- selectorsCount,
- this.resetInterval,
- spectralStart,
- spectralEnd,
- successiveApproximation >> 4,
- successiveApproximation & 15);
- }
-
- ///
- /// Build the data for the given component
- ///
- /// The component
- /// The frame component
- private void BuildComponentData(ref PdfJsComponent component, ref PdfJsFrameComponent frameComponent)
- {
- int blocksPerLine = component.BlocksPerLine;
- int blocksPerColumn = component.BlocksPerColumn;
- using (var computationBuffer = Buffer.CreateClean(64))
-
- // IDCTFast Only
- // using (var multiplicationBuffer = Buffer.CreateClean(64))
- {
- Span quantizationTable =
- this.quantizationTables.Tables.GetRowSpan(frameComponent.QuantizationIdentifier);
- Span computationBufferSpan = computationBuffer;
-
- // For AA&N IDCT method, multiplier are equal to quantization
- // coefficients scaled by scalefactor[row]*scalefactor[col], where
- // scalefactor[0] = 1
- // scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
- // For integer operation, the multiplier table is to be scaled by 12.
-
- // IDCTFast Only
- // Span multiplierSpan = multiplicationBuffer;
- // for (int i = 0; i < 64; i++)
- // {
- // multiplierSpan[i] = (short)PdfJsIDCT.Descale(quantizationTable[i] * PdfJsIDCT.Aanscales[i], 12);
- // }
- for (int blockRow = 0; blockRow < blocksPerColumn; blockRow++)
- {
- for (int blockCol = 0; blockCol < blocksPerLine; blockCol++)
- {
- int offset = GetBlockBufferOffset(ref component, blockRow, blockCol);
-
- // IDCTFast Only
- // PdfJsIDCT.QuantizeAndInverseFast(
- // ref frameComponent,
- // offset,
- // ref computationBufferSpan,
- // ref multiplierSpan);
- PdfJsIDCT.QuantizeAndInverse(
- ref frameComponent,
- offset,
- ref computationBufferSpan,
- ref quantizationTable);
- }
- }
- }
-
- component.Output = frameComponent.BlockData;
- }
-
- ///
- /// Builds the huffman tables
- ///
- /// The tables
- /// The table index
- /// The codelengths
- /// The values
- private void BuildHuffmanTable(PdfJsHuffmanTables tables, int index, byte[] codeLengths, byte[] values)
- {
- tables[index] = new PdfJsHuffmanTable(codeLengths, values);
- }
-
- ///
- /// Allocates the frame component blocks
- ///
- private void PrepareComponents()
- {
- int mcusPerLine = (int)MathF.Ceiling(this.frame.SamplesPerLine / 8F / this.frame.MaxHorizontalFactor);
- int mcusPerColumn = (int)MathF.Ceiling(this.frame.Scanlines / 8F / this.frame.MaxVerticalFactor);
-
- for (int i = 0; i < this.frame.ComponentCount; i++)
- {
- ref var component = ref this.frame.Components[i];
- int blocksPerLine = (int)MathF.Ceiling(
- MathF.Ceiling(this.frame.SamplesPerLine / 8F) * component.HorizontalFactor
- / this.frame.MaxHorizontalFactor);
- int blocksPerColumn = (int)MathF.Ceiling(
- MathF.Ceiling(this.frame.Scanlines / 8F) * component.VerticalFactor / this.frame.MaxVerticalFactor);
- int blocksPerLineForMcu = mcusPerLine * component.HorizontalFactor;
- int blocksPerColumnForMcu = mcusPerColumn * component.VerticalFactor;
-
- int blocksBufferSize = 64 * blocksPerColumnForMcu * (blocksPerLineForMcu + 1);
-
- // Pooled. Disposed via frame disposal
- component.BlockData = Buffer.CreateClean(blocksBufferSize);
- component.BlocksPerLine = blocksPerLine;
- component.BlocksPerColumn = blocksPerColumn;
- }
-
- this.frame.McusPerLine = mcusPerLine;
- this.frame.McusPerColumn = mcusPerColumn;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void FillGrayScaleImage(Image image)
- where TPixel : struct, IPixel
- {
- for (int y = 0; y < image.Height; y++)
- {
- Span imageRowSpan = image.GetRowSpan(y);
- Span areaRowSpan = this.pixelArea.GetRowSpan(y);
-
- for (int x = 0; x < image.Width; x++)
- {
- ref byte luminance = ref areaRowSpan[x];
- ref TPixel pixel = ref imageRowSpan[x];
- var rgba = new Rgba32(luminance, luminance, luminance);
- pixel.PackFromRgba32(rgba);
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void FillYCbCrImage(Image image)
- where TPixel : struct, IPixel
- {
- for (int y = 0; y < image.Height; y++)
- {
- Span imageRowSpan = image.GetRowSpan(y);
- Span areaRowSpan = this.pixelArea.GetRowSpan(y);
- for (int x = 0, o = 0; x < image.Width; x++, o += 3)
- {
- ref byte yy = ref areaRowSpan[o];
- ref byte cb = ref areaRowSpan[o + 1];
- ref byte cr = ref areaRowSpan[o + 2];
- ref TPixel pixel = ref imageRowSpan[x];
- PdfJsYCbCrToRgbTables.PackYCbCr(ref pixel, yy, cb, cr);
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void FillYcckImage(Image image)
- where TPixel : struct, IPixel
- {
- for (int y = 0; y < image.Height; y++)
- {
- Span imageRowSpan = image.GetRowSpan(y);
- Span areaRowSpan = this.pixelArea.GetRowSpan(y);
- for (int x = 0, o = 0; x < image.Width; x++, o += 4)
- {
- ref byte yy = ref areaRowSpan[o];
- ref byte cb = ref areaRowSpan[o + 1];
- ref byte cr = ref areaRowSpan[o + 2];
- ref byte k = ref areaRowSpan[o + 3];
-
- ref TPixel pixel = ref imageRowSpan[x];
- PdfJsYCbCrToRgbTables.PackYccK(ref pixel, yy, cb, cr, k);
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void FillCmykImage(Image image)
- where TPixel : struct, IPixel
- {
- for (int y = 0; y < image.Height; y++)
- {
- Span imageRowSpan = image.GetRowSpan(y);
- Span areaRowSpan = this.pixelArea.GetRowSpan(y);
- for (int x = 0, o = 0; x < image.Width; x++, o += 4)
- {
- ref byte c = ref areaRowSpan[o];
- ref byte m = ref areaRowSpan[o + 1];
- ref byte cy = ref areaRowSpan[o + 2];
- ref byte k = ref areaRowSpan[o + 3];
-
- byte r = (byte)((c * k) / 255);
- byte g = (byte)((m * k) / 255);
- byte b = (byte)((cy * k) / 255);
-
- ref TPixel pixel = ref imageRowSpan[x];
- var rgba = new Rgba32(r, g, b);
- pixel.PackFromRgba32(rgba);
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void FillRgbImage(Image image)
- where TPixel : struct, IPixel
- {
- for (int y = 0; y < image.Height; y++)
- {
- Span imageRowSpan = image.GetRowSpan(y);
- Span areaRowSpan = this.pixelArea.GetRowSpan(y);
-
- PixelOperations.Instance.PackFromRgb24Bytes(areaRowSpan, imageRowSpan, image.Width);
- }
- }
-
- ///
- /// Reads a from the stream advancing it by two bytes
- ///
- /// The
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private ushort ReadUint16()
- {
- this.InputStream.Read(this.markerBuffer, 0, 2);
- return (ushort)((this.markerBuffer[0] << 8) | this.markerBuffer[1]);
- }
- }
-}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
index e77ebb92b..234f4dcdc 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
@@ -11,7 +11,7 @@ namespace ImageSharp.Tests
using System.Linq;
using ImageSharp.Formats;
- using ImageSharp.Formats.Jpeg.PdfJsPort;
+
using ImageSharp.PixelFormats;
using ImageSharp.Tests.TestUtilities.ImageComparison;
@@ -40,6 +40,10 @@ namespace ImageSharp.Tests
private ITestOutputHelper Output { get; }
+ private static IImageDecoder OriginalDecoder => new JpegDecoder();
+
+ private static IImageDecoder GetPdfJsDecoder => throw new NotImplementedException();
+
private float GetDifferenceInPercents(Image image, TestImageProvider provider)
where TPixel : struct, IPixel
{
@@ -66,13 +70,13 @@ namespace ImageSharp.Tests
this.Output.WriteLine(provider.SourceFileOrDescription);
provider.Utility.TestName = nameof(this.DecodeBaselineJpeg);
- using (Image image = provider.GetImage(new JpegDecoder()))
+ using (Image image = provider.GetImage(OriginalDecoder))
{
double d = this.GetDifferenceInPercents(image, provider);
this.Output.WriteLine($"Difference using ORIGINAL decoder: {d:0.0000}%");
}
- using (Image image = provider.GetImage(new PdfJsJpegDecoder()))
+ using (Image image = provider.GetImage(GetPdfJsDecoder))
{
double d = this.GetDifferenceInPercents(image, provider);
this.Output.WriteLine($"Difference using PDFJS decoder: {d:0.0000}%");
@@ -84,7 +88,7 @@ namespace ImageSharp.Tests
public void DecodeBaselineJpeg(TestImageProvider provider)
where TPixel : struct, IPixel
{
- using (Image image = provider.GetImage(new JpegDecoder()))
+ using (Image image = provider.GetImage(OriginalDecoder))
{
image.DebugSave(provider);
image.CompareToReferenceOutput(provider, VeryTolerantJpegComparer, appendPixelTypeToFileName: false);
@@ -96,7 +100,7 @@ namespace ImageSharp.Tests
public void DecodeBaselineJpeg_PdfJs(TestImageProvider provider)
where TPixel : struct, IPixel
{
- using (Image image = provider.GetImage(new PdfJsJpegDecoder()))
+ using (Image image = provider.GetImage(GetPdfJsDecoder))
{
image.DebugSave(provider);
@@ -110,7 +114,7 @@ namespace ImageSharp.Tests
public void DecodeProgressiveJpeg(TestImageProvider provider)
where TPixel : struct, IPixel
{
- using (Image image = provider.GetImage(new JpegDecoder()))
+ using (Image image = provider.GetImage(OriginalDecoder))
{
image.DebugSave(provider, VeryTolerantJpegComparer);
}
@@ -122,7 +126,7 @@ namespace ImageSharp.Tests
public void DecodeProgressiveJpeg_PdfJs(TestImageProvider provider)
where TPixel : struct, IPixel
{
- using (Image image = provider.GetImage(new PdfJsJpegDecoder()))
+ using (Image image = provider.GetImage(GetPdfJsDecoder))
{
image.DebugSave(provider, VeryTolerantJpegComparer);
}