Browse Source

OrigJpegDecoderCore channel management refactor

pull/322/head
Anton Firszov 9 years ago
parent
commit
21afb0565f
  1. 17
      src/ImageSharp/Formats/Jpeg/Common/IJpegComponent.cs
  2. 40
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponent.cs
  3. 6
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs
  4. 21
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/SubsampleRatio.cs
  5. 46
      src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
  6. 16
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs
  7. 40
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs
  8. 4
      src/ImageSharp/Formats/Jpeg/PdfJsPort/JpegDecoderCore.cs
  9. 6
      tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs

17
src/ImageSharp/Formats/Jpeg/Common/IJpegComponent.cs

@ -2,7 +2,24 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
{
internal interface IJpegComponent
{
/// <summary>
/// Gets the number of blocks per line
/// </summary>
int WidthInBlocks { get; }
/// <summary>
/// Gets the number of blocks per column
/// </summary>
int HeightInBlocks { get; }
/// <summary>
/// Gets the horizontal sampling factor.
/// </summary>
int HorizontalSamplingFactor { get; }
/// <summary>
/// Gets the vertical sampling factor.
/// </summary>
int VerticalSamplingFactor { get; }
}
}

40
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigComponent.cs

@ -28,15 +28,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary>
public int Index { get; }
/// <summary>
/// Gets the horizontal sampling factor.
/// </summary>
public int HorizontalFactor { get; private set; }
/// <inheritdoc />
public int HorizontalSamplingFactor { get; private set; }
/// <summary>
/// Gets the vertical sampling factor.
/// </summary>
public int VerticalFactor { get; private set; }
/// <inheritdoc />
public int VerticalSamplingFactor { get; private set; }
/// <summary>
/// Gets the quantization table destination selector.
@ -51,14 +47,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary>
public Buffer2D<Block8x8> SpectralBlocks { get; private set; }
/// <summary>
/// Gets the number of blocks for this component along the X axis
/// </summary>
/// <inheritdoc />
public int WidthInBlocks { get; private set; }
/// <summary>
/// Gets the number of blocks for this component along the Y axis
/// </summary>
/// <inheritdoc />
public int HeightInBlocks { get; private set; }
public ref Block8x8 GetBlockReference(int bx, int by)
@ -72,8 +64,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param>
public void InitializeBlocks(OrigJpegDecoderCore decoder)
{
this.WidthInBlocks = decoder.MCUCountX * this.HorizontalFactor;
this.HeightInBlocks = decoder.MCUCountY * this.VerticalFactor;
this.WidthInBlocks = decoder.MCUCountX * this.HorizontalSamplingFactor;
this.HeightInBlocks = decoder.MCUCountY * this.VerticalSamplingFactor;
this.SpectralBlocks = Buffer2D<Block8x8>.CreateClean(this.WidthInBlocks, this.HeightInBlocks);
}
@ -161,8 +153,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
case 1:
{
// Cb.
if (decoder.Components[0].HorizontalFactor % h != 0
|| decoder.Components[0].VerticalFactor % v != 0)
if (decoder.Components[0].HorizontalSamplingFactor % h != 0
|| decoder.Components[0].VerticalSamplingFactor % v != 0)
{
throw new ImageFormatException("Unsupported subsampling ratio");
}
@ -173,8 +165,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
case 2:
{
// Cr.
if (decoder.Components[1].HorizontalFactor != h
|| decoder.Components[1].VerticalFactor != v)
if (decoder.Components[1].HorizontalSamplingFactor != h
|| decoder.Components[1].VerticalSamplingFactor != v)
{
throw new ImageFormatException("Unsupported subsampling ratio");
}
@ -214,8 +206,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
break;
case 3:
if (decoder.Components[0].HorizontalFactor != h
|| decoder.Components[0].VerticalFactor != v)
if (decoder.Components[0].HorizontalSamplingFactor != h
|| decoder.Components[0].VerticalSamplingFactor != v)
{
throw new ImageFormatException("Unsupported subsampling ratio");
}
@ -226,8 +218,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
break;
}
this.HorizontalFactor = h;
this.VerticalFactor = v;
this.HorizontalSamplingFactor = h;
this.VerticalSamplingFactor = v;
}
public void Dispose()

