diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockProcessor.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockProcessor.cs
index ba4a42127..a6c4e4f1a 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockProcessor.cs
@@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
private void ProcessBlockColors(OldJpegDecoderCore decoder, ref DecodedBlock decodedBlock)
{
this.data.Block = decodedBlock.Block;
- int qtIndex = decoder.ComponentArray[this.componentIndex].Selector;
+ int qtIndex = decoder.Components[this.componentIndex].Selector;
this.data.QuantiazationTable = decoder.QuantizationTables[qtIndex];
Block8x8F* b = this.pointers.Block;
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldComponent.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldComponent.cs
index 3f1f70b20..dca131961 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldComponent.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldComponent.cs
@@ -3,29 +3,210 @@
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
+ using System;
+
+ using SixLabors.ImageSharp.Memory;
+
///
/// Represents a single color component
///
- internal struct OldComponent
+ internal class OldComponent
{
+ public OldComponent(byte identifier, int index)
+ {
+ this.Identifier = identifier;
+ this.Index = index;
+ }
+
///
- /// Gets or sets the horizontal sampling factor.
+ /// Gets the identifier
///
- public int HorizontalFactor;
+ public byte Identifier { get; }
///
- /// Gets or sets the vertical sampling factor.
+ /// Gets the component's position in
///
- public int VerticalFactor;
+ public int Index { get; }
///
- /// Gets or sets the identifier
+ /// Gets the horizontal sampling factor.
///
- public byte Identifier;
+ public int HorizontalFactor { get; private set; }
///
- /// Gets or sets the quantization table destination selector.
+ /// Gets the vertical sampling factor.
///
- public byte Selector;
+ public int VerticalFactor { get; private set; }
+
+ ///
+ /// Gets the quantization table destination selector.
+ ///
+ public byte Selector { get; private set; }
+
+ public Buffer DecodedBlocks { get; private set; }
+
+ ///
+ /// Initializes
+ ///
+ /// The instance
+ public void InitializeBlocks(OldJpegDecoderCore decoder)
+ {
+ // TODO: count could be component and JpegSubsample specific:
+ int count = decoder.TotalMCUCount * this.HorizontalFactor * this.VerticalFactor;
+ this.DecodedBlocks = Buffer.CreateClean(count);
+ }
+
+ ///
+ /// Initializes all component data except .
+ ///
+ /// The instance
+ public void InitializeData(OldJpegDecoderCore decoder)
+ {
+ // Section B.2.2 states that "the value of C_i shall be different from
+ // the values of C_1 through C_(i-1)".
+ int i = this.Index;
+
+ for (int j = 0; j < this.Index; j++)
+ {
+ if (this.Identifier == decoder.Components[j].Identifier)
+ {
+ throw new ImageFormatException("Repeated component identifier");
+ }
+ }
+
+ this.Selector = decoder.Temp[8 + (3 * i)];
+ if (this.Selector > OldJpegDecoderCore.MaxTq)
+ {
+ throw new ImageFormatException("Bad Tq value");
+ }
+
+ byte hv = decoder.Temp[7 + (3 * i)];
+ int h = hv >> 4;
+ int v = hv & 0x0f;
+ if (h < 1 || h > 4 || v < 1 || v > 4)
+ {
+ throw new ImageFormatException("Unsupported Luma/chroma subsampling ratio");
+ }
+
+ if (h == 3 || v == 3)
+ {
+ throw new ImageFormatException("Lnsupported subsampling ratio");
+ }
+
+ switch (decoder.ComponentCount)
+ {
+ case 1:
+
+ // If a JPEG image has only one component, section A.2 says "this data
+ // is non-interleaved by definition" and section A.2.2 says "[in this
+ // case...] the order of data units within a scan shall be left-to-right
+ // and top-to-bottom... regardless of the values of H_1 and V_1". Section
+ // 4.8.2 also says "[for non-interleaved data], the MCU is defined to be
+ // one data unit". Similarly, section A.1.1 explains that it is the ratio
+ // of H_i to max_j(H_j) that matters, and similarly for V. For grayscale
+ // images, H_1 is the maximum H_j for all components j, so that ratio is
+ // always 1. The component's (h, v) is effectively always (1, 1): even if
+ // the nominal (h, v) is (2, 1), a 20x5 image is encoded in three 8x8
+ // MCUs, not two 16x8 MCUs.
+ h = 1;
+ v = 1;
+ break;
+
+ case 3:
+
+ // For YCbCr images, we only support 4:4:4, 4:4:0, 4:2:2, 4:2:0,
+ // 4:1:1 or 4:1:0 chroma subsampling ratios. This implies that the
+ // (h, v) values for the Y component are either (1, 1), (1, 2),
+ // (2, 1), (2, 2), (4, 1) or (4, 2), and the Y component's values
+ // must be a multiple of the Cb and Cr component's values. We also
+ // assume that the two chroma components have the same subsampling
+ // ratio.
+ switch (i)
+ {
+ case 0:
+ {
+ // Y.
+ // We have already verified, above, that h and v are both
+ // either 1, 2 or 4, so invalid (h, v) combinations are those
+ // with v == 4.
+ if (v == 4)
+ {
+ throw new ImageFormatException("Unsupported subsampling ratio");
+ }
+
+ break;
+ }
+
+ case 1:
+ {
+ // Cb.
+ if (decoder.Components[0].HorizontalFactor % h != 0
+ || decoder.Components[0].VerticalFactor % v != 0)
+ {
+ throw new ImageFormatException("Unsupported subsampling ratio");
+ }
+
+ break;
+ }
+
+ case 2:
+ {
+ // Cr.
+ if (decoder.Components[1].HorizontalFactor != h
+ || decoder.Components[1].VerticalFactor != v)
+ {
+ throw new ImageFormatException("Unsupported subsampling ratio");
+ }
+
+ break;
+ }
+ }
+
+ break;
+
+ case 4:
+
+ // For 4-component images (either CMYK or YCbCrK), we only support two
+ // hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
+ // Theoretically, 4-component JPEG images could mix and match hv values
+ // but in practice, those two combinations are the only ones in use,
+ // and it simplifies the applyBlack code below if we can assume that:
+ // - for CMYK, the C and K channels have full samples, and if the M
+ // and Y channels subsample, they subsample both horizontally and
+ // vertically.
+ // - for YCbCrK, the Y and K channels have full samples.
+ switch (i)
+ {
+ case 0:
+ if (hv != 0x11 && hv != 0x22)
+ {
+ throw new ImageFormatException("Unsupported subsampling ratio");
+ }
+
+ break;
+ case 1:
+ case 2:
+ if (hv != 0x11)
+ {
+ throw new ImageFormatException("Unsupported subsampling ratio");
+ }
+
+ break;
+ case 3:
+ if (decoder.Components[0].HorizontalFactor != h
+ || decoder.Components[0].VerticalFactor != v)
+ {
+ throw new ImageFormatException("Unsupported subsampling ratio");
+ }
+
+ break;
+ }
+
+ break;
+ }
+
+ this.HorizontalFactor = h;
+ this.VerticalFactor = v;
+ }
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.cs
index 81e9a5034..7fd6276d8 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.cs
@@ -147,8 +147,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
for (int scanIndex = 0; scanIndex < this.componentScanCount; scanIndex++)
{
this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex;
- this.hi = decoder.ComponentArray[this.ComponentIndex].HorizontalFactor;
- int vi = decoder.ComponentArray[this.ComponentIndex].VerticalFactor;
+ this.hi = decoder.Components[this.ComponentIndex].HorizontalFactor;
+ int vi = decoder.Components[this.ComponentIndex].VerticalFactor;
for (int j = 0; j < this.hi * vi; j++)
{
@@ -440,7 +440,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
for (int j = 0; j < decoder.ComponentCount; j++)
{
// Component compv = ;
- if (cs == decoder.ComponentArray[j].Identifier)
+ if (cs == decoder.Components[j].Identifier)
{
compIndex = j;
}
@@ -453,7 +453,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
currentComponentScan.ComponentIndex = (byte)compIndex;
- this.ProcessComponentImpl(decoder, i, ref currentComponentScan, ref totalHv, ref decoder.ComponentArray[compIndex]);
+ this.ProcessComponentImpl(decoder, i, ref currentComponentScan, ref totalHv, decoder.Components[compIndex]);
}
private void ProcessComponentImpl(
@@ -461,7 +461,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
int i,
ref OldComponentScan currentComponentScan,
ref int totalHv,
- ref OldComponent currentComponent)
+ OldComponent currentComponent)
{
// Section B.2.3 states that "the value of Cs_j shall be different from
// the values of Cs_1 through Cs_(j-1)". Since we have previously
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs
index 765c5f39a..250e6e0d2 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs
@@ -107,14 +107,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.HuffmanTrees = OldHuffmanTree.CreateHuffmanTrees();
this.QuantizationTables = new Block8x8F[MaxTq + 1];
this.Temp = new byte[2 * Block8x8F.ScalarCount];
- this.ComponentArray = new OldComponent[MaxComponents];
this.DecodedBlocks = new Buffer[MaxComponents];
}
///
/// Gets the component array
///
- public OldComponent[] ComponentArray { get; }
+ public OldComponent[] Components { get; private set; }
///
/// Gets the huffman trees
@@ -576,7 +575,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromCmyk(Image image)
where TPixel : struct, IPixel
{
- int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
+ int scale = this.Components[0].HorizontalFactor / this.Components[1].HorizontalFactor;
using (PixelAccessor pixels = image.Lock())
{
@@ -642,7 +641,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromRGB(Image image)
where TPixel : struct, IPixel
{
- int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
+ int scale = this.Components[0].HorizontalFactor / this.Components[1].HorizontalFactor;
Parallel.For(
0,
@@ -679,7 +678,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromYCbCr(Image image)
where TPixel : struct, IPixel
{
- int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
+ int scale = this.Components[0].HorizontalFactor / this.Components[1].HorizontalFactor;
using (PixelAccessor pixels = image.Lock())
{
Parallel.For(
@@ -724,7 +723,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromYcck(Image image)
where TPixel : struct, IPixel
{
- int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
+ int scale = this.Components[0].HorizontalFactor / this.Components[1].HorizontalFactor;
Parallel.For(
0,
@@ -770,8 +769,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
return true;
}
- return this.ComponentArray[0].Identifier == 'R' && this.ComponentArray[1].Identifier == 'G'
- && this.ComponentArray[2].Identifier == 'B';
+ return this.Components[0].Identifier == 'R' && this.Components[1].Identifier == 'G'
+ && this.Components[2].Identifier == 'B';
}
///
@@ -791,10 +790,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
else
{
- int h0 = this.ComponentArray[0].HorizontalFactor;
- int v0 = this.ComponentArray[0].VerticalFactor;
- int horizontalRatio = h0 / this.ComponentArray[1].HorizontalFactor;
- int verticalRatio = v0 / this.ComponentArray[1].VerticalFactor;
+ int h0 = this.Components[0].HorizontalFactor;
+ int v0 = this.Components[0].VerticalFactor;
+ int horizontalRatio = h0 / this.Components[1].HorizontalFactor;
+ int verticalRatio = v0 / this.Components[1].VerticalFactor;
YCbCrImage.YCbCrSubsampleRatio ratio = YCbCrImage.YCbCrSubsampleRatio.YCbCrSubsampleRatio444;
switch ((horizontalRatio << 4) | verticalRatio)
@@ -823,10 +822,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
if (this.ComponentCount == 4)
{
- int h3 = this.ComponentArray[3].HorizontalFactor;
- int v3 = this.ComponentArray[3].VerticalFactor;
+ int h3 = this.Components[3].HorizontalFactor;
+ int v3 = this.Components[3].VerticalFactor;
- Buffer2D buffer = Buffer2D.CreateClean(8 * h3 * this.MCUCountX, 8 * v3 * this.MCUCountY);
+ var buffer = Buffer2D.CreateClean(8 * h3 * this.MCUCountX, 8 * v3 * this.MCUCountY);
this.blackImage = new OldJpegPixelArea(buffer);
}
}
@@ -1208,165 +1207,26 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
throw new ImageFormatException("SOF has wrong length");
}
+ this.Components = new OldComponent[this.ComponentCount];
+
for (int i = 0; i < this.ComponentCount; i++)
{
- this.ComponentArray[i].Identifier = this.Temp[6 + (3 * i)];
-
- // Section B.2.2 states that "the value of C_i shall be different from
- // the values of C_1 through C_(i-1)".
- for (int j = 0; j < i; j++)
- {
- if (this.ComponentArray[i].Identifier == this.ComponentArray[j].Identifier)
- {
- throw new ImageFormatException("Repeated component identifier");
- }
- }
-
- this.ComponentArray[i].Selector = this.Temp[8 + (3 * i)];
- if (this.ComponentArray[i].Selector > MaxTq)
- {
- throw new ImageFormatException("Bad Tq value");
- }
-
- byte hv = this.Temp[7 + (3 * i)];
- int h = hv >> 4;
- int v = hv & 0x0f;
- if (h < 1 || h > 4 || v < 1 || v > 4)
- {
- throw new ImageFormatException("Unsupported Luma/chroma subsampling ratio");
- }
-
- if (h == 3 || v == 3)
- {
- throw new ImageFormatException("Lnsupported subsampling ratio");
- }
-
- switch (this.ComponentCount)
- {
- case 1:
-
- // If a JPEG image has only one component, section A.2 says "this data
- // is non-interleaved by definition" and section A.2.2 says "[in this
- // case...] the order of data units within a scan shall be left-to-right
- // and top-to-bottom... regardless of the values of H_1 and V_1". Section
- // 4.8.2 also says "[for non-interleaved data], the MCU is defined to be
- // one data unit". Similarly, section A.1.1 explains that it is the ratio
- // of H_i to max_j(H_j) that matters, and similarly for V. For grayscale
- // images, H_1 is the maximum H_j for all components j, so that ratio is
- // always 1. The component's (h, v) is effectively always (1, 1): even if
- // the nominal (h, v) is (2, 1), a 20x5 image is encoded in three 8x8
- // MCUs, not two 16x8 MCUs.
- h = 1;
- v = 1;
- break;
-
- case 3:
-
- // For YCbCr images, we only support 4:4:4, 4:4:0, 4:2:2, 4:2:0,
- // 4:1:1 or 4:1:0 chroma subsampling ratios. This implies that the
- // (h, v) values for the Y component are either (1, 1), (1, 2),
- // (2, 1), (2, 2), (4, 1) or (4, 2), and the Y component's values
- // must be a multiple of the Cb and Cr component's values. We also
- // assume that the two chroma components have the same subsampling
- // ratio.
- switch (i)
- {
- case 0:
- {
- // Y.
- // We have already verified, above, that h and v are both
- // either 1, 2 or 4, so invalid (h, v) combinations are those
- // with v == 4.
- if (v == 4)
- {
- throw new ImageFormatException("Unsupported subsampling ratio");
- }
-
- break;
- }
-
- case 1:
- {
- // Cb.
- if (this.ComponentArray[0].HorizontalFactor % h != 0
- || this.ComponentArray[0].VerticalFactor % v != 0)
- {
- throw new ImageFormatException("Unsupported subsampling ratio");
- }
-
- break;
- }
-
- case 2:
- {
- // Cr.
- if (this.ComponentArray[1].HorizontalFactor != h
- || this.ComponentArray[1].VerticalFactor != v)
- {
- throw new ImageFormatException("Unsupported subsampling ratio");
- }
-
- break;
- }
- }
-
- break;
-
- case 4:
-
- // For 4-component images (either CMYK or YCbCrK), we only support two
- // hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
- // Theoretically, 4-component JPEG images could mix and match hv values
- // but in practice, those two combinations are the only ones in use,
- // and it simplifies the applyBlack code below if we can assume that:
- // - for CMYK, the C and K channels have full samples, and if the M
- // and Y channels subsample, they subsample both horizontally and
- // vertically.
- // - for YCbCrK, the Y and K channels have full samples.
- switch (i)
- {
- case 0:
- if (hv != 0x11 && hv != 0x22)
- {
- throw new ImageFormatException("Unsupported subsampling ratio");
- }
-
- break;
- case 1:
- case 2:
- if (hv != 0x11)
- {
- throw new ImageFormatException("Unsupported subsampling ratio");
- }
-
- break;
- case 3:
- if (this.ComponentArray[0].HorizontalFactor != h
- || this.ComponentArray[0].VerticalFactor != v)
- {
- throw new ImageFormatException("Unsupported subsampling ratio");
- }
-
- break;
- }
-
- break;
- }
-
- this.ComponentArray[i].HorizontalFactor = h;
- this.ComponentArray[i].VerticalFactor = v;
+ byte componentIdentifier = this.Temp[6 + (3 * i)];
+ var component = new OldComponent(componentIdentifier, i);
+ component.InitializeData(this);
+ this.Components[i] = component;
}
- int h0 = this.ComponentArray[0].HorizontalFactor;
- int v0 = this.ComponentArray[0].VerticalFactor;
+ int h0 = this.Components[0].HorizontalFactor;
+ int v0 = this.Components[0].VerticalFactor;
this.MCUCountX = (this.ImageWidth + (8 * h0) - 1) / (8 * h0);
this.MCUCountY = (this.ImageHeight + (8 * v0) - 1) / (8 * v0);
// As a preparation for parallelizing Scan decoder, we also allocate DecodedBlocks in the non-progressive case!
for (int i = 0; i < this.ComponentCount; i++)
{
- int count = this.TotalMCUCount * this.ComponentArray[i].HorizontalFactor
- * this.ComponentArray[i].VerticalFactor;
+ int count = this.TotalMCUCount * this.Components[i].HorizontalFactor
+ * this.Components[i].VerticalFactor;
this.DecodedBlocks[i] = Buffer.CreateClean(count);
}
}