Browse Source

Small bug fixes, ready for merging

pull/2076/head
Dmitry Pentin 4 years ago
parent
commit
95c56b0936
  1. 5
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs
  2. 25
      src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
  3. 13
      src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs
  4. 25
      src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
  5. 35
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  6. 4
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
  7. 11
      tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs

5
src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs

@ -247,8 +247,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.scanBuffer = new JpegBitReader(this.stream);
bool fullScan = this.frame.Progressive || this.frame.MultiScan;
this.frame.AllocateComponents(fullScan);
this.frame.AllocateComponents();
if (this.frame.Progressive)
{
@ -326,11 +325,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
if (this.scanComponentCount != 1)
{
this.spectralConverter.PrepareForDecoding();
this.ParseBaselineDataInterleaved();
this.spectralConverter.CommitConversion();
}
else if (this.frame.ComponentCount == 1)
{
this.spectralConverter.PrepareForDecoding();
this.ParseBaselineDataSingleComponent();
this.spectralConverter.CommitConversion();
}

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

@ -109,13 +109,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// The successive approximation low bit end.
public int SuccessiveLow { get; set; }
/// <summary>
/// Decodes the entropy coded data.
/// </summary>
/// <param name="scanComponentCount">Component count in the current scan.</param>
/// <param name="frame">Frame containing decoding data about the frame.</param>
/// <param name="jpegData">Decoding data about the jpeg.</param>
public void ParseEntropyCodedData(int scanComponentCount, JpegFrame frame, IRawJpegData jpegData)
/// <inheritdoc/>
public void ParseEntropyCodedData(int scanComponentCount)
{
this.cancellationToken.ThrowIfCancellationRequested();
@ -123,17 +118,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.scanBuffer = new JpegBitReader(this.stream);
// Decoder can encounter markers which would alter parameters
// needed for spectral buffers allocation and for spectral
// converter allocation
if (this.frame == null)
{
frame.AllocateComponents();
this.frame = frame;
this.components = frame.Components;
this.spectralConverter.InjectFrameData(frame, jpegData);
}
this.frame.AllocateComponents();
if (!this.frame.Progressive)
{
@ -163,11 +148,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
if (this.scanComponentCount != 1)
{
this.spectralConverter.PrepareForDecoding();
this.ParseBaselineDataInterleaved();
this.spectralConverter.CommitConversion();
}
else if (this.frame.ComponentCount == 1)
{
this.spectralConverter.PrepareForDecoding();
this.ParseBaselineDataSingleComponent();
this.spectralConverter.CommitConversion();
}
@ -280,7 +267,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private void ParseBaselineDataSingleComponent()
{
var component = this.frame.Components[0] as JpegComponent;
JpegComponent component = this.frame.Components[0];
int mcuLines = this.frame.McusPerColumn;
int w = component.WidthInBlocks;
int h = component.SamplingFactors.Height;

13
src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter.cs

@ -35,12 +35,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// Injects jpeg image decoding metadata.
/// </summary>
/// <remarks>
/// This is guaranteed to be called only once at SOF marker by <see cref="HuffmanScanDecoder"/>.
/// This should be called exactly once during SOF (Start Of Frame) marker.
/// </remarks>
/// <param name="frame"><see cref="JpegFrame"/> instance containing decoder-specific parameters.</param>
/// <param name="jpegData"><see cref="IRawJpegData"/> instance containing decoder-specific parameters.</param>
/// <param name="frame"><see cref="JpegFrame"/>Instance containing decoder-specific parameters.</param>
/// <param name="jpegData"><see cref="IRawJpegData"/>Instance containing decoder-specific parameters.</param>
public abstract void InjectFrameData(JpegFrame frame, IRawJpegData jpegData);
/// <summary>
/// Initializes this spectral decoder instance for decoding.
/// This should be called exactly once after all markers which can alter
/// spectral decoding parameters.
/// </summary>
public abstract void PrepareForDecoding();
/// <summary>
/// Converts single spectral jpeg stride to color stride in baseline
/// decoding mode.

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

@ -31,6 +31,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// </summary>
private readonly Configuration configuration;
private JpegFrame frame;
private IRawJpegData jpegData;
/// <summary>
/// Jpeg component converters from decompressed spectral to color data.
/// </summary>
@ -99,6 +103,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
if (!this.Converted)
{
this.PrepareForDecoding();
int steps = (int)Math.Ceiling(this.pixelBuffer.Height / (float)this.pixelRowsPerStep);
for (int step = 0; step < steps; step++)
@ -166,18 +172,27 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// <inheritdoc/>
public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData)
{
this.frame = frame;
this.jpegData = jpegData;
}
/// <inheritdoc/>
public override void PrepareForDecoding()
{
DebugGuard.IsTrue(this.colorConverter == null, "SpectralConverter.PrepareForDecoding() must be called once.");
MemoryAllocator allocator = this.configuration.MemoryAllocator;
// color converter from RGB to TPixel
JpegColorConverterBase converter = this.GetColorConverter(frame, jpegData);
JpegColorConverterBase converter = this.GetColorConverter(this.frame, this.jpegData);
this.colorConverter = converter;
// resulting image size
Size pixelSize = CalculateResultingImageSize(frame.PixelSize, this.targetSize, out int blockPixelSize);
Size pixelSize = CalculateResultingImageSize(this.frame.PixelSize, this.targetSize, out int blockPixelSize);
// iteration data
int majorBlockWidth = frame.Components.Max((component) => component.SizeInBlocks.Width);
int majorVerticalSamplingFactor = frame.Components.Max((component) => component.SamplingFactors.Height);
int majorBlockWidth = this.frame.Components.Max((component) => component.SizeInBlocks.Width);
int majorVerticalSamplingFactor = this.frame.Components.Max((component) => component.SamplingFactors.Height);
this.pixelRowsPerStep = majorVerticalSamplingFactor * blockPixelSize;
@ -193,7 +208,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
int batchSize = converter.ElementsPerBatch;
int batchRemainder = bufferWidth & (batchSize - 1);
var postProcessorBufferSize = new Size(bufferWidth + (batchSize - batchRemainder), this.pixelRowsPerStep);
this.componentProcessors = this.CreateComponentProcessors(frame, jpegData, blockPixelSize, postProcessorBufferSize);
this.componentProcessors = this.CreateComponentProcessors(this.frame, this.jpegData, blockPixelSize, postProcessorBufferSize);
// single 'stride' rgba32 buffer for conversion between spectral and TPixel
this.rgbBuffer = allocator.Allocate<byte>(pixelSize.Width * 3);

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

@ -198,6 +198,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
where TPixel : unmanaged, IPixel<TPixel>
=> this.Decode<TPixel>(stream, targetSize: null, cancellationToken);
/// <inheritdoc/>
public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{
this.ParseStream(stream, spectralConverter: null, cancellationToken);
this.InitExifProfile();
this.InitIccProfile();
this.InitIptcProfile();
this.InitXmpProfile();
this.InitDerivedMetadataProperties();
Size pixelSize = this.Frame.PixelSize;
return new ImageInfo(new PixelTypeInfo(this.Frame.BitsPerPixel), pixelSize.Width, pixelSize.Height, this.Metadata);
}
/// <summary>
/// Decodes and downscales the image from the specified stream if possible.
/// </summary>
@ -205,10 +219,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <param name="stream">Stream.</param>
/// <param name="targetSize">Target size.</param>
/// <param name="cancellationToken">Cancellation token.</param>
public Image<TPixel> DecodeInto<TPixel>(BufferedReadStream stream, Size targetSize, CancellationToken cancellationToken)
internal Image<TPixel> DecodeInto<TPixel>(BufferedReadStream stream, Size targetSize, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
=> this.Decode<TPixel>(stream, targetSize, cancellationToken);
private Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Size? targetSize, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
using var spectralConverter = new SpectralConverter<TPixel>(this.Configuration, targetSize);
this.ParseStream(stream, spectralConverter, cancellationToken);
this.InitExifProfile();
this.InitIccProfile();
@ -222,20 +240,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.Metadata);
}
/// <inheritdoc/>
public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{
this.ParseStream(stream, spectralConverter: null, cancellationToken);
this.InitExifProfile();
this.InitIccProfile();
this.InitIptcProfile();
this.InitXmpProfile();
this.InitDerivedMetadataProperties();
Size pixelSize = this.Frame.PixelSize;
return new ImageInfo(new PixelTypeInfo(this.Frame.BitsPerPixel), pixelSize.Width, pixelSize.Height, this.Metadata);
}
/// <summary>
/// Load quantization and/or Huffman tables for subsequent use for jpeg's embedded in tiff's,
/// so those tables do not need to be duplicated with segmented tiff's (tiff's with multiple strips).
@ -1263,6 +1267,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
if (!metadataOnly)
{
this.Frame.Init(maxH, maxV);
this.scanDecoder.InjectFrameData(this.Frame, this);
}
}

4
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs

@ -57,6 +57,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData)
{
}
public override void PrepareForDecoding()
{
}
}
}
}

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

@ -141,6 +141,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
private JpegFrame frame;
private IRawJpegData jpegData;
private LibJpegTools.SpectralData spectralData;
private int baselineScanRowCounter;
@ -153,6 +155,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
// Progressive and multi-scan images must be loaded manually
if (this.frame.Progressive || this.frame.MultiScan)
{
this.PrepareForDecoding();
LibJpegTools.ComponentData[] components = this.spectralData.Components;
for (int i = 0; i < components.Length; i++)
{
@ -190,11 +193,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public override void InjectFrameData(JpegFrame frame, IRawJpegData jpegData)
{
this.frame = frame;
this.jpegData = jpegData;
}
var spectralComponents = new LibJpegTools.ComponentData[frame.ComponentCount];
public override void PrepareForDecoding()
{
var spectralComponents = new LibJpegTools.ComponentData[this.frame.ComponentCount];
for (int i = 0; i < spectralComponents.Length; i++)
{
var component = frame.Components[i] as JpegComponent;
JpegComponent component = this.frame.Components[i];
spectralComponents[i] = new LibJpegTools.ComponentData(component.WidthInBlocks, component.HeightInBlocks, component.Index);
}

Loading…
Cancel
Save