6
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs

@ -149,8 +149,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.Components[this.ComponentIndex].HorizontalFactor;
int vi = decoder.Components[this.ComponentIndex].VerticalFactor;
this.hi = decoder.Components[this.ComponentIndex].HorizontalSamplingFactor;
int vi = decoder.Components[this.ComponentIndex].VerticalSamplingFactor;
for (int j = 0; j < this.hi * vi; j++)
{
@ -482,7 +482,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
}
totalHv += currentComponent.HorizontalFactor * currentComponent.VerticalFactor;
totalHv += currentComponent.HorizontalSamplingFactor * currentComponent.VerticalSamplingFactor;
currentComponentScan.DcTableSelector = (byte)(decoder.Temp[2 + (2 * i)] >> 4);
if (currentComponentScan.DcTableSelector > OrigHuffmanTree.MaxTh)

21
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/SubsampleRatio.cs

@ -1,5 +1,9 @@
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
using System.Collections.Generic;
using System.Linq;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.Primitives;
/// <summary>
@ -67,6 +71,23 @@
return SubsampleRatio.Ratio444;
}
public static SubsampleRatio GetSubsampleRatio(IEnumerable<IJpegComponent> components)
{
IJpegComponent[] componentArray = components.ToArray();
if (componentArray.Length == 3)
{
int h0 = componentArray[0].HorizontalSamplingFactor;
int v0 = componentArray[0].VerticalSamplingFactor;
int horizontalRatio = h0 / componentArray[1].HorizontalSamplingFactor;
int verticalRatio = v0 / componentArray[1].VerticalSamplingFactor;
return GetSubsampleRatio(horizontalRatio, verticalRatio);
}
else
{
return SubsampleRatio.Undefined;
}
}
/// <summary>
/// Returns the height and width of the chroma components
/// </summary>

46
src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs

