diff --git a/src/ImageProcessorCore/Formats/Jpg/Block.cs b/src/ImageProcessorCore/Formats/Jpg/Block.cs
index 655471a07d..35aa10f181 100644
--- a/src/ImageProcessorCore/Formats/Jpg/Block.cs
+++ b/src/ImageProcessorCore/Formats/Jpg/Block.cs
@@ -1,19 +1,44 @@
-namespace ImageProcessorCore.Formats
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Formats
{
+ ///
+ /// Represents an 8x8 block of coefficients to transform and encode.
+ ///
internal class Block
{
- public const int blockSize = 64;
- private int[] _data;
+ ///
+ /// Gets the size of the block.
+ ///
+ public const int BlockSize = 64;
+
+ ///
+ /// The array of block data.
+ ///
+ private readonly int[] data;
+ ///
+ /// Initializes a new instance of the class.
+ ///
public Block()
{
- _data = new int[blockSize];
+ this.data = new int[BlockSize];
}
- public int this[int idx]
+ ///
+ /// Gets the pixel data at the given block index.
+ ///
+ /// The index of the data to return.
+ ///
+ /// The .
+ ///
+ public int this[int index]
{
- get { return _data[idx]; }
- set { _data[idx] = value; }
+ get { return this.data[index]; }
+ set { this.data[index] = value; }
}
}
}
diff --git a/src/ImageProcessorCore/Formats/Jpg/FDCT.cs b/src/ImageProcessorCore/Formats/Jpg/FDCT.cs
index a6073f9c79..e51ea64151 100644
--- a/src/ImageProcessorCore/Formats/Jpg/FDCT.cs
+++ b/src/ImageProcessorCore/Formats/Jpg/FDCT.cs
@@ -5,9 +5,14 @@
namespace ImageProcessorCore.Formats
{
+ ///
+ /// Performs a fast, forward descrete cosine transform against the given block
+ /// decomposing it into 64 orthogonal basis signals.
+ ///
internal class FDCT
{
// Trigonometric constants in 13-bit fixed point format.
+ // TODO: Rename and describe these.
private const int fix_0_298631336 = 2446;
private const int fix_0_390180644 = 3196;
private const int fix_0_541196100 = 4433;
@@ -20,27 +25,42 @@ namespace ImageProcessorCore.Formats
private const int fix_2_053119869 = 16819;
private const int fix_2_562915447 = 20995;
private const int fix_3_072711026 = 25172;
- private const int constBits = 13;
- private const int pass1Bits = 2;
- private const int centerJSample = 128;
- // fdct performs a forward DCT on an 8x8 block of coefficients, including a
- // level shift.
- public static void Transform(Block b)
+ ///
+ /// The number of bits
+ ///
+ private const int Bits = 13;
+
+ ///
+ /// The number of bits to shift by on the first pass.
+ ///
+ private const int Pass1Bits = 2;
+
+ ///
+ /// The value to shift by
+ ///
+ private const int CenterJSample = 128;
+
+ ///
+ /// Performs a forward DCT on an 8x8 block of coefficients, including a
+ /// level shift.
+ ///
+ /// The block.
+ public static void Transform(Block block)
{
// Pass 1: process rows.
for (int y = 0; y < 8; y++)
{
int y8 = y * 8;
- int x0 = b[y8 + 0];
- int x1 = b[y8 + 1];
- int x2 = b[y8 + 2];
- int x3 = b[y8 + 3];
- int x4 = b[y8 + 4];
- int x5 = b[y8 + 5];
- int x6 = b[y8 + 6];
- int x7 = b[y8 + 7];
+ int x0 = block[y8];
+ int x1 = block[y8 + 1];
+ int x2 = block[y8 + 2];
+ int x3 = block[y8 + 3];
+ int x4 = block[y8 + 4];
+ int x5 = block[y8 + 5];
+ int x6 = block[y8 + 6];
+ int x7 = block[y8 + 7];
int tmp0 = x0 + x7;
int tmp1 = x1 + x6;
@@ -57,19 +77,19 @@ namespace ImageProcessorCore.Formats
tmp2 = x2 - x5;
tmp3 = x3 - x4;
- b[y8] = (tmp10 + tmp11 - 8 * centerJSample) << pass1Bits;
- b[y8 + 4] = (tmp10 - tmp11) << pass1Bits;
+ block[y8] = (tmp10 + tmp11 - (8 * CenterJSample)) << Pass1Bits;
+ block[y8 + 4] = (tmp10 - tmp11) << Pass1Bits;
int z1 = (tmp12 + tmp13) * fix_0_541196100;
- z1 += 1 << (constBits - pass1Bits - 1);
- b[y8 + 2] = (z1 + tmp12 * fix_0_765366865) >> (constBits - pass1Bits);
- b[y8 + 6] = (z1 - tmp13 * fix_1_847759065) >> (constBits - pass1Bits);
+ z1 += 1 << (Bits - Pass1Bits - 1);
+ block[y8 + 2] = (z1 + (tmp12 * fix_0_765366865)) >> (Bits - Pass1Bits);
+ block[y8 + 6] = (z1 - (tmp13 * fix_1_847759065)) >> (Bits - Pass1Bits);
tmp10 = tmp0 + tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp0 + tmp2;
tmp13 = tmp1 + tmp3;
z1 = (tmp12 + tmp13) * fix_1_175875602;
- z1 += 1 << (constBits - pass1Bits - 1);
+ z1 += 1 << (Bits - Pass1Bits - 1);
tmp0 = tmp0 * fix_1_501321110;
tmp1 = tmp1 * fix_3_072711026;
tmp2 = tmp2 * fix_2_053119869;
@@ -81,45 +101,45 @@ namespace ImageProcessorCore.Formats
tmp12 += z1;
tmp13 += z1;
- b[y8 + 1] = (tmp0 + tmp10 + tmp12) >> (constBits - pass1Bits);
- b[y8 + 3] = (tmp1 + tmp11 + tmp13) >> (constBits - pass1Bits);
- b[y8 + 5] = (tmp2 + tmp11 + tmp12) >> (constBits - pass1Bits);
- b[y8 + 7] = (tmp3 + tmp10 + tmp13) >> (constBits - pass1Bits);
+ block[y8 + 1] = (tmp0 + tmp10 + tmp12) >> (Bits - Pass1Bits);
+ block[y8 + 3] = (tmp1 + tmp11 + tmp13) >> (Bits - Pass1Bits);
+ block[y8 + 5] = (tmp2 + tmp11 + tmp12) >> (Bits - Pass1Bits);
+ block[y8 + 7] = (tmp3 + tmp10 + tmp13) >> (Bits - Pass1Bits);
}
// Pass 2: process columns.
// We remove pass1Bits scaling, but leave results scaled up by an overall factor of 8.
for (int x = 0; x < 8; x++)
{
- int tmp0 = b[x] + b[56 + x];
- int tmp1 = b[8 + x] + b[48 + x];
- int tmp2 = b[16 + x] + b[40 + x];
- int tmp3 = b[24 + x] + b[32 + x];
+ int tmp0 = block[x] + block[56 + x];
+ int tmp1 = block[8 + x] + block[48 + x];
+ int tmp2 = block[16 + x] + block[40 + x];
+ int tmp3 = block[24 + x] + block[32 + x];
- int tmp10 = tmp0 + tmp3 + (1 << (pass1Bits - 1));
+ int tmp10 = tmp0 + tmp3 + (1 << (Pass1Bits - 1));
int tmp12 = tmp0 - tmp3;
int tmp11 = tmp1 + tmp2;
int tmp13 = tmp1 - tmp2;
- tmp0 = b[x] - b[56 + x];
- tmp1 = b[8 + x] - b[48 + x];
- tmp2 = b[16 + x] - b[40 + x];
- tmp3 = b[24 + x] - b[32 + x];
+ tmp0 = block[x] - block[56 + x];
+ tmp1 = block[8 + x] - block[48 + x];
+ tmp2 = block[16 + x] - block[40 + x];
+ tmp3 = block[24 + x] - block[32 + x];
- b[x] = (tmp10 + tmp11) >> pass1Bits;
- b[32 + x] = (tmp10 - tmp11) >> pass1Bits;
+ block[x] = (tmp10 + tmp11) >> Pass1Bits;
+ block[32 + x] = (tmp10 - tmp11) >> Pass1Bits;
int z1 = (tmp12 + tmp13) * fix_0_541196100;
- z1 += 1 << (constBits + pass1Bits - 1);
- b[16 + x] = (z1 + tmp12 * fix_0_765366865) >> (constBits + pass1Bits);
- b[48 + x] = (z1 - tmp13 * fix_1_847759065) >> (constBits + pass1Bits);
+ z1 += 1 << (Bits + Pass1Bits - 1);
+ block[16 + x] = (z1 + (tmp12 * fix_0_765366865)) >> (Bits + Pass1Bits);
+ block[48 + x] = (z1 - (tmp13 * fix_1_847759065)) >> (Bits + Pass1Bits);
tmp10 = tmp0 + tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp0 + tmp2;
tmp13 = tmp1 + tmp3;
z1 = (tmp12 + tmp13) * fix_1_175875602;
- z1 += 1 << (constBits + pass1Bits - 1);
+ z1 += 1 << (Bits + Pass1Bits - 1);
tmp0 = tmp0 * fix_1_501321110;
tmp1 = tmp1 * fix_3_072711026;
tmp2 = tmp2 * fix_2_053119869;
@@ -131,10 +151,10 @@ namespace ImageProcessorCore.Formats
tmp12 += z1;
tmp13 += z1;
- b[8 + x] = (tmp0 + tmp10 + tmp12) >> (constBits + pass1Bits);
- b[24 + x] = (tmp1 + tmp11 + tmp13) >> (constBits + pass1Bits);
- b[40 + x] = (tmp2 + tmp11 + tmp12) >> (constBits + pass1Bits);
- b[56 + x] = (tmp3 + tmp10 + tmp13) >> (constBits + pass1Bits);
+ block[8 + x] = (tmp0 + tmp10 + tmp12) >> (Bits + Pass1Bits);
+ block[24 + x] = (tmp1 + tmp11 + tmp13) >> (Bits + Pass1Bits);
+ block[40 + x] = (tmp2 + tmp11 + tmp12) >> (Bits + Pass1Bits);
+ block[56 + x] = (tmp3 + tmp10 + tmp13) >> (Bits + Pass1Bits);
}
}
}
diff --git a/src/ImageProcessorCore/Formats/Jpg/JpegConstants.cs b/src/ImageProcessorCore/Formats/Jpg/JpegConstants.cs
new file mode 100644
index 0000000000..27514d667f
--- /dev/null
+++ b/src/ImageProcessorCore/Formats/Jpg/JpegConstants.cs
@@ -0,0 +1,171 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Formats
+{
+ ///
+ /// Defines jpeg constants defined in the specification.
+ ///
+ internal static class JpegConstants
+ {
+ ///
+ /// The maximum allowable length in each dimension of a jpeg image.
+ ///
+ public const ushort MaxLength = 65535;
+
+ ///
+ /// Represents high detail chroma horizontal subsampling.
+ ///
+ public static readonly byte[] ChromaFourFourFourHorizontal = { 1, 1, 1 };
+
+ ///
+ /// Represents high detail chroma vertical subsampling.
+ ///
+ public static readonly byte[] ChromaFourFourFourVertical = { 1, 1, 1 };
+
+ ///
+ /// Represents medium detail chroma horizontal subsampling.
+ ///
+ public static readonly byte[] ChromaFourTwoTwoHorizontal = { 2, 1, 1 };
+
+ ///
+ /// Represents medium detail chroma vertical subsampling.
+ ///
+ public static readonly byte[] ChromaFourTwoTwoVertical = { 1, 1, 1 };
+
+ ///
+ /// Represents low detail chroma horizontal subsampling.
+ ///
+ public static readonly byte[] ChromaFourTwoZeroHorizontal = { 2, 1, 1 };
+
+ ///
+ /// Represents low detail chroma vertical subsampling.
+ ///
+ public static readonly byte[] ChromaFourTwoZeroVertical = { 2, 1, 1 };
+
+ ///
+ /// Describes component ids for start of frame components.
+ ///
+ internal static class Components
+ {
+ ///
+ /// The YCbCr luminance component id.
+ ///
+ public const byte Y = 1;
+
+ ///
+ /// The YCbCr chroma component id.
+ ///
+ public const byte Cb = 2;
+
+ ///
+ /// The YCbCr chroma component id.
+ ///
+ public const byte Cr = 3;
+
+ ///
+ /// The YIQ x coordinate component id.
+ ///
+ public const byte I = 4;
+
+ ///
+ /// The YIQ y coordinate component id.
+ ///
+ public const byte Q = 5;
+ }
+
+ ///
+ /// Describes common Jpeg markers
+ ///
+ internal static class Markers
+ {
+ ///
+ /// Marker prefix. Next byte is a marker.
+ ///
+ public const byte XFF = 0xff;
+
+ ///
+ /// Start of Image
+ ///
+ public const byte SOI = 0xd8;
+
+ ///
+ /// 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 byte SOF0 = 0xc0;
+
+ ///
+ /// 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 byte SOF2 = 0xc0;
+
+ ///
+ /// Define Huffman Table(s)
+ ///
+ /// Specifies one or more Huffman tables.
+ ///
+ ///
+ public const byte DHT = 0xc4;
+
+ ///
+ /// Define Quantization Table(s)
+ ///
+ /// Specifies one or more quantization tables.
+ ///
+ ///
+ public const byte DQT = 0xdb;
+
+ ///
+ /// 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 byte DRI = 0xdd;
+
+ ///
+ /// 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 byte SOS = 0xda;
+
+ ///
+ /// Comment
+ ///
+ /// Contains a text comment.
+ ///
+ ///
+ public const byte COM = 0xfe;
+
+ ///
+ /// End of Image
+ ///
+ public const byte EOI = 0xd9;
+
+ ///
+ /// Application specific marker for marking the jpeg format.
+ ///
+ public const byte APP0 = 0xe0;
+
+ ///
+ /// Application specific marker for marking where to store metadata.
+ ///
+ public const byte APP1 = 0xe1;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id b/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id
index 6cf3cee55e..8d3e51867e 100644
--- a/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id
+++ b/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id
@@ -1 +1 @@
-07d53b1f9ee1e867cfd8bb664c2cf3f31c0e8289
\ No newline at end of file
+af4a353d1d290be5dd231656bdb558fcdc143805
\ No newline at end of file
diff --git a/src/ImageProcessorCore/Formats/Jpg/JpegEncoderCore.cs b/src/ImageProcessorCore/Formats/Jpg/JpegEncoderCore.cs
index a1f49a0c83..f211e05f8b 100644
--- a/src/ImageProcessorCore/Formats/Jpg/JpegEncoderCore.cs
+++ b/src/ImageProcessorCore/Formats/Jpg/JpegEncoderCore.cs
@@ -298,7 +298,7 @@ namespace ImageProcessorCore.Formats
// writeDQT writes the Define Quantization Table marker.
private void writeDQT()
{
- int markerlen = 2 + nQuantIndex * (1 + Block.blockSize);
+ int markerlen = 2 + nQuantIndex * (1 + Block.BlockSize);
writeMarkerHeader(dqtMarker, markerlen);
for (int i = 0; i < nQuantIndex; i++)
{
@@ -396,7 +396,7 @@ namespace ImageProcessorCore.Formats
var h = (huffIndex)(2 * (int)q + 1);
int runLength = 0;
- for (int zig = 1; zig < Block.blockSize; zig++)
+ for (int zig = 1; zig < Block.BlockSize; zig++)
{
int ac = div(b[unzig[zig]], 8 * quant[(int)q][zig]);
@@ -567,7 +567,7 @@ namespace ImageProcessorCore.Formats
for (int i = 0; i < nQuantIndex; i++)
{
- quant[i] = new byte[Block.blockSize];
+ quant[i] = new byte[Block.BlockSize];
}
if (image.Width >= (1 << 16) || image.Height >= (1 << 16))
@@ -592,7 +592,7 @@ namespace ImageProcessorCore.Formats
// Initialize the quantization tables.
for (int i = 0; i < nQuantIndex; i++)
{
- for (int j = 0; j < Block.blockSize; j++)
+ for (int j = 0; j < Block.BlockSize; j++)
{
int x = unscaledQuant[i, j];
x = (x * scale + 50) / 100;