diff --git a/src/ImageProcessorCore/Colors/Colorspaces/YCbCr.cs b/src/ImageProcessorCore/Colors/Colorspaces/YCbCr.cs
index 64560d7d0..a801582f7 100644
--- a/src/ImageProcessorCore/Colors/Colorspaces/YCbCr.cs
+++ b/src/ImageProcessorCore/Colors/Colorspaces/YCbCr.cs
@@ -10,7 +10,7 @@ namespace ImageProcessorCore
using System.Numerics;
///
- /// Represents an YCbCr (luminance, chroma, chroma) color conforming to the
+ /// Represents an YCbCr (luminance, blue chroma, red chroma) color conforming to the
/// Full range standard used in digital imaging systems.
///
///
diff --git a/src/ImageProcessorCore/Formats/Jpg/Components/Bits.cs b/src/ImageProcessorCore/Formats/Jpg/Components/Bits.cs
new file mode 100644
index 000000000..615a8f897
--- /dev/null
+++ b/src/ImageProcessorCore/Formats/Jpg/Components/Bits.cs
@@ -0,0 +1,31 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Formats
+{
+ ///
+ /// Holds the unprocessed bits that have been taken from the byte-stream.
+ /// The n least significant bits of a form the unread bits, to be read in MSB to
+ /// LSB order.
+ ///
+ internal class Bits
+ {
+ ///
+ /// Gets or sets the accumulator.
+ ///
+ public uint Accumulator { get; set; }
+
+ ///
+ /// Gets or sets the mask.
+ /// 0, with mask==0 when unreadbits==0.]]>
+ ///
+ public uint Mask { get; set; }
+
+ ///
+ /// Gets or sets the number of unread bits in the accumulator.
+ ///
+ public int UnreadBits { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageProcessorCore/Formats/Jpg/Block.cs b/src/ImageProcessorCore/Formats/Jpg/Components/Block.cs
similarity index 100%
rename from src/ImageProcessorCore/Formats/Jpg/Block.cs
rename to src/ImageProcessorCore/Formats/Jpg/Components/Block.cs
diff --git a/src/ImageProcessorCore/Formats/Jpg/Components/Bytes.cs b/src/ImageProcessorCore/Formats/Jpg/Components/Bytes.cs
new file mode 100644
index 000000000..8467d3b9f
--- /dev/null
+++ b/src/ImageProcessorCore/Formats/Jpg/Components/Bytes.cs
@@ -0,0 +1,43 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Formats
+{
+ ///
+ /// Bytes is a byte buffer, similar to a stream, except that it
+ /// has to be able to unread more than 1 byte, due to byte stuffing.
+ /// Byte stuffing is specified in section F.1.2.3.
+ ///
+ internal class Bytes
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Bytes()
+ {
+ this.Buffer = new byte[4096];
+ this.I = 0;
+ this.J = 0;
+ this.UnreadableBytes = 0;
+ }
+
+ ///
+ /// Gets or sets the buffer.
+ /// buffer[i:j] are the buffered bytes read from the underlying
+ /// stream that haven't yet been passed further on.
+ ///
+ public byte[] Buffer { get; set; }
+
+ public int I { get; set; }
+
+ public int J { get; set; }
+
+ ///
+ /// Gets or sets the unreadable bytes. The number of bytes to back up i after
+ /// overshooting. It can be 0, 1 or 2.
+ ///
+ public int UnreadableBytes { get; set; }
+ }
+}
diff --git a/src/ImageProcessorCore/Formats/Jpg/Components/Component.cs b/src/ImageProcessorCore/Formats/Jpg/Components/Component.cs
new file mode 100644
index 000000000..a4131af6e
--- /dev/null
+++ b/src/ImageProcessorCore/Formats/Jpg/Components/Component.cs
@@ -0,0 +1,33 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Formats
+{
+ ///
+ /// Represents a single color component
+ ///
+ internal class Component
+ {
+ ///
+ /// Gets or sets the horizontal sampling factor.
+ ///
+ public int HorizontalFactor { get; set; }
+
+ ///
+ /// Gets or sets the vertical sampling factor.
+ ///
+ public int VerticalFactor { get; set; }
+
+ ///
+ /// Gets or sets the identifier
+ ///
+ public byte Identifier { get; set; }
+
+ ///
+ /// Gets or sets the quantization table destination selector.
+ ///
+ public byte Selector { get; set; }
+ }
+}
diff --git a/src/ImageProcessorCore/Formats/Jpg/FDCT.cs b/src/ImageProcessorCore/Formats/Jpg/Components/FDCT.cs
similarity index 100%
rename from src/ImageProcessorCore/Formats/Jpg/FDCT.cs
rename to src/ImageProcessorCore/Formats/Jpg/Components/FDCT.cs
diff --git a/src/ImageProcessorCore/Formats/Jpg/Components/GrayImage.cs b/src/ImageProcessorCore/Formats/Jpg/Components/GrayImage.cs
new file mode 100644
index 000000000..b511b2694
--- /dev/null
+++ b/src/ImageProcessorCore/Formats/Jpg/Components/GrayImage.cs
@@ -0,0 +1,101 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Formats
+{
+ ///
+ /// Represents a grayscale image
+ ///
+ internal class GrayImage
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The width.
+ /// The height.
+ public GrayImage(int width, int height)
+ {
+ this.Width = width;
+ this.Height = height;
+ this.Pixels = new byte[width * height];
+ this.Stride = width;
+ this.Offset = 0;
+ }
+
+ ///
+ /// Prevents a default instance of the class from being created.
+ ///
+ private GrayImage()
+ {
+ }
+
+ ///
+ /// Gets or sets the pixels.
+ ///
+ public byte[] Pixels { get; set; }
+
+ ///
+ /// Gets or sets the stride.
+ ///
+ public int Stride { get; set; }
+
+ ///
+ /// Gets or sets the horizontal position.
+ ///
+ public int X { get; set; }
+
+ ///
+ /// Gets or sets the vertical position.
+ ///
+ public int Y { get; set; }
+
+ ///
+ /// Gets or sets the width.
+ ///
+ public int Width { get; set; }
+
+ ///
+ /// Gets or sets the height.
+ ///
+ public int Height { get; set; }
+
+ ///
+ /// Gets or sets the offset
+ ///
+ public int Offset { get; set; }
+
+ ///
+ /// Gets an image made up of a subset of the originals pixels.
+ ///
+ /// The x-coordinate of the image.
+ /// The y-coordinate of the image.
+ /// The width.
+ /// The height.
+ ///
+ /// The .
+ ///
+ public GrayImage Subimage(int x, int y, int width, int height)
+ {
+ return new GrayImage
+ {
+ Width = width,
+ Height = height,
+ Pixels = this.Pixels,
+ Stride = this.Stride,
+ Offset = (y * this.Stride) + x
+ };
+ }
+
+ ///
+ /// Gets the row offset at the given position
+ ///
+ /// The y-coordinate of the image.
+ /// The
+ public int GetRowOffset(int y)
+ {
+ return this.Offset + (y * this.Stride);
+ }
+ }
+}
diff --git a/src/ImageProcessorCore/Formats/Jpg/Components/Huffman.cs b/src/ImageProcessorCore/Formats/Jpg/Components/Huffman.cs
new file mode 100644
index 000000000..7a7083202
--- /dev/null
+++ b/src/ImageProcessorCore/Formats/Jpg/Components/Huffman.cs
@@ -0,0 +1,64 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Formats
+{
+ ///
+ /// Represents a Huffman tree
+ ///
+ internal class Huffman
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The log-2 size of the Huffman decoder's look-up table.
+ /// The maximum (inclusive) number of codes in a Huffman tree.
+ /// The maximum (inclusive) number of bits in a Huffman code.
+ public Huffman(int lutSize, int maxNCodes, int maxCodeLength)
+ {
+ this.Lut = new ushort[1 << lutSize];
+ this.Values = new byte[maxNCodes];
+ this.MinCodes = new int[maxCodeLength];
+ this.MaxCodes = new int[maxCodeLength];
+ this.Indices = new int[maxCodeLength];
+ this.Length = 0;
+ }
+
+ ///
+ /// Gets or sets the number of codes in the tree.
+ ///
+ public int Length { get; set; }
+
+ ///
+ /// Gets the look-up table for the next LutSize bits in the bit-stream.
+ /// The high 8 bits of the uint16 are the encoded value. The low 8 bits
+ /// are 1 plus the code length, or 0 if the value is too large to fit in
+ /// lutSize bits.
+ ///
+ public ushort[] Lut { get; }
+
+ ///
+ /// Gets the the decoded values, sorted by their encoding.
+ ///
+ public byte[] Values { get; }
+
+ ///
+ /// Gets the array of minimum codes.
+ /// MinCodes[i] is the minimum code of length i, or -1 if there are no codes of that length.
+ ///
+ public int[] MinCodes { get; }
+
+ ///
+ /// Gets the array of maximum codes.
+ /// MaxCodes[i] is the maximum code of length i, or -1 if there are no codes of that length.
+ ///
+ public int[] MaxCodes { get; }
+
+ ///
+ /// Gets the array of indices. Indices[i] is the index into Values of MinCodes[i].
+ ///
+ public int[] Indices { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageProcessorCore/Formats/Jpg/IDCT.cs b/src/ImageProcessorCore/Formats/Jpg/Components/IDCT.cs
similarity index 100%
rename from src/ImageProcessorCore/Formats/Jpg/IDCT.cs
rename to src/ImageProcessorCore/Formats/Jpg/Components/IDCT.cs
diff --git a/src/ImageProcessorCore/Formats/Jpg/Components/YCbCrImage.cs b/src/ImageProcessorCore/Formats/Jpg/Components/YCbCrImage.cs
new file mode 100644
index 000000000..ea7ab15f7
--- /dev/null
+++ b/src/ImageProcessorCore/Formats/Jpg/Components/YCbCrImage.cs
@@ -0,0 +1,228 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Formats
+{
+ ///
+ /// Represents an image made up of three color components (luminance, blue chroma, red chroma)
+ ///
+ internal class YCbCrImage
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The width.
+ /// The height.
+ /// The ratio.
+ public YCbCrImage(int width, int height, YCbCrSubsampleRatio ratio)
+ {
+ int cw, ch;
+ YCbCrSize(width, height, ratio, out cw, out ch);
+ this.YChannel = new byte[width * height];
+ this.CbChannel = new byte[cw * ch];
+ this.CrChannel = new byte[cw * ch];
+ this.Ratio = ratio;
+ this.YStride = width;
+ this.CStride = cw;
+ this.X = 0;
+ this.Y = 0;
+ this.Width = width;
+ this.Height = height;
+ }
+
+ ///
+ /// Prevents a default instance of the class from being created.
+ ///
+ private YCbCrImage()
+ {
+ }
+
+ ///
+ /// Provides enumeration of the various available subsample ratios.
+ ///
+ public enum YCbCrSubsampleRatio
+ {
+ YCbCrSubsampleRatio444,
+
+ YCbCrSubsampleRatio422,
+
+ YCbCrSubsampleRatio420,
+
+ YCbCrSubsampleRatio440,
+
+ YCbCrSubsampleRatio411,
+
+ YCbCrSubsampleRatio410,
+ }
+
+ ///
+ /// Gets or sets the luminance components channel.
+ ///
+ public byte[] YChannel { get; set; }
+
+ ///
+ /// Gets or sets the blue chroma components channel.
+ ///
+ public byte[] CbChannel { get; set; }
+
+ ///
+ /// Gets or sets the red chroma components channel.
+ ///
+ public byte[] CrChannel { get; set; }
+
+ ///
+ /// Gets or sets the Y slice index delta between vertically adjacent pixels.
+ ///
+ public int YStride { get; set; }
+
+ ///
+ /// Gets or sets the red and blue chroma slice index delta between vertically adjacent pixels
+ /// that map to separate chroma samples.
+ ///
+ public int CStride { get; set; }
+
+ ///
+ /// Gets or sets the index of the first luminance element.
+ ///
+ public int YOffset { get; set; }
+
+ ///
+ /// Gets or sets the index of the first element of red or blue chroma.
+ ///
+ public int COffset { get; set; }
+
+ ///
+ /// Gets or sets the horizontal position.
+ ///
+ public int X { get; set; }
+
+ ///
+ /// Gets or sets the vertical position.
+ ///
+ public int Y { get; set; }
+
+ ///
+ /// Gets or sets the width.
+ ///
+ public int Width { get; set; }
+
+ ///
+ /// Gets or sets the height.
+ ///
+ public int Height { get; set; }
+
+ ///
+ /// Gets or sets the subsampling ratio.
+ ///
+ public YCbCrSubsampleRatio Ratio { get; set; }
+
+ ///
+ /// Gets an image made up of a subset of the originals pixels.
+ ///
+ /// The x-coordinate of the image.
+ /// The y-coordinate of the image.
+ /// The width.
+ /// The height.
+ ///
+ /// The .
+ ///
+ public YCbCrImage Subimage(int x, int y, int width, int height)
+ {
+ YCbCrImage ret = new YCbCrImage
+ {
+ Width = width,
+ Height = height,
+ YChannel = this.YChannel,
+ CbChannel = this.CbChannel,
+ CrChannel = this.CrChannel,
+ Ratio = this.Ratio,
+ YStride = this.YStride,
+ CStride = this.CStride,
+ YOffset = (y * this.YStride) + x,
+ COffset = (y * this.CStride) + x
+ };
+ return ret;
+ }
+
+ ///
+ /// Returns the offset of the first luminance component at the given row
+ ///
+ /// The row number.
+ ///
+ /// The .
+ ///
+ public int GetRowYOffset(int y)
+ {
+ return y * this.YStride;
+ }
+
+ ///
+ /// Returns the offset of the first chroma component at the given row
+ ///
+ /// The row number.
+ ///
+ /// The .
+ ///
+ public int GetRowCOffset(int y)
+ {
+ switch (this.Ratio)
+ {
+ case YCbCrSubsampleRatio.YCbCrSubsampleRatio422:
+ return y * this.CStride;
+ case YCbCrSubsampleRatio.YCbCrSubsampleRatio420:
+ return (y / 2) * this.CStride;
+ case YCbCrSubsampleRatio.YCbCrSubsampleRatio440:
+ return (y / 2) * this.CStride;
+ case YCbCrSubsampleRatio.YCbCrSubsampleRatio411:
+ return y * this.CStride;
+ case YCbCrSubsampleRatio.YCbCrSubsampleRatio410:
+ return (y / 2) * this.CStride;
+ default:
+ return y * this.CStride;
+ }
+ }
+
+ ///
+ /// Returns the height and width of the chroma components
+ ///
+ /// The width.
+ /// The height.
+ /// The subsampling ratio.
+ /// The chroma width.
+ /// The chroma height.
+ private static void YCbCrSize(int width, int height, YCbCrSubsampleRatio ratio, out int chromaWidth, out int chromaHeight)
+ {
+ switch (ratio)
+ {
+ case YCbCrSubsampleRatio.YCbCrSubsampleRatio422:
+ chromaWidth = (width + 1) / 2;
+ chromaHeight = height;
+ break;
+ case YCbCrSubsampleRatio.YCbCrSubsampleRatio420:
+ chromaWidth = (width + 1) / 2;
+ chromaHeight = (height + 1) / 2;
+ break;
+ case YCbCrSubsampleRatio.YCbCrSubsampleRatio440:
+ chromaWidth = width;
+ chromaHeight = (height + 1) / 2;
+ break;
+ case YCbCrSubsampleRatio.YCbCrSubsampleRatio411:
+ chromaWidth = (width + 3) / 4;
+ chromaHeight = height;
+ break;
+ case YCbCrSubsampleRatio.YCbCrSubsampleRatio410:
+ chromaWidth = (width + 3) / 4;
+ chromaHeight = (height + 1) / 2;
+ break;
+ default:
+
+ // Default to 4:4:4 subsampling.
+ chromaWidth = width;
+ chromaHeight = height;
+ break;
+ }
+ }
+ }
+}
diff --git a/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id b/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id
index 922e9cccc..f10210ac0 100644
--- a/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id
+++ b/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id
@@ -1 +1 @@
-efdc36c9d84d1fd42bf3b1e722946bccef95db1c
\ No newline at end of file
+8ce31914f581080b90c50b6a6529db20a29e7551
\ No newline at end of file