@ -456,19 +456,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
OrigJpegScanDecoder scan = default(OrigJpegScanDecoder);
OrigJpegScanDecoder.InitStreamReading(&scan, this, remaining);
this.InputProcessor.Bits = default(Bits);
this.MakeImage();
scan.DecodeBlocks(this);
}
/// <summary>
/// Process the blocks in <see cref="DecodedBlocks"/> into Jpeg image channels (<see cref="YCbCrImage"/> and <see cref="OrigJpegPixelArea"/>)
/// <see cref="DecodedBlocks"/> are in a "raw" frequency-domain form. We need to apply IDCT, dequantization and unzigging to transform them into color-space blocks.
/// Process the blocks in <see cref="OrigComponent.SpectralBlocks"/> into Jpeg image channels (<see cref="YCbCrImage"/> and <see cref="OrigJpegPixelArea"/>)
/// <see cref="OrigComponent.SpectralBlocks"/> are in a "raw" frequency-domain form. We need to apply IDCT, dequantization and unzigging to transform them into color-space blocks.
/// We can copy these blocks into <see cref="OrigJpegPixelArea"/>-s afterwards.
/// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam>
private void ProcessBlocksIntoJpegImageChannels<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
this.InitJpegImageChannels();
Parallel.For(
0,
this.ComponentCount,
@ -577,7 +578,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromCmyk<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>
{
int scale = this.Components[0].HorizontalFactor / this.Components[1].HorizontalFactor;
int scale = this.Components[0].HorizontalSamplingFactor / this.Components[1].HorizontalSamplingFactor;
using (PixelAccessor<TPixel> pixels = image.Lock())
{
@ -643,7 +644,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromRGB<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>
{
int scale = this.Components[0].HorizontalFactor / this.Components[1].HorizontalFactor;
int scale = this.Components[0].HorizontalSamplingFactor / this.Components[1].HorizontalSamplingFactor;
Parallel.For(
0,
@ -680,7 +681,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromYCbCr<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>
{
int scale = this.Components[0].HorizontalFactor / this.Components[1].HorizontalFactor;
int scale = this.Components[0].HorizontalSamplingFactor / this.Components[1].HorizontalSamplingFactor;
using (PixelAccessor<TPixel> pixels = image.Lock())
{
Parallel.For(
@ -725,7 +726,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void ConvertFromYcck<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>
{
int scale = this.Components[0].HorizontalFactor / this.Components[1].HorizontalFactor;
int scale = this.Components[0].HorizontalSamplingFactor / this.Components[1].HorizontalSamplingFactor;
Parallel.For(
0,
@ -778,35 +779,24 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// <summary>
/// Makes the image from the buffer.
/// </summary>
private void MakeImage()
private void InitJpegImageChannels()
{
if (this.grayImage.IsInitialized || this.ycbcrImage != null)
{
return;
}
this.SubsampleRatio = GolangPort.Components.Decoder.SubsampleRatio.Undefined;
if (this.ComponentCount == 1)
{
Buffer2D<byte> buffer = Buffer2D<byte>.CreateClean(8 * this.MCUCountX, 8 * this.MCUCountY);
var buffer = Buffer2D<byte>.CreateClean(8 * this.MCUCountX, 8 * this.MCUCountY);
this.grayImage = new OrigJpegPixelArea(buffer);
}
else
{
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;
int h0 = this.Components[0].HorizontalSamplingFactor;
int v0 = this.Components[0].VerticalSamplingFactor;
SubsampleRatio ratio = Subsampling.GetSubsampleRatio(horizontalRatio, verticalRatio);
this.ycbcrImage = new YCbCrImage(8 * h0 * this.MCUCountX, 8 * v0 * this.MCUCountY, ratio);
this.ycbcrImage = new YCbCrImage(8 * h0 * this.MCUCountX, 8 * v0 * this.MCUCountY, this.SubsampleRatio);
if (this.ComponentCount == 4)
{
int h3 = this.Components[3].HorizontalFactor;
int v3 = this.Components[3].VerticalFactor;
int h3 = this.Components[3].HorizontalSamplingFactor;
int v3 = this.Components[3].VerticalSamplingFactor;
var buffer = Buffer2D<byte>.CreateClean(8 * h3 * this.MCUCountX, 8 * v3 * this.MCUCountY);
this.blackImage = new OrigJpegPixelArea(buffer);
@ -1199,8 +1189,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.Components[i] = component;
}
int h0 = this.Components[0].HorizontalFactor;
int v0 = this.Components[0].VerticalFactor;
int h0 = this.Components[0].HorizontalSamplingFactor;
int v0 = this.Components[0].VerticalSamplingFactor;
this.MCUCountX = (this.ImageWidth + (8 * h0) - 1) / (8 * h0);
this.MCUCountY = (this.ImageHeight + (8 * v0) - 1) / (8 * v0);
@ -1209,6 +1199,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{
this.Components[i].InitializeBlocks(this);
}
this.SubsampleRatio = Subsampling.GetSubsampleRatio(this.Components);
}
}
}

16
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFrameComponent.cs

@ -20,8 +20,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
this.Frame = frame;
this.Id = id;
this.HorizontalFactor = horizontalFactor;
this.VerticalFactor = verticalFactor;
this.HorizontalSamplingFactor = horizontalFactor;
this.VerticalSamplingFactor = verticalFactor;
this.QuantizationIdentifier = quantizationIdentifier;
}
@ -38,12 +38,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// <summary>
/// Gets the horizontal sampling factor.
/// </summary>
public int HorizontalFactor { get; }
public int HorizontalSamplingFactor { get; }
/// <summary>
/// Gets the vertical sampling factor.
/// </summary>
public int VerticalFactor { get; }
public int VerticalSamplingFactor { get; }
/// <summary>
/// Gets the identifier
@ -91,13 +91,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
public void Init()
{
this.WidthInBlocks = (int)MathF.Ceiling(
MathF.Ceiling(this.Frame.SamplesPerLine / 8F) * this.HorizontalFactor / this.Frame.MaxHorizontalFactor);
MathF.Ceiling(this.Frame.SamplesPerLine / 8F) * this.HorizontalSamplingFactor / this.Frame.MaxHorizontalFactor);
this.HeightInBlocks = (int)MathF.Ceiling(
MathF.Ceiling(this.Frame.Scanlines / 8F) * this.VerticalFactor / this.Frame.MaxVerticalFactor);
MathF.Ceiling(this.Frame.Scanlines / 8F) * this.VerticalSamplingFactor / this.Frame.MaxVerticalFactor);
this.BlocksPerLineForMcu = this.Frame.McusPerLine * this.HorizontalFactor;
this.BlocksPerColumnForMcu = this.Frame.McusPerColumn * this.VerticalFactor;
this.BlocksPerLineForMcu = this.Frame.McusPerLine * this.HorizontalSamplingFactor;
this.BlocksPerColumnForMcu = this.Frame.McusPerColumn * this.VerticalSamplingFactor;
int blocksBufferSize = 64 * this.BlocksPerColumnForMcu * (this.BlocksPerLineForMcu + 1);

40
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsScanDecoder.cs

@ -224,8 +224,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
PdfJsFrameComponent component = components[i];
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
int h = component.HorizontalFactor;
int v = component.VerticalFactor;
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;
for (int j = 0; j < v; j++)
{
@ -280,8 +280,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
PdfJsFrameComponent component = components[i];
ref PdfJsHuffmanTable dcHuffmanTable = ref dcHuffmanTables[component.DCHuffmanTableId];
int h = component.HorizontalFactor;
int v = component.VerticalFactor;
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;
for (int j = 0; j < v; j++)
{
@ -332,8 +332,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
for (int i = 0; i < componentsLength; i++)
{
PdfJsFrameComponent component = components[i];
int h = component.HorizontalFactor;
int v = component.VerticalFactor;
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;
for (int j = 0; j < v; j++)
{
for (int k = 0; k < h; k++)
@ -387,8 +387,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
PdfJsFrameComponent component = components[i];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
int h = component.HorizontalFactor;
int v = component.VerticalFactor;
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;
for (int j = 0; j < v; j++)
{
@ -443,8 +443,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
PdfJsFrameComponent component = components[i];
ref PdfJsHuffmanTable acHuffmanTable = ref acHuffmanTables[component.ACHuffmanTableId];
int h = component.HorizontalFactor;
int v = component.VerticalFactor;
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;
for (int j = 0; j < v; j++)
{
@ -479,8 +479,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalFactor) + row;
int blockCol = (mcuCol * component.HorizontalFactor) + col;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeBaseline(component, offset, ref dcHuffmanTable, ref acHuffmanTable, stream);
}
@ -499,8 +499,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalFactor) + row;
int blockCol = (mcuCol * component.HorizontalFactor) + col;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeDCFirst(component, offset, ref dcHuffmanTable, stream);
}
@ -519,8 +519,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalFactor) + row;
int blockCol = (mcuCol * component.HorizontalFactor) + col;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeDCSuccessive(component, offset, stream);
}
@ -539,8 +539,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalFactor) + row;
int blockCol = (mcuCol * component.HorizontalFactor) + col;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeACFirst(component, offset, ref acHuffmanTable, stream);
}
@ -559,8 +559,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalFactor) + row;
int blockCol = (mcuCol * component.HorizontalFactor) + col;
int blockRow = (mcuRow * component.VerticalSamplingFactor) + row;
int blockCol = (mcuCol * component.HorizontalSamplingFactor) + col;
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeACSuccessive(component, offset, ref acHuffmanTable, stream);
}

4
src/ImageSharp/Formats/Jpeg/PdfJsPort/JpegDecoderCore.cs

@ -296,8 +296,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
var component = new PdfJsComponent
{
Scale = new System.Numerics.Vector2(
frameComponent.HorizontalFactor / (float)this.Frame.MaxHorizontalFactor,
frameComponent.VerticalFactor / (float)this.Frame.MaxVerticalFactor),
frameComponent.HorizontalSamplingFactor / (float)this.Frame.MaxHorizontalFactor,
frameComponent.VerticalSamplingFactor / (float)this.Frame.MaxVerticalFactor),
BlocksPerLine = frameComponent.WidthInBlocks,
BlocksPerColumn = frameComponent.HeightInBlocks
};

6
tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs

@ -27,9 +27,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
public int Index { get; }
public int HeightInBlocks { get; }
public int WidthInBlocks { get; }
public int HorizontalSamplingFactor => throw new NotSupportedException();
public int VerticalSamplingFactor => throw new NotSupportedException();
public Buffer2D<Block8x8> Blocks { get; private set; }
public short MinVal { get; private set; } = short.MaxValue;

Loading…
Cancel
Save