Browse Source

Fixed styling issues

pull/1694/head
Dmitry Pentin 5 years ago
parent
commit
d325d06b5f
  1. 143
      src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
  2. 8
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
  3. 27
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs
  4. 29
      src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
  5. 21
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

143
src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs

@ -18,43 +18,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
private readonly BufferedReadStream stream; private readonly BufferedReadStream stream;
// huffman tables
public HuffmanTable[] dcHuffmanTables;
public HuffmanTable[] acHuffmanTables;
// Frame related // Frame related
private JpegFrame frame; private JpegFrame frame;
private JpegComponent[] components; private JpegComponent[] components;
// The restart interval. // The restart interval.
private int restartInterval; private int restartInterval;
// How many mcu's are left to do. // How many mcu's are left to do.
private int todo; private int todo;
public int ResetInterval
{
set
{
restartInterval = value;
todo = value;
}
}
// The number of interleaved components.
public int componentsLength;
// The spectral selection start.
public int spectralStart;
// The spectral selection end.
public int spectralEnd;
// The successive approximation high bit end.
public int successiveHigh;
// The successive approximation low bit end.
public int successiveLow;
// The End-Of-Block countdown for ending the sequence prematurely when the remaining coefficients are zero. // The End-Of-Block countdown for ending the sequence prematurely when the remaining coefficients are zero.
private int eobrun; private int eobrun;
@ -63,7 +36,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private HuffmanScanBuffer scanBuffer; private HuffmanScanBuffer scanBuffer;
private SpectralConverter spectralConverter; private readonly SpectralConverter spectralConverter;
private CancellationToken cancellationToken; private CancellationToken cancellationToken;
@ -71,15 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// Initializes a new instance of the <see cref="HuffmanScanDecoder"/> class. /// Initializes a new instance of the <see cref="HuffmanScanDecoder"/> class.
/// </summary> /// </summary>
/// <param name="stream">The input stream.</param> /// <param name="stream">The input stream.</param>
/// <param name="frame">The image frame.</param> /// <param name="converter">Spectral to pixel converter.</param>
/// <param name="dcHuffmanTables">The DC Huffman tables.</param>
/// <param name="acHuffmanTables">The AC Huffman tables.</param>
/// <param name="componentsLength">The length of the components. Different to the array length.</param>
/// <param name="restartInterval">The reset interval.</param>
/// <param name="spectralStart">The spectral selection start.</param>
/// <param name="spectralEnd">The spectral selection end.</param>
/// <param name="successiveHigh">The successive approximation bit high end.</param>
/// <param name="successiveLow">The successive approximation bit low end.</param>
/// <param name="cancellationToken">The token to monitor cancellation.</param> /// <param name="cancellationToken">The token to monitor cancellation.</param>
public HuffmanScanDecoder( public HuffmanScanDecoder(
BufferedReadStream stream, BufferedReadStream stream,
@ -92,6 +57,36 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.cancellationToken = cancellationToken; this.cancellationToken = cancellationToken;
} }
// huffman tables
public HuffmanTable[] DcHuffmanTables { get; set; }
public HuffmanTable[] AcHuffmanTables { get; set; }
// Reset interval
public int ResetInterval
{
set
{
this.restartInterval = value;
this.todo = value;
}
}
// The number of interleaved components.
public int ComponentsLength { get; set; }
// The spectral selection start.
public int SpectralStart { get; set; }
// The spectral selection end.
public int SpectralEnd { get; set; }
// The successive approximation high bit end.
public int SuccessiveHigh { get; set; }
// The successive approximation low bit end.
public int SuccessiveLow { get; set; }
/// <summary> /// <summary>
/// Decodes the entropy coded data. /// Decodes the entropy coded data.
/// </summary> /// </summary>
@ -126,7 +121,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private void ParseBaselineData() private void ParseBaselineData()
{ {
if (this.componentsLength == 1) if (this.ComponentsLength == 1)
{ {
this.frame.AllocateComponents(fullScan: true); this.frame.AllocateComponents(fullScan: true);
this.ParseBaselineDataNonInterleaved(); this.ParseBaselineDataNonInterleaved();
@ -148,13 +143,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
ref HuffmanScanBuffer buffer = ref this.scanBuffer; ref HuffmanScanBuffer buffer = ref this.scanBuffer;
// Pre-derive the huffman table to avoid in-loop checks. // Pre-derive the huffman table to avoid in-loop checks.
for (int i = 0; i < this.componentsLength; i++) for (int i = 0; i < this.ComponentsLength; i++)
{ {
int order = this.frame.ComponentOrder[i]; int order = this.frame.ComponentOrder[i];
JpegComponent component = this.components[order]; JpegComponent component = this.components[order];
ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; ref HuffmanTable dcHuffmanTable = ref this.DcHuffmanTables[component.DCHuffmanTableId];
ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId]; ref HuffmanTable acHuffmanTable = ref this.AcHuffmanTables[component.ACHuffmanTableId];
dcHuffmanTable.Configure(); dcHuffmanTable.Configure();
acHuffmanTable.Configure(); acHuffmanTable.Configure();
} }
@ -169,13 +164,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// Scan an interleaved mcu... process components in order // Scan an interleaved mcu... process components in order
int mcuRow = mcu / mcusPerLine; int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine; int mcuCol = mcu % mcusPerLine;
for (int k = 0; k < this.componentsLength; k++) for (int k = 0; k < this.ComponentsLength; k++)
{ {
int order = this.frame.ComponentOrder[k]; int order = this.frame.ComponentOrder[k];
JpegComponent component = this.components[order]; JpegComponent component = this.components[order];
ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; ref HuffmanTable dcHuffmanTable = ref this.DcHuffmanTables[component.DCHuffmanTableId];
ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId]; ref HuffmanTable acHuffmanTable = ref this.AcHuffmanTables[component.ACHuffmanTableId];
int h = component.HorizontalSamplingFactor; int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor; int v = component.VerticalSamplingFactor;
@ -225,8 +220,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
int w = component.WidthInBlocks; int w = component.WidthInBlocks;
int h = component.HeightInBlocks; int h = component.HeightInBlocks;
ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; ref HuffmanTable dcHuffmanTable = ref this.DcHuffmanTables[component.DCHuffmanTableId];
ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId]; ref HuffmanTable acHuffmanTable = ref this.AcHuffmanTables[component.ACHuffmanTableId];
dcHuffmanTable.Configure(); dcHuffmanTable.Configure();
acHuffmanTable.Configure(); acHuffmanTable.Configure();
@ -260,9 +255,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// Logic has been adapted from libjpeg. // Logic has been adapted from libjpeg.
// See Table B.3 – Scan header parameter size and values. itu-t81.pdf // See Table B.3 – Scan header parameter size and values. itu-t81.pdf
bool invalid = false; bool invalid = false;
if (this.spectralStart == 0) if (this.SpectralStart == 0)
{ {
if (this.spectralEnd != 0) if (this.SpectralEnd != 0)
{ {
invalid = true; invalid = true;
} }
@ -270,22 +265,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
else else
{ {
// Need not check Ss/Se < 0 since they came from unsigned bytes. // Need not check Ss/Se < 0 since they came from unsigned bytes.
if (this.spectralEnd < this.spectralStart || this.spectralEnd > 63) if (this.SpectralEnd < this.SpectralStart || this.SpectralEnd > 63)
{ {
invalid = true; invalid = true;
} }
// AC scans may have only one component. // AC scans may have only one component.
if (this.componentsLength != 1) if (this.ComponentsLength != 1)
{ {
invalid = true; invalid = true;
} }
} }
if (this.successiveHigh != 0) if (this.SuccessiveHigh != 0)
{ {
// Successive approximation refinement scan: must have Al = Ah-1. // Successive approximation refinement scan: must have Al = Ah-1.
if (this.successiveHigh - 1 != this.successiveLow) if (this.SuccessiveHigh - 1 != this.SuccessiveLow)
{ {
invalid = true; invalid = true;
} }
@ -293,14 +288,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// TODO: How does this affect 12bit jpegs. // TODO: How does this affect 12bit jpegs.
// According to libjpeg the range covers 8bit only? // According to libjpeg the range covers 8bit only?
if (this.successiveLow > 13) if (this.SuccessiveLow > 13)
{ {
invalid = true; invalid = true;
} }
if (invalid) if (invalid)
{ {
JpegThrowHelper.ThrowBadProgressiveScan(this.spectralStart, this.spectralEnd, this.successiveHigh, this.successiveLow); JpegThrowHelper.ThrowBadProgressiveScan(this.SpectralStart, this.SpectralEnd, this.SuccessiveHigh, this.SuccessiveLow);
} }
} }
@ -309,7 +304,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.CheckProgressiveData(); this.CheckProgressiveData();
this.frame.AllocateComponents(fullScan: true); this.frame.AllocateComponents(fullScan: true);
if (this.componentsLength == 1) if (this.ComponentsLength == 1)
{ {
this.ParseProgressiveDataNonInterleaved(); this.ParseProgressiveDataNonInterleaved();
} }
@ -328,11 +323,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
ref HuffmanScanBuffer buffer = ref this.scanBuffer; ref HuffmanScanBuffer buffer = ref this.scanBuffer;
// Pre-derive the huffman table to avoid in-loop checks. // Pre-derive the huffman table to avoid in-loop checks.
for (int k = 0; k < this.componentsLength; k++) for (int k = 0; k < this.ComponentsLength; k++)
{ {
int order = this.frame.ComponentOrder[k]; int order = this.frame.ComponentOrder[k];
JpegComponent component = this.components[order]; JpegComponent component = this.components[order];
ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; ref HuffmanTable dcHuffmanTable = ref this.DcHuffmanTables[component.DCHuffmanTableId];
dcHuffmanTable.Configure(); dcHuffmanTable.Configure();
} }
@ -343,11 +338,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// Scan an interleaved mcu... process components in order // Scan an interleaved mcu... process components in order
int mcuRow = mcu / mcusPerLine; int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine; int mcuCol = mcu % mcusPerLine;
for (int k = 0; k < this.componentsLength; k++) for (int k = 0; k < this.ComponentsLength; k++)
{ {
int order = this.frame.ComponentOrder[k]; int order = this.frame.ComponentOrder[k];
JpegComponent component = this.components[order]; JpegComponent component = this.components[order];
ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; ref HuffmanTable dcHuffmanTable = ref this.DcHuffmanTables[component.DCHuffmanTableId];
int h = component.HorizontalSamplingFactor; int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor; int v = component.VerticalSamplingFactor;
@ -393,9 +388,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
int w = component.WidthInBlocks; int w = component.WidthInBlocks;
int h = component.HeightInBlocks; int h = component.HeightInBlocks;
if (this.spectralStart == 0) if (this.SpectralStart == 0)
{ {
ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; ref HuffmanTable dcHuffmanTable = ref this.DcHuffmanTables[component.DCHuffmanTableId];
dcHuffmanTable.Configure(); dcHuffmanTable.Configure();
for (int j = 0; j < h; j++) for (int j = 0; j < h; j++)
@ -423,7 +418,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
} }
else else
{ {
ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId]; ref HuffmanTable acHuffmanTable = ref this.AcHuffmanTables[component.ACHuffmanTableId];
acHuffmanTable.Configure(); acHuffmanTable.Configure();
for (int j = 0; j < h; j++) for (int j = 0; j < h; j++)
@ -502,7 +497,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
ref short blockDataRef = ref Unsafe.As<Block8x8, short>(ref block); ref short blockDataRef = ref Unsafe.As<Block8x8, short>(ref block);
ref HuffmanScanBuffer buffer = ref this.scanBuffer; ref HuffmanScanBuffer buffer = ref this.scanBuffer;
if (this.successiveHigh == 0) if (this.SuccessiveHigh == 0)
{ {
// First scan for DC coefficient, must be first // First scan for DC coefficient, must be first
int s = buffer.DecodeHuffman(ref dcTable); int s = buffer.DecodeHuffman(ref dcTable);
@ -513,20 +508,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
s += component.DcPredictor; s += component.DcPredictor;
component.DcPredictor = s; component.DcPredictor = s;
blockDataRef = (short)(s << this.successiveLow); blockDataRef = (short)(s << this.SuccessiveLow);
} }
else else
{ {
// Refinement scan for DC coefficient // Refinement scan for DC coefficient
buffer.CheckBits(); buffer.CheckBits();
blockDataRef |= (short)(buffer.GetBits(1) << this.successiveLow); blockDataRef |= (short)(buffer.GetBits(1) << this.SuccessiveLow);
} }
} }
private void DecodeBlockProgressiveAC(ref Block8x8 block, ref HuffmanTable acTable) private void DecodeBlockProgressiveAC(ref Block8x8 block, ref HuffmanTable acTable)
{ {
ref short blockDataRef = ref Unsafe.As<Block8x8, short>(ref block); ref short blockDataRef = ref Unsafe.As<Block8x8, short>(ref block);
if (this.successiveHigh == 0) if (this.SuccessiveHigh == 0)
{ {
// MCU decoding for AC initial scan (either spectral selection, // MCU decoding for AC initial scan (either spectral selection,
// or first pass of successive approximation). // or first pass of successive approximation).
@ -538,9 +533,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
ref HuffmanScanBuffer buffer = ref this.scanBuffer; ref HuffmanScanBuffer buffer = ref this.scanBuffer;
ref ZigZag zigzag = ref this.dctZigZag; ref ZigZag zigzag = ref this.dctZigZag;
int start = this.spectralStart; int start = this.SpectralStart;
int end = this.spectralEnd; int end = this.SpectralEnd;
int low = this.successiveLow; int low = this.SuccessiveLow;
for (int i = start; i <= end; ++i) for (int i = start; i <= end; ++i)
{ {
@ -584,11 +579,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// Refinement scan for these AC coefficients // Refinement scan for these AC coefficients
ref HuffmanScanBuffer buffer = ref this.scanBuffer; ref HuffmanScanBuffer buffer = ref this.scanBuffer;
ref ZigZag zigzag = ref this.dctZigZag; ref ZigZag zigzag = ref this.dctZigZag;
int start = this.spectralStart; int start = this.SpectralStart;
int end = this.spectralEnd; int end = this.SpectralEnd;
int p1 = 1 << this.successiveLow; int p1 = 1 << this.SuccessiveLow;
int m1 = (-1) << this.successiveLow; int m1 = (-1) << this.SuccessiveLow;
int k = start; int k = start;

8
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs

@ -2,9 +2,6 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
@ -63,10 +60,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
public int BlockRowsPerStep { get; } public int BlockRowsPerStep { get; }
/// <inheritdoc /> /// <inheritdoc />
public void Dispose() public void Dispose() => this.ColorBuffer.Dispose();
{
this.ColorBuffer.Dispose();
}
/// <summary> /// <summary>
/// Invoke <see cref="JpegBlockPostProcessor"/> for <see cref="BlockRowsPerStep"/> block rows, copy the result into <see cref="ColorBuffer"/>. /// Invoke <see cref="JpegBlockPostProcessor"/> for <see cref="BlockRowsPerStep"/> block rows, copy the result into <see cref="ColorBuffer"/>.

27
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs

@ -5,7 +5,6 @@ using System;
using System.Buffers; using System.Buffers;
using System.Numerics; using System.Numerics;
using System.Threading; using System.Threading;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using JpegColorConverter = SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters.JpegColorConverter; using JpegColorConverter = SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters.JpegColorConverter;
@ -19,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// (3) Color conversion form one of the <see cref="JpegColorSpace"/>-s into a <see cref="Vector4"/> buffer of RGBA values <br/> /// (3) Color conversion form one of the <see cref="JpegColorSpace"/>-s into a <see cref="Vector4"/> buffer of RGBA values <br/>
/// (4) Packing <see cref="Image{TPixel}"/> pixels from the <see cref="Vector4"/> buffer. <br/> /// (4) Packing <see cref="Image{TPixel}"/> pixels from the <see cref="Vector4"/> buffer. <br/>
/// These operations are executed in <see cref="NumberOfPostProcessorSteps"/> steps. /// These operations are executed in <see cref="NumberOfPostProcessorSteps"/> steps.
/// <see cref="PixelRowsPerStep"/> image rows are converted in one step, /// <see cref="pixelRowsPerStep"/> image rows are converted in one step,
/// which means that size of the allocated memory is limited (does not depend on <see cref="ImageFrame.Height"/>). /// which means that size of the allocated memory is limited (does not depend on <see cref="ImageFrame.Height"/>).
/// </summary> /// </summary>
internal class JpegImagePostProcessor : IDisposable internal class JpegImagePostProcessor : IDisposable
@ -29,12 +28,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// <summary> /// <summary>
/// The number of block rows to be processed in one Step. /// The number of block rows to be processed in one Step.
/// </summary> /// </summary>
public int BlockRowsPerStep; private readonly int blockRowsPerStep;
/// <summary> /// <summary>
/// The number of image pixel rows to be processed in one step. /// The number of image pixel rows to be processed in one step.
/// </summary> /// </summary>
public int PixelRowsPerStep; private readonly int pixelRowsPerStep;
/// <summary> /// <summary>
/// Temporal buffer to store a row of colors. /// Temporal buffer to store a row of colors.
@ -57,12 +56,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.RawJpeg = rawJpeg; this.RawJpeg = rawJpeg;
IJpegComponent c0 = rawJpeg.Components[0]; IJpegComponent c0 = rawJpeg.Components[0];
this.BlockRowsPerStep = c0.SamplingFactors.Height; this.blockRowsPerStep = c0.SamplingFactors.Height;
this.PixelRowsPerStep = this.BlockRowsPerStep * 8; this.pixelRowsPerStep = this.blockRowsPerStep * 8;
this.NumberOfPostProcessorSteps = c0.SizeInBlocks.Height / this.BlockRowsPerStep; this.NumberOfPostProcessorSteps = c0.SizeInBlocks.Height / this.blockRowsPerStep;
var postProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, this.PixelRowsPerStep); var postProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, this.pixelRowsPerStep);
MemoryAllocator memoryAllocator = configuration.MemoryAllocator; MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
this.ComponentProcessors = new JpegComponentPostProcessor[rawJpeg.Components.Length]; this.ComponentProcessors = new JpegComponentPostProcessor[rawJpeg.Components.Length];
for (int i = 0; i < rawJpeg.Components.Length; i++) for (int i = 0; i < rawJpeg.Components.Length; i++)
@ -85,12 +84,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
public IRawJpegData RawJpeg { get; } public IRawJpegData RawJpeg { get; }
/// <summary> /// <summary>
/// Gets the total number of post processor steps deduced from the height of the image and <see cref="PixelRowsPerStep"/>. /// Gets the total number of post processor steps deduced from the height of the image and <see cref="pixelRowsPerStep"/>.
/// </summary> /// </summary>
public int NumberOfPostProcessorSteps { get; } public int NumberOfPostProcessorSteps { get; }
/// <summary> /// <summary>
/// Gets the value of the counter that grows by each step by <see cref="PixelRowsPerStep"/>. /// Gets the value of the counter that grows by each step by <see cref="pixelRowsPerStep"/>.
/// </summary> /// </summary>
public int PixelRowCounter { get; private set; } public int PixelRowCounter { get; private set; }
@ -129,15 +128,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
} }
/// <summary> /// <summary>
/// Execute one step processing <see cref="PixelRowsPerStep"/> pixel rows into 'destination'. /// Execute one step processing <see cref="pixelRowsPerStep"/> pixel rows into 'destination'.
/// Convert and copy <see cref="PixelRowsPerStep"/> row of colors into 'destination' starting at row <see cref="PixelRowCounter"/>. /// Convert and copy <see cref="pixelRowsPerStep"/> row of colors into 'destination' starting at row <see cref="PixelRowCounter"/>.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam> /// <typeparam name="TPixel">The pixel type</typeparam>
/// <param name="destination">The destination image</param> /// <param name="destination">The destination image</param>
public void DoPostProcessorStep<TPixel>(ImageFrame<TPixel> destination) public void DoPostProcessorStep<TPixel>(ImageFrame<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int maxY = Math.Min(destination.Height, this.PixelRowCounter + PixelRowsPerStep); int maxY = Math.Min(destination.Height, this.PixelRowCounter + this.pixelRowsPerStep);
var buffers = new Buffer2D<float>[this.ComponentProcessors.Length]; var buffers = new Buffer2D<float>[this.ComponentProcessors.Length];
for (int i = 0; i < this.ComponentProcessors.Length; i++) for (int i = 0; i < this.ComponentProcessors.Length; i++)
@ -159,7 +158,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow);
} }
this.PixelRowCounter += PixelRowsPerStep; this.PixelRowCounter += this.pixelRowsPerStep;
} }
} }
} }

