mirror of https://github.com/SixLabors/ImageSharp
2 changed files with 0 additions and 191 deletions
@ -1,164 +0,0 @@ |
|||||
// Copyright (c) Six Labors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
|
|
||||
using System; |
|
||||
using System.Buffers; |
|
||||
using System.Numerics; |
|
||||
using System.Threading; |
|
||||
using SixLabors.ImageSharp.Memory; |
|
||||
using SixLabors.ImageSharp.PixelFormats; |
|
||||
using JpegColorConverter = SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters.JpegColorConverter; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Encapsulates the execution od post-processing algorithms to be applied on a <see cref="IRawJpegData"/> to produce a valid <see cref="Image{TPixel}"/>: <br/>
|
|
||||
/// (1) Dequantization <br/>
|
|
||||
/// (2) IDCT <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/>
|
|
||||
/// These operations are executed in <see cref="NumberOfPostProcessorSteps"/> steps.
|
|
||||
/// <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"/>).
|
|
||||
/// </summary>
|
|
||||
internal class JpegImagePostProcessor : IDisposable |
|
||||
{ |
|
||||
private readonly Configuration configuration; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The number of block rows to be processed in one Step.
|
|
||||
/// </summary>
|
|
||||
private readonly int blockRowsPerStep; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The number of image pixel rows to be processed in one step.
|
|
||||
/// </summary>
|
|
||||
private readonly int pixelRowsPerStep; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Temporal buffer to store a row of colors.
|
|
||||
/// </summary>
|
|
||||
private readonly IMemoryOwner<Vector4> rgbaBuffer; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The <see cref="JpegColorConverter"/> corresponding to the current <see cref="JpegColorSpace"/> determined by <see cref="IRawJpegData.ColorSpace"/>.
|
|
||||
/// </summary>
|
|
||||
private readonly JpegColorConverter colorConverter; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="JpegImagePostProcessor"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="configuration">The <see cref="Configuration"/> to configure internal operations.</param>
|
|
||||
/// <param name="rawJpeg">The <see cref="IRawJpegData"/> representing the uncompressed spectral Jpeg data</param>
|
|
||||
public JpegImagePostProcessor(Configuration configuration, IRawJpegData rawJpeg) |
|
||||
{ |
|
||||
this.configuration = configuration; |
|
||||
this.RawJpeg = rawJpeg; |
|
||||
IJpegComponent c0 = rawJpeg.Components[0]; |
|
||||
|
|
||||
this.blockRowsPerStep = c0.SamplingFactors.Height; |
|
||||
this.pixelRowsPerStep = this.blockRowsPerStep * 8; |
|
||||
|
|
||||
this.NumberOfPostProcessorSteps = c0.SizeInBlocks.Height / this.blockRowsPerStep; |
|
||||
|
|
||||
var postProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, this.pixelRowsPerStep); |
|
||||
MemoryAllocator memoryAllocator = configuration.MemoryAllocator; |
|
||||
this.ComponentProcessors = new JpegComponentPostProcessor[rawJpeg.Components.Length]; |
|
||||
for (int i = 0; i < rawJpeg.Components.Length; i++) |
|
||||
{ |
|
||||
this.ComponentProcessors[i] = new JpegComponentPostProcessor(memoryAllocator, this.RawJpeg, postProcessorBufferSize, rawJpeg.Components[i]); |
|
||||
} |
|
||||
|
|
||||
this.rgbaBuffer = memoryAllocator.Allocate<Vector4>(rawJpeg.ImageSizeInPixels.Width); |
|
||||
this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace, rawJpeg.Precision); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the <see cref="JpegComponentPostProcessor"/> instances.
|
|
||||
/// </summary>
|
|
||||
public JpegComponentPostProcessor[] ComponentProcessors { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the <see cref="IRawJpegData"/> to be processed.
|
|
||||
/// </summary>
|
|
||||
public IRawJpegData RawJpeg { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the total number of post processor steps deduced from the height of the image and <see cref="pixelRowsPerStep"/>.
|
|
||||
/// </summary>
|
|
||||
public int NumberOfPostProcessorSteps { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the value of the counter that grows by each step by <see cref="pixelRowsPerStep"/>.
|
|
||||
/// </summary>
|
|
||||
public int PixelRowCounter { get; private set; } |
|
||||
|
|
||||
/// <inheritdoc />
|
|
||||
public void Dispose() |
|
||||
{ |
|
||||
foreach (JpegComponentPostProcessor cpp in this.ComponentProcessors) |
|
||||
{ |
|
||||
cpp.Dispose(); |
|
||||
} |
|
||||
|
|
||||
this.rgbaBuffer.Dispose(); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Process all pixels into 'destination'. The image dimensions should match <see cref="RawJpeg"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The pixel type</typeparam>
|
|
||||
/// <param name="destination">The destination image</param>
|
|
||||
/// <param name="cancellationToken">The token to request cancellation.</param>
|
|
||||
public void PostProcess<TPixel>(ImageFrame<TPixel> destination, CancellationToken cancellationToken) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
{ |
|
||||
this.PixelRowCounter = 0; |
|
||||
|
|
||||
if (this.RawJpeg.ImageSizeInPixels != destination.Size()) |
|
||||
{ |
|
||||
throw new ArgumentException("Input image is not of the size of the processed one!"); |
|
||||
} |
|
||||
|
|
||||
while (this.PixelRowCounter < this.RawJpeg.ImageSizeInPixels.Height) |
|
||||
{ |
|
||||
cancellationToken.ThrowIfCancellationRequested(); |
|
||||
this.DoPostProcessorStep(destination); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// 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"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The pixel type</typeparam>
|
|
||||
/// <param name="destination">The destination image</param>
|
|
||||
public void DoPostProcessorStep<TPixel>(ImageFrame<TPixel> destination) |
|
||||
where TPixel : unmanaged, IPixel<TPixel> |
|
||||
{ |
|
||||
int maxY = Math.Min(destination.Height, this.PixelRowCounter + this.pixelRowsPerStep); |
|
||||
|
|
||||
var buffers = new Buffer2D<float>[this.ComponentProcessors.Length]; |
|
||||
for (int i = 0; i < this.ComponentProcessors.Length; i++) |
|
||||
{ |
|
||||
this.ComponentProcessors[i].CopyBlocksToColorBuffer(); |
|
||||
buffers[i] = this.ComponentProcessors[i].ColorBuffer; |
|
||||
} |
|
||||
|
|
||||
for (int yy = this.PixelRowCounter; yy < maxY; yy++) |
|
||||
{ |
|
||||
int y = yy - this.PixelRowCounter; |
|
||||
|
|
||||
var values = new JpegColorConverter.ComponentValues(buffers, y); |
|
||||
this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.GetSpan()); |
|
||||
|
|
||||
Span<TPixel> destRow = destination.GetPixelRowSpan(yy); |
|
||||
|
|
||||
// TODO: Investigate if slicing is actually necessary
|
|
||||
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); |
|
||||
} |
|
||||
|
|
||||
this.PixelRowCounter += this.pixelRowsPerStep; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue