Browse Source

refactor OldComponent: it's class again + got moved in some logic

af/merge-core
Anton Firszov 9 years ago
parent
commit
97685f1c42
  1. 2
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockProcessor.cs
  2. 199
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldComponent.cs
  3. 10
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.cs
  4. 188
      src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs

2
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) private void ProcessBlockColors(OldJpegDecoderCore decoder, ref DecodedBlock decodedBlock)
{ {
this.data.Block = decodedBlock.Block; 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]; this.data.QuantiazationTable = decoder.QuantizationTables[qtIndex];
Block8x8F* b = this.pointers.Block; Block8x8F* b = this.pointers.Block;

199
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldComponent.cs

@ -3,29 +3,210 @@
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{ {
using System;
using SixLabors.ImageSharp.Memory;
/// <summary> /// <summary>
/// Represents a single color component /// Represents a single color component
/// </summary> /// </summary>
internal struct OldComponent internal class OldComponent
{ {
public OldComponent(byte identifier, int index)
{
this.Identifier = identifier;
this.Index = index;
}
/// <summary> /// <summary>
/// Gets or sets the horizontal sampling factor. /// Gets the identifier
/// </summary> /// </summary>
public int HorizontalFactor; public byte Identifier { get; }
/// <summary> /// <summary>
/// Gets or sets the vertical sampling factor. /// Gets the component's position in <see cref="OldJpegDecoderCore.Components"/>
/// </summary> /// </summary>
public int VerticalFactor; public int Index { get; }
/// <summary> /// <summary>
/// Gets or sets the identifier /// Gets the horizontal sampling factor.
/// </summary> /// </summary>
public byte Identifier; public int HorizontalFactor { get; private set; }
/// <summary> /// <summary>
/// Gets or sets the quantization table destination selector. /// Gets the vertical sampling factor.
/// </summary> /// </summary>
public byte Selector; public int VerticalFactor { get; private set; }
/// <summary>
/// Gets the quantization table destination selector.
/// </summary>
public byte Selector { get; private set; }
public Buffer<DecodedBlock> DecodedBlocks { get; private set; }
/// <summary>
/// Initializes <see cref="DecodedBlocks"/>
/// </summary>
/// <param name="decoder">The <see cref="OldJpegDecoderCore"/> instance</param>
public void InitializeBlocks(OldJpegDecoderCore decoder)
{
// TODO: count could be component and JpegSubsample specific:
int count = decoder.TotalMCUCount * this.HorizontalFactor * this.VerticalFactor;
this.DecodedBlocks = Buffer<DecodedBlock>.CreateClean(count);
}
/// <summary>
/// Initializes all component data except <see cref="DecodedBlocks"/>.
/// </summary>
/// <param name="decoder">The <see cref="OldJpegDecoderCore"/> instance</param>
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;
}
} }
} }

