Browse Source

Basement for spectral tests

pull/1694/head
Dmitry Pentin 5 years ago
parent
commit
daccbfbccc
  1. 12
      src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
  2. 25
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  3. 31
      tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs

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

@ -32,10 +32,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private int pixelRowCounter; private int pixelRowCounter;
public SpectralConverter(Configuration configuration, CancellationToken ct) public SpectralConverter(Configuration configuration, CancellationToken cancellationToken)
{ {
this.configuration = configuration; this.configuration = configuration;
this.cancellationToken = ct; this.cancellationToken = cancellationToken;
} }
private bool Converted => this.pixelRowCounter >= this.pixelBuffer.Height; private bool Converted => this.pixelRowCounter >= this.pixelBuffer.Height;
@ -90,10 +90,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
public override void ConvertStrideBaseline() public override void ConvertStrideBaseline()
{ {
// Convert next pixel stride using single spectral `stride'
// Note that zero passing eliminates the need of virtual call from JpegComponentPostProcessor
this.ConvertNextStride(spectralStep: 0);
// Clear spectral stride - this is VERY important as jpeg possibly won't fill entire buffer each stride // Clear spectral stride - this is VERY important as jpeg possibly won't fill entire buffer each stride
// Which leads to decoding artifacts // Which leads to decoding artifacts
// Note that this code clears all buffers of the post processors, it's their responsibility to allocate only single stride // Note that this code clears all buffers of the post processors, it's their responsibility to allocate only single stride
@ -101,6 +97,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{ {
cpp.ClearSpectralBuffers(); cpp.ClearSpectralBuffers();
} }
// Convert next pixel stride using single spectral `stride'
// Note that zero passing eliminates the need of virtual call from JpegComponentPostProcessor
this.ConvertNextStride(spectralStep: 0);
} }
public override void Dispose() public override void Dispose()

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

@ -220,9 +220,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
{ {
using var spectralConverter = new SpectralConverter<TPixel>(this.Configuration, cancellationToken); using var spectralConverter = new SpectralConverter<TPixel>(this.Configuration, cancellationToken);
this.scanDecoder = new HuffmanScanDecoder(stream, spectralConverter, cancellationToken); var scanDecoder = new HuffmanScanDecoder(stream, spectralConverter, cancellationToken);
this.ParseStream(stream, cancellationToken: cancellationToken); this.ParseStream(stream, scanDecoder, cancellationToken);
this.InitExifProfile(); this.InitExifProfile();
this.InitIccProfile(); this.InitIccProfile();
this.InitIptcProfile(); this.InitIptcProfile();
@ -234,7 +234,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <inheritdoc/> /// <inheritdoc/>
public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken) public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{ {
this.ParseStream(stream, true, cancellationToken); this.ParseStream(stream, scanDecoder: null, cancellationToken);
this.InitExifProfile(); this.InitExifProfile();
this.InitIccProfile(); this.InitIccProfile();
this.InitIptcProfile(); this.InitIptcProfile();
@ -244,13 +244,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
} }
/// <summary> /// <summary>
/// Parses the input stream for file markers /// Parses the input stream for file markers.
/// </summary> /// </summary>
/// <param name="stream">The input stream</param> /// <param name="stream">The input stream.</param>
/// <param name="metadataOnly">Whether to decode metadata only.</param> /// <param name="scanDecoder">Scan decoder used exclusively to decode SOS marker.</param>
/// <param name="cancellationToken">The token to monitor cancellation.</param> /// <param name="ct">The token to monitor cancellation.</param>
private void ParseStream(BufferedReadStream stream, bool metadataOnly = false, CancellationToken cancellationToken = default) internal void ParseStream(BufferedReadStream stream, HuffmanScanDecoder scanDecoder, CancellationToken ct)
{ {
bool metadataOnly = scanDecoder == null;
this.scanDecoder = scanDecoder;
this.Metadata = new ImageMetadata(); this.Metadata = new ImageMetadata();
// Check for the Start Of Image marker. // Check for the Start Of Image marker.
@ -279,7 +283,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
while (fileMarker.Marker != JpegConstants.Markers.EOI while (fileMarker.Marker != JpegConstants.Markers.EOI
|| (fileMarker.Marker == JpegConstants.Markers.EOI && fileMarker.Invalid)) || (fileMarker.Marker == JpegConstants.Markers.EOI && fileMarker.Invalid))
{ {
cancellationToken.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
if (!fileMarker.Invalid) if (!fileMarker.Invalid)
{ {
@ -297,7 +301,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
case JpegConstants.Markers.SOS: case JpegConstants.Markers.SOS:
if (!metadataOnly) if (!metadataOnly)
{ {
this.ProcessStartOfScanMarker(stream, cancellationToken); this.ProcessStartOfScanMarker(stream, ct);
break; break;
} }
else else
@ -1030,6 +1034,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
} }
int selectorsCount = stream.ReadByte(); int selectorsCount = stream.ReadByte();
this.Frame.MultiScan = this.Frame.ComponentCount != selectorsCount;
for (int i = 0; i < selectorsCount; i++) for (int i = 0; i < selectorsCount; i++)
{ {
int componentIndex = -1; int componentIndex = -1;

31
tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs

@ -6,6 +6,7 @@ using System.IO;
using System.Linq; using System.Linq;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils;
@ -76,6 +77,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
using var ms = new MemoryStream(sourceBytes); using var ms = new MemoryStream(sourceBytes);
using var bufferedStream = new BufferedReadStream(Configuration.Default, ms); using var bufferedStream = new BufferedReadStream(Configuration.Default, ms);
using var spectralConverter = new SpectralConverter<TPixel>(Configuration.Default, cancellationToken: default);
var scanDecoder = new HuffmanScanDecoder(bufferedStream, spectralConverter, cancellationToken: default);
using Image<Rgba32> image = decoder.Decode<Rgba32>(bufferedStream, cancellationToken: default); using Image<Rgba32> image = decoder.Decode<Rgba32>(bufferedStream, cancellationToken: default);
var imageSharpData = LibJpegTools.SpectralData.LoadFromImageSharpDecoder(decoder); var imageSharpData = LibJpegTools.SpectralData.LoadFromImageSharpDecoder(decoder);
@ -126,5 +131,31 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.True(totalDifference < tolerance); Assert.True(totalDifference < tolerance);
} }
private class DebugSpectralConverter<TPixel> : SpectralConverter
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly SpectralConverter<TPixel> converter;
public DebugSpectralConverter(SpectralConverter<TPixel> converter)
{
this.converter = converter;
}
public override void ConvertStrideBaseline()
{
this.converter.ConvertStrideBaseline();
}
public override void Dispose()
{
this.converter?.Dispose();
}
public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData)
{
this.converter.InjectFrameData(frame, jpegData);
}
}
} }
} }

Loading…
Cancel
Save