29
src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs

@ -3,9 +3,7 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Collections.Generic;
using System.Numerics; using System.Numerics;
using System.Text;
using System.Threading; using System.Threading;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
@ -16,11 +14,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
internal sealed class SpectralConverter<TPixel> : SpectralConverter internal sealed class SpectralConverter<TPixel> : SpectralConverter
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
private Configuration configuration; private readonly Configuration configuration;
private CancellationToken cancellationToken; private CancellationToken cancellationToken;
private JpegComponentPostProcessor[] componentProcessors; private JpegComponentPostProcessor[] componentProcessors;
private JpegColorConverter colorConverter; private JpegColorConverter colorConverter;
@ -29,11 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private Buffer2D<TPixel> pixelBuffer; private Buffer2D<TPixel> pixelBuffer;
public int BlockRowsPerStep; private int blockRowsPerStep;
private int PixelRowsPerStep; private int pixelRowsPerStep;
private int PixelRowCounter; private int pixelRowCounter;
public SpectralConverter(Configuration configuration, CancellationToken ct) public SpectralConverter(Configuration configuration, CancellationToken ct)
{ {
@ -41,7 +38,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.cancellationToken = ct; this.cancellationToken = ct;
} }
private bool Converted => this.PixelRowCounter >= this.pixelBuffer.Height; private bool Converted => this.pixelRowCounter >= this.pixelBuffer.Height;
public Buffer2D<TPixel> PixelBuffer public Buffer2D<TPixel> PixelBuffer
{ {
@ -49,7 +46,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
if (!this.Converted) if (!this.Converted)
{ {
int steps = (int)Math.Ceiling(this.pixelBuffer.Height / (float)this.PixelRowsPerStep); int steps = (int)Math.Ceiling(this.pixelBuffer.Height / (float)this.pixelRowsPerStep);
for (int step = 0; step < steps; step++) for (int step = 0; step < steps; step++)
{ {
@ -70,14 +67,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
IJpegComponent c0 = frame.Components[0]; IJpegComponent c0 = frame.Components[0];
const int blockPixelHeight = 8; const int blockPixelHeight = 8;
this.BlockRowsPerStep = c0.SamplingFactors.Height; this.blockRowsPerStep = c0.SamplingFactors.Height;
this.PixelRowsPerStep = this.BlockRowsPerStep * blockPixelHeight; this.pixelRowsPerStep = this.blockRowsPerStep * blockPixelHeight;
// pixel buffer for resulting image // pixel buffer for resulting image
this.pixelBuffer = allocator.Allocate2D<TPixel>(frame.PixelWidth, frame.PixelHeight, AllocationOptions.Clean); this.pixelBuffer = allocator.Allocate2D<TPixel>(frame.PixelWidth, frame.PixelHeight, AllocationOptions.Clean);
// component processors from spectral to Rgba32 // component processors from spectral to Rgba32
var postProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, this.PixelRowsPerStep); var postProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, this.pixelRowsPerStep);
this.componentProcessors = new JpegComponentPostProcessor[frame.Components.Length]; this.componentProcessors = new JpegComponentPostProcessor[frame.Components.Length];
for (int i = 0; i < this.componentProcessors.Length; i++) for (int i = 0; i < this.componentProcessors.Length; i++)
{ {
@ -118,7 +115,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private void ConvertNextStride(int spectralStep) private void ConvertNextStride(int spectralStep)
{ {
int maxY = Math.Min(this.pixelBuffer.Height, this.PixelRowCounter + this.PixelRowsPerStep); int maxY = Math.Min(this.pixelBuffer.Height, this.pixelRowCounter + this.pixelRowsPerStep);
var buffers = new Buffer2D<float>[this.componentProcessors.Length]; var buffers = new Buffer2D<float>[this.componentProcessors.Length];
for (int i = 0; i < this.componentProcessors.Length; i++) for (int i = 0; i < this.componentProcessors.Length; i++)
@ -127,9 +124,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
buffers[i] = this.componentProcessors[i].ColorBuffer; buffers[i] = this.componentProcessors[i].ColorBuffer;
} }
for (int yy = this.PixelRowCounter; yy < maxY; yy++) for (int yy = this.pixelRowCounter; yy < maxY; yy++)
{ {
int y = yy - this.PixelRowCounter; int y = yy - this.pixelRowCounter;
var values = new JpegColorConverter.ComponentValues(buffers, y); var values = new JpegColorConverter.ComponentValues(buffers, y);
this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.GetSpan()); this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.GetSpan());
@ -140,7 +137,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow);
} }
this.PixelRowCounter += this.PixelRowsPerStep; this.pixelRowCounter += this.pixelRowsPerStep;
} }
} }
} }

