Browse Source

open up OldJpegDecoderCore API for testing

af/merge-core
Anton Firszov 9 years ago
parent
commit
c3c29586fe
  1. 42
      src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs
  2. 38
      src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs
  3. 38
      tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs
  4. 69
      tests/ImageSharp.Tests/Formats/Jpg/LibJpegTools.cs
  5. 6
      tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs

42
src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// Represents a Jpeg block with <see cref="short"/> coefficiens.
/// </summary>
// ReSharper disable once InconsistentNaming
internal unsafe struct Block8x8
internal unsafe struct Block8x8 : IEquatable<Block8x8>
{
/// <summary>
/// A number of scalar coefficients in a <see cref="Block8x8F"/>
@ -44,6 +44,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
}
}
public static bool operator ==(Block8x8 left, Block8x8 right)
{
return left.Equals(right);
}
public static bool operator !=(Block8x8 left, Block8x8 right)
{
return !left.Equals(right);
}
/// <summary>
/// Pointer-based "Indexer" (getter part)
/// </summary>
@ -74,6 +84,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
fp[idx] = value;
}
public short GetValueAt(int x, int y) => this[(y * 8) + x];
public Block8x8F AsFloatBlock()
{
@ -124,5 +135,34 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
bld.Append(']');
return bld.ToString();
}
public bool Equals(Block8x8 other)
{
for (int i = 0; i < Size; i++)
{
if (this[i] != other[i])
{
return false;
}
}
return true;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is Block8x8 && this.Equals((Block8x8)obj);
}
public override int GetHashCode()
{
return (this[0] * 31) + this[1];
}
}
}

38
src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs

