Browse Source

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

pull/322/head
Anton Firszov 9 years ago
parent
commit
a25ecc961e
  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)
{
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;

199
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;
/// <summary>
/// Represents a single color component
/// </summary>
internal struct OldComponent
internal class OldComponent
{
public OldComponent(byte identifier, int index)
{
this.Identifier = identifier;
this.Index = index;
}
/// <summary>
/// Gets or sets the horizontal sampling factor.
/// Gets the identifier
/// </summary>
public int HorizontalFactor;
public byte Identifier { get; }
/// <summary>
/// Gets or sets the vertical sampling factor.
/// Gets the component's position in <see cref="OldJpegDecoderCore.Components"/>
/// </summary>
public int VerticalFactor;
public int Index { get; }
/// <summary>
/// Gets or sets the identifier
/// Gets the horizontal sampling factor.
/// </summary>
public byte Identifier;
public int HorizontalFactor { get; private set; }
/// <summary>
/// Gets or sets the quantization table destination selector.
/// Gets the vertical sampling factor.
/// </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++)
{
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

188
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<DecodedBlock>[MaxComponents];
}
/// <summary>
/// Gets the component array
/// </summary>
public OldComponent[] ComponentArray { get; }
public OldComponent[] Components { get; private set; }
/// <summary>
/// Gets the huffman trees
@ -576,7 +575,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromCmyk<TPixel>(Image<TPixel> image)
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())
{
@ -642,7 +641,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromRGB<TPixel>(Image<TPixel> image)
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(
0,
@ -679,7 +678,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromYCbCr<TPixel>(Image<TPixel> image)
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())
{
Parallel.For(
@ -724,7 +723,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromYcck<TPixel>(Image<TPixel> image)
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(
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';
}
/// <summary>
@ -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<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);
}
}
@ -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<DecodedBlock>.CreateClean(count);
}
}

Loading…
Cancel
Save