10
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++) for (int scanIndex = 0; scanIndex < this.componentScanCount; scanIndex++)
{ {
this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex; this.ComponentIndex = this.pointers.ComponentScan[scanIndex].ComponentIndex;
this.hi = decoder.ComponentArray[this.ComponentIndex].HorizontalFactor; this.hi = decoder.Components[this.ComponentIndex].HorizontalFactor;
int vi = decoder.ComponentArray[this.ComponentIndex].VerticalFactor; int vi = decoder.Components[this.ComponentIndex].VerticalFactor;
for (int j = 0; j < this.hi * vi; j++) 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++) for (int j = 0; j < decoder.ComponentCount; j++)
{ {
// Component compv = ; // Component compv = ;
if (cs == decoder.ComponentArray[j].Identifier) if (cs == decoder.Components[j].Identifier)
{ {
compIndex = j; compIndex = j;
} }
@ -453,7 +453,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
currentComponentScan.ComponentIndex = (byte)compIndex; 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( private void ProcessComponentImpl(
@ -461,7 +461,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
int i, int i,
ref OldComponentScan currentComponentScan, ref OldComponentScan currentComponentScan,
ref int totalHv, ref int totalHv,
ref OldComponent currentComponent) OldComponent currentComponent)
{ {
// Section B.2.3 states that "the value of Cs_j shall be different from // 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 // the values of Cs_1 through Cs_(j-1)". Since we have previously

188
src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs

@ -107,14 +107,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.HuffmanTrees = OldHuffmanTree.CreateHuffmanTrees(); this.HuffmanTrees = OldHuffmanTree.CreateHuffmanTrees();
this.QuantizationTables = new Block8x8F[MaxTq + 1]; this.QuantizationTables = new Block8x8F[MaxTq + 1];
this.Temp = new byte[2 * Block8x8F.ScalarCount]; this.Temp = new byte[2 * Block8x8F.ScalarCount];
this.ComponentArray = new OldComponent[MaxComponents];
this.DecodedBlocks = new Buffer<DecodedBlock>[MaxComponents]; this.DecodedBlocks = new Buffer<DecodedBlock>[MaxComponents];
} }
/// <summary> /// <summary>
/// Gets the component array /// Gets the component array
/// </summary> /// </summary>
public OldComponent[] ComponentArray { get; } public OldComponent[] Components { get; private set; }
/// <summary> /// <summary>
/// Gets the huffman trees /// Gets the huffman trees
@ -576,7 +575,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromCmyk<TPixel>(Image<TPixel> image) private void ConvertFromCmyk<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor; int scale = this.Components[0].HorizontalFactor / this.Components[1].HorizontalFactor;
using (PixelAccessor<TPixel> pixels = image.Lock()) using (PixelAccessor<TPixel> pixels = image.Lock())
{ {
@ -642,7 +641,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromRGB<TPixel>(Image<TPixel> image) private void ConvertFromRGB<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor; int scale = this.Components[0].HorizontalFactor / this.Components[1].HorizontalFactor;
Parallel.For( Parallel.For(
0, 0,
@ -679,7 +678,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromYCbCr<TPixel>(Image<TPixel> image) private void ConvertFromYCbCr<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor; int scale = this.Components[0].HorizontalFactor / this.Components[1].HorizontalFactor;
using (PixelAccessor<TPixel> pixels = image.Lock()) using (PixelAccessor<TPixel> pixels = image.Lock())
{ {
Parallel.For( Parallel.For(
@ -724,7 +723,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromYcck<TPixel>(Image<TPixel> image) private void ConvertFromYcck<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor; int scale = this.Components[0].HorizontalFactor / this.Components[1].HorizontalFactor;
Parallel.For( Parallel.For(
0, 0,
@ -770,8 +769,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
return true; return true;
} }
return this.ComponentArray[0].Identifier == 'R' && this.ComponentArray[1].Identifier == 'G' return this.Components[0].Identifier == 'R' && this.Components[1].Identifier == 'G'
&& this.ComponentArray[2].Identifier == 'B'; && this.Components[2].Identifier == 'B';
} }
/// <summary> /// <summary>
@ -791,10 +790,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
} }
else else
{ {
int h0 = this.ComponentArray[0].HorizontalFactor; int h0 = this.Components[0].HorizontalFactor;
int v0 = this.ComponentArray[0].VerticalFactor; int v0 = this.Components[0].VerticalFactor;
int horizontalRatio = h0 / this.ComponentArray[1].HorizontalFactor; int horizontalRatio = h0 / this.Components[1].HorizontalFactor;
int verticalRatio = v0 / this.ComponentArray[1].VerticalFactor; int verticalRatio = v0 / this.Components[1].VerticalFactor;
YCbCrImage.YCbCrSubsampleRatio ratio = YCbCrImage.YCbCrSubsampleRatio.YCbCrSubsampleRatio444; YCbCrImage.YCbCrSubsampleRatio ratio = YCbCrImage.YCbCrSubsampleRatio.YCbCrSubsampleRatio444;
switch ((horizontalRatio << 4) | verticalRatio) switch ((horizontalRatio << 4) | verticalRatio)
@ -823,10 +822,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
if (this.ComponentCount == 4) if (this.ComponentCount == 4)
{ {
int h3 = this.ComponentArray[3].HorizontalFactor; int h3 = this.Components[3].HorizontalFactor;
int v3 = this.ComponentArray[3].VerticalFactor; int v3 = this.Components[3].VerticalFactor;
Buffer2D<byte> buffer = Buffer2D<byte>.CreateClean(8 * h3 * this.MCUCountX, 8 * v3 * this.MCUCountY); var buffer = Buffer2D<byte>.CreateClean(8 * h3 * this.MCUCountX, 8 * v3 * this.MCUCountY);
this.blackImage = new OldJpegPixelArea(buffer); this.blackImage = new OldJpegPixelArea(buffer);
} }
} }
@ -1208,165 +1207,26 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
throw new ImageFormatException("SOF has wrong length"); throw new ImageFormatException("SOF has wrong length");
} }
this.Components = new OldComponent[this.ComponentCount];
for (int i = 0; i < this.ComponentCount; i++) for (int i = 0; i < this.ComponentCount; i++)
{ {
this.ComponentArray[i].Identifier = this.Temp[6 + (3 * i)]; byte componentIdentifier = this.Temp[6 + (3 * i)];
var component = new OldComponent(componentIdentifier, i);
// Section B.2.2 states that "the value of C_i shall be different from component.InitializeData(this);
// the values of C_1 through C_(i-1)". this.Components[i] = component;
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;
} }
int h0 = this.ComponentArray[0].HorizontalFactor; int h0 = this.Components[0].HorizontalFactor;
int v0 = this.ComponentArray[0].VerticalFactor; int v0 = this.Components[0].VerticalFactor;
this.MCUCountX = (this.ImageWidth + (8 * h0) - 1) / (8 * h0); this.MCUCountX = (this.ImageWidth + (8 * h0) - 1) / (8 * h0);
this.MCUCountY = (this.ImageHeight + (8 * v0) - 1) / (8 * v0); 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! // As a preparation for parallelizing Scan decoder, we also allocate DecodedBlocks in the non-progressive case!
for (int i = 0; i < this.ComponentCount; i++) for (int i = 0; i < this.ComponentCount; i++)
{ {
int count = this.TotalMCUCount * this.ComponentArray[i].HorizontalFactor int count = this.TotalMCUCount * this.Components[i].HorizontalFactor
* this.ComponentArray[i].VerticalFactor; * this.Components[i].VerticalFactor;
this.DecodedBlocks[i] = Buffer<DecodedBlock>.CreateClean(count); this.DecodedBlocks[i] = Buffer<DecodedBlock>.CreateClean(count);
} }
} }

Loading…
Cancel
Save