@ -120,7 +120,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// Gets the huffman trees
/// </summary>
public OldHuffmanTree[] HuffmanTrees { get; }
/// <summary>
/// Gets the quantization tables, in zigzag order.
/// </summary>
@ -182,6 +182,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// </summary>
public bool IgnoreMetadata { get; private set; }
/// <summary>
/// Gets the <see cref="ImageMetaData"/> decoded by this decoder instance.
/// </summary>
public ImageMetaData MetaData { get; private set; }
/// <summary>
/// Decodes the image from the specified <see cref="Stream"/> and sets
/// the data to image.
@ -192,10 +197,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
public Image<TPixel> Decode<TPixel>(Stream stream)
where TPixel : struct, IPixel<TPixel>
{
ImageMetaData metadata = new ImageMetaData();
this.ProcessStream(metadata, stream, false);
this.ParseStream(stream, false);
this.ProcessBlocksIntoJpegImageChannels<TPixel>();
Image<TPixel> image = this.ConvertJpegPixelsToImagePixels<TPixel>(metadata);
Image<TPixel> image = this.ConvertJpegPixelsToImagePixels<TPixel>();
return image;
}
@ -254,11 +258,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// <summary>
/// Read metadata from stream and read the blocks in the scans into <see cref="OldComponent.SpectralBlocks"/>.
/// </summary>
/// <param name="metadata">The metadata</param>
/// <param name="stream">The stream</param>
/// <param name="metadataOnly">Whether to decode metadata only.</param>
private void ProcessStream(ImageMetaData metadata, Stream stream, bool metadataOnly)
public void ParseStream(Stream stream, bool metadataOnly)
{
this.MetaData = new ImageMetaData();
this.InputStream = stream;
this.InputProcessor = new InputProcessor(stream, this.Temp);
@ -405,10 +409,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.ProcessApplicationHeader(remaining);
break;
case OldJpegConstants.Markers.APP1:
this.ProcessApp1Marker(remaining, metadata);
this.ProcessApp1Marker(remaining);
break;
case OldJpegConstants.Markers.APP2:
this.ProcessApp2Marker(remaining, metadata);
this.ProcessApp2Marker(remaining);
break;
case OldJpegConstants.Markers.APP14:
this.ProcessApp14Marker(remaining);
@ -475,12 +479,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// Convert the pixel data in <see cref="YCbCrImage"/> and/or <see cref="OldJpegPixelArea"/> into pixels of <see cref="Image{TPixel}"/>
/// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam>
/// <param name="metadata">The metadata for the image.</param>
/// <returns>The decoded image.</returns>
private Image<TPixel> ConvertJpegPixelsToImagePixels<TPixel>(ImageMetaData metadata)
private Image<TPixel> ConvertJpegPixelsToImagePixels<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
Image<TPixel> image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, metadata);
var image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData);
if (this.grayImage.IsInitialized)
{
@ -929,7 +932,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// </summary>
/// <param name="remaining">The remaining bytes in the segment block.</param>
/// <param name="metadata">The image.</param>
private void ProcessApp1Marker(int remaining, ImageMetaData metadata)
private void ProcessApp1Marker(int remaining)
{
if (remaining < 6 || this.IgnoreMetadata)
{
@ -948,7 +951,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
profile[5] == '\0')
{
this.isExif = true;
metadata.ExifProfile = new ExifProfile(profile);
this.MetaData.ExifProfile = new ExifProfile(profile);
}
}
@ -956,8 +959,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// Processes the App2 marker retrieving any stored ICC profile information
/// </summary>
/// <param name="remaining">The remaining bytes in the segment block.</param>
/// <param name="metadata">The image.</param>
private void ProcessApp2Marker(int remaining, ImageMetaData metadata)
private void ProcessApp2Marker(int remaining)
{
// Length is 14 though we only need to check 12.
const int Icclength = 14;
@ -987,13 +989,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
byte[] profile = new byte[remaining];
this.InputProcessor.ReadFull(profile, 0, remaining);
if (metadata.IccProfile == null)
if (this.MetaData.IccProfile == null)
{
metadata.IccProfile = new IccProfile(profile);
this.MetaData.IccProfile = new IccProfile(profile);
}
else
{
metadata.IccProfile.Extend(profile);
this.MetaData.IccProfile.Extend(profile);
}
}
else

38
tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs

@ -87,5 +87,43 @@ namespace SixLabors.ImageSharp.Tests
Assert.Equal(data, result);
}
[Fact]
public void Equality_WhenTrue()
{
short[] data = Create8x8ShortData();
var block1 = new Block8x8(data);
var block2 = new Block8x8(data);
block1[0] = 42;
block2[0] = 42;
Assert.Equal(block1, block2);
Assert.Equal(block1.GetHashCode(), block2.GetHashCode());
}
[Fact]
public void Equality_WhenFalse()
{
short[] data = Create8x8ShortData();
var block1 = new Block8x8(data);
var block2 = new Block8x8(data);
block1[0] = 42;
block2[0] = 666;
Assert.NotEqual(block1, block2);
}
[Fact]
public void GetValueAt()
{
var block = default(Block8x8);
block[8 * 3 + 5] = 42;
short value = block.GetValueAt(5, 3);
Assert.Equal(42, value);
}
}
}

69
tests/ImageSharp.Tests/Formats/Jpg/LibJpegTools.cs