21
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -97,6 +97,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </summary> /// </summary>
private AdobeMarker adobe; private AdobeMarker adobe;
/// <summary>
/// Scan decoder.
/// </summary>
private HuffmanScanDecoder scanDecoder;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="JpegDecoderCore" /> class. /// Initializes a new instance of the <see cref="JpegDecoderCore" /> class.
/// </summary> /// </summary>
@ -172,8 +177,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <inheritdoc/> /// <inheritdoc/>
public Block8x8F[] QuantizationTables { get; private set; } public Block8x8F[] QuantizationTables { get; private set; }
private HuffmanScanDecoder scanDecoder;
/// <summary> /// <summary>
/// Finds the next file marker within the byte stream. /// Finds the next file marker within the byte stream.
/// </summary> /// </summary>
@ -1064,20 +1067,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
// Main reason it's not fixed here is to make this commit less intrusive // Main reason it's not fixed here is to make this commit less intrusive
// Huffman tables can be calculated directly in the scan decoder class // Huffman tables can be calculated directly in the scan decoder class
this.scanDecoder.dcHuffmanTables = this.dcHuffmanTables; this.scanDecoder.DcHuffmanTables = this.dcHuffmanTables;
this.scanDecoder.acHuffmanTables = this.acHuffmanTables; this.scanDecoder.AcHuffmanTables = this.acHuffmanTables;
// This can be injectd in DRI marker callback // This can be injectd in DRI marker callback
this.scanDecoder.ResetInterval = this.resetInterval; this.scanDecoder.ResetInterval = this.resetInterval;
// This can be passed as ParseEntropyCodedData() parameter as it is used only there // This can be passed as ParseEntropyCodedData() parameter as it is used only there
this.scanDecoder.componentsLength = selectorsCount; this.scanDecoder.ComponentsLength = selectorsCount;
// This is okay to inject here, might be good to wrap it in a separate struct but not really necessary // This is okay to inject here, might be good to wrap it in a separate struct but not really necessary
this.scanDecoder.spectralStart = spectralStart; this.scanDecoder.SpectralStart = spectralStart;
this.scanDecoder.spectralEnd = spectralEnd; this.scanDecoder.SpectralEnd = spectralEnd;
this.scanDecoder.successiveHigh = successiveApproximation >> 4; this.scanDecoder.SuccessiveHigh = successiveApproximation >> 4;
this.scanDecoder.successiveLow = successiveApproximation & 15; this.scanDecoder.SuccessiveLow = successiveApproximation & 15;
this.scanDecoder.ParseEntropyCodedData(); this.scanDecoder.ParseEntropyCodedData();
} }

Loading…
Cancel
Save