@ -8,6 +8,7 @@ namespace SixLabors.ImageSharp.Tests
using BitMiracle.LibJpeg.Classic;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components;
using SixLabors.ImageSharp.PixelFormats;
@ -17,52 +18,6 @@ namespace SixLabors.ImageSharp.Tests
internal static class LibJpegTools
{
public unsafe struct Block : IEquatable<Block>
{
public Block(short[] data)
{
this.Data = data;
}
public short[] Data { get; }
public short this[int x, int y]
{
get => this.Data[y * 8 + x];
set => this.Data[y * 8 + x] = value;
}
public bool Equals(Block other)
{
for (int i = 0; i < 64; i++)
{
if (this.Data[i] != other.Data[i]) return false;
}
return true;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is Block && Equals((Block)obj);
}
public override int GetHashCode()
{
return (this.Data != null ? this.Data.GetHashCode() : 0);
}
public static bool operator ==(Block left, Block right)
{
return left.Equals(right);
}
public static bool operator !=(Block left, Block right)
{
return !left.Equals(right);
}
}
public class SpectralData : IEquatable<SpectralData>
{
public int ComponentCount { get; private set; }
@ -187,9 +142,9 @@ namespace SixLabors.ImageSharp.Tests
ComponentData c1 = this.Components[1];
ComponentData c2 = this.Components[2];
Block block0 = c0.Blocks[by, bx];
Block block1 = c1.Blocks[by, bx];
Block block2 = c2.Blocks[by, bx];
Block8x8 block0 = c0.Blocks[by, bx];
Block8x8 block1 = c1.Blocks[by, bx];
Block8x8 block2 = c2.Blocks[by, bx];
float d0 = (c0.MaxVal - c0.MinVal);
float d1 = (c1.MaxVal - c1.MinVal);
@ -266,7 +221,7 @@ namespace SixLabors.ImageSharp.Tests
this.YCount = yCount;
this.XCount = xCount;
this.Index = index;
this.Blocks = new Block[this.YCount, this.XCount];
this.Blocks = new Block8x8[this.YCount, this.XCount];
}
public Size Size => new Size(this.XCount, this.YCount);
@ -277,7 +232,7 @@ namespace SixLabors.ImageSharp.Tests
public int XCount { get; }
public Block[,] Blocks { get; private set; }
public Block8x8[,] Blocks { get; private set; }
public short MinVal { get; private set; } = short.MaxValue;
@ -311,7 +266,7 @@ namespace SixLabors.ImageSharp.Tests
{
this.MinVal = Math.Min(this.MinVal, data.Min());
this.MaxVal = Math.Max(this.MaxVal, data.Max());
this.Blocks[y, x] = new Block(data);
this.Blocks[y, x] = new Block8x8(data);
}
public static ComponentData Load(FrameComponent sc, int index)
@ -353,7 +308,7 @@ namespace SixLabors.ImageSharp.Tests
internal void WriteToImage(int bx, int by, Image<Rgba32> image)
{
Block block = this.Blocks[by, bx];
Block8x8 block = this.Blocks[by, bx];
for (int y = 0; y < 8; y++)
{
@ -372,10 +327,10 @@ namespace SixLabors.ImageSharp.Tests
}
}
internal float GetBlockValue(Block block, int x, int y)
internal float GetBlockValue(Block8x8 block, int x, int y)
{
float d = (this.MaxVal - this.MinVal);
float val = block[x, y];
float val = block.GetValueAt(x, y);
val -= this.MinVal;
val /= d;
return val;
@ -394,8 +349,8 @@ namespace SixLabors.ImageSharp.Tests
{
for (int j = 0; j < this.XCount; j++)
{
Block a = this.Blocks[i, j];
Block b = other.Blocks[i, j];
Block8x8 a = this.Blocks[i, j];
Block8x8 b = other.Blocks[i, j];
if (!a.Equals(b)) return false;
}
}

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

@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Tests
[Theory]
[WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
public void JpegDecoderCore_ParseStream_SaveSpectralResult<TPixel>(TestImageProvider<TPixel> provider)
public void PdfJsDecoder_ParseStream_SaveSpectralResult<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
JpegDecoderCore decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder());
@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests
[Theory]
[WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)]
public void CompareSpectralResults<TPixel>(TestImageProvider<TPixel> provider)
public void CompareSpectralResults_PdfJs<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
JpegDecoderCore decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder());
@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Tests
bool equality = libJpegData.Equals(imageSharpData);
this.Output.WriteLine("Spectral data equality: " + equality);
// Assert.Equal(libJpegData, imageSharpData);
Assert.Equal(libJpegData, imageSharpData);
}
}

Loading…
Cancel
Save