Browse Source

CompareSpectralResults

af/merge-core
Anton Firszov 9 years ago
parent
commit
26e645d0eb
  1. 2
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/Component.cs
  2. 18
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/Frame.cs
  3. 62
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/FrameComponent.cs
  4. 26
      src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/ScanDecoder.cs
  5. 57
      src/ImageSharp/Formats/Jpeg/PdfJsPort/JpegDecoderCore.cs
  6. 281
      tests/ImageSharp.Tests/Formats/Jpg/LibJpegTools.cs
  7. 39
      tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs

2
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/Component.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// <summary>
/// Represents a component block
/// </summary>
internal struct Component : IDisposable
internal class Component : IDisposable
{
/// <summary>
/// Gets or sets the output

18
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/Frame.cs

@ -5,6 +5,8 @@ using System;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
using SixLabors.ImageSharp.Memory;
/// <summary>
/// Represent a single jpeg frame
/// </summary>
@ -83,5 +85,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
this.Components = null;
}
}
/// <summary>
/// Allocates the frame component blocks
/// </summary>
public void InitComponents()
{
this.McusPerLine = (int)MathF.Ceiling(this.SamplesPerLine / 8F / this.MaxHorizontalFactor);
this.McusPerColumn = (int)MathF.Ceiling(this.Scanlines / 8F / this.MaxVerticalFactor);
for (int i = 0; i < this.ComponentCount; i++)
{
FrameComponent component = this.Components[i];
component.Init();
}
}
}
}

62
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/FrameComponent.cs

@ -6,6 +6,8 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
using System.Runtime.CompilerServices;
/// <summary>
/// Represents a single frame component
/// </summary>
@ -13,9 +15,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
#pragma warning disable SA1401 // Fields should be private
/// <summary>
/// Gets or sets the component Id
/// Gets the component Id
/// </summary>
public byte Id;
public byte Id { get; }
/// <summary>
/// TODO: What does pred stand for?
@ -23,19 +25,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
public int Pred;
/// <summary>
/// Gets or sets the horizontal sampling factor.
/// Gets the horizontal sampling factor.
/// </summary>
public int HorizontalFactor;
public int HorizontalFactor { get; }
/// <summary>
/// Gets or sets the vertical sampling factor.
/// Gets the vertical sampling factor.
/// </summary>
public int VerticalFactor;
public int VerticalFactor { get; }
/// <summary>
/// Gets or sets the identifier
/// Gets the identifier
/// </summary>
public byte QuantizationIdentifier;
public byte QuantizationIdentifier { get; }
/// <summary>
/// Gets or sets the block data
@ -62,11 +64,55 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
/// </summary>
public int ACHuffmanTableId;
internal int BlocksPerLineForMcu;
internal int BlocksPerColumnForMcu;
public Frame Frame { get; }
public FrameComponent(Frame frame, byte id, int horizontalFactor, int verticalFactor, byte quantizationIdentifier)
{
this.Frame = frame;
this.Id = id;
this.HorizontalFactor = horizontalFactor;
this.VerticalFactor = verticalFactor;
this.QuantizationIdentifier = quantizationIdentifier;
}
/// <inheritdoc/>
public void Dispose()
{
this.BlockData?.Dispose();
this.BlockData = null;
}
public void Init()
{
this.BlocksPerLine = (int)MathF.Ceiling(
MathF.Ceiling(this.Frame.SamplesPerLine / 8F) * this.HorizontalFactor / this.Frame.MaxHorizontalFactor);
this.BlocksPerColumn = (int)MathF.Ceiling(
MathF.Ceiling(this.Frame.Scanlines / 8F) * this.VerticalFactor / this.Frame.MaxVerticalFactor);
this.BlocksPerLineForMcu = this.Frame.McusPerLine * this.HorizontalFactor;
this.BlocksPerColumnForMcu = this.Frame.McusPerColumn * this.VerticalFactor;
int blocksBufferSize = 64 * this.BlocksPerColumnForMcu * (this.BlocksPerLineForMcu + 1);
// Pooled. Disposed via frame disposal
this.BlockData = Buffer<short>.CreateClean(blocksBufferSize);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetBlockBufferOffset(int row, int col)
{
return 64 * (((this.BlocksPerLine + 1) * row) + col);
}
public Span<short> GetBlockBuffer(int row, int col)
{
int offset = this.GetBlockBufferOffset(row, col);
return this.BlockData.Span.Slice(offset, 64);
}
}
}

26
src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/ScanDecoder.cs

@ -187,12 +187,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetBlockBufferOffset(FrameComponent component, int row, int col)
{
return 64 * (((component.BlocksPerLine + 1) * row) + col);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DecodeScanBaseline(
HuffmanTables dcHuffmanTables,
@ -476,7 +470,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
int blockRow = mcu / component.BlocksPerLine;
int blockCol = mcu % component.BlocksPerLine;
int offset = GetBlockBufferOffset(component, blockRow, blockCol);
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeBaseline(component, offset, ref dcHuffmanTable, ref acHuffmanTable, stream);
}
@ -487,7 +481,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalFactor) + row;
int blockCol = (mcuCol * component.HorizontalFactor) + col;
int offset = GetBlockBufferOffset(component, blockRow, blockCol);
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeBaseline(component, offset, ref dcHuffmanTable, ref acHuffmanTable, stream);
}
@ -496,7 +490,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
int blockRow = mcu / component.BlocksPerLine;
int blockCol = mcu % component.BlocksPerLine;
int offset = GetBlockBufferOffset(component, blockRow, blockCol);
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeDCFirst(component, offset, ref dcHuffmanTable, stream);
}
@ -507,7 +501,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalFactor) + row;
int blockCol = (mcuCol * component.HorizontalFactor) + col;
int offset = GetBlockBufferOffset(component, blockRow, blockCol);
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeDCFirst(component, offset, ref dcHuffmanTable, stream);
}
@ -516,7 +510,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
int blockRow = mcu / component.BlocksPerLine;
int blockCol = mcu % component.BlocksPerLine;
int offset = GetBlockBufferOffset(component, blockRow, blockCol);
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeDCSuccessive(component, offset, stream);
}
@ -527,7 +521,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalFactor) + row;
int blockCol = (mcuCol * component.HorizontalFactor) + col;
int offset = GetBlockBufferOffset(component, blockRow, blockCol);
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeDCSuccessive(component, offset, stream);
}
@ -536,7 +530,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
int blockRow = mcu / component.BlocksPerLine;
int blockCol = mcu % component.BlocksPerLine;
int offset = GetBlockBufferOffset(component, blockRow, blockCol);
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeACFirst(component, offset, ref acHuffmanTable, stream);
}
@ -547,7 +541,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalFactor) + row;
int blockCol = (mcuCol * component.HorizontalFactor) + col;
int offset = GetBlockBufferOffset(component, blockRow, blockCol);
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeACFirst(component, offset, ref acHuffmanTable, stream);
}
@ -556,7 +550,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
{
int blockRow = mcu / component.BlocksPerLine;
int blockCol = mcu % component.BlocksPerLine;
int offset = GetBlockBufferOffset(component, blockRow, blockCol);
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeACSuccessive(component, offset, ref acHuffmanTable, stream);
}
@ -567,7 +561,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components
int mcuCol = mcu % mcusPerLine;
int blockRow = (mcuRow * component.VerticalFactor) + row;
int blockCol = (mcuCol * component.HorizontalFactor) + col;
int offset = GetBlockBufferOffset(component, blockRow, blockCol);
int offset = component.GetBlockBufferOffset(blockRow, blockCol);
this.DecodeACSuccessive(component, offset, ref acHuffmanTable, stream);
}

57
src/ImageSharp/Formats/Jpeg/PdfJsPort/JpegDecoderCore.cs

@ -140,6 +140,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
{
ImageMetaData metadata = this.ParseStream(stream);
this.QuantizeAndInverseAllComponents();
var image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, metadata);
this.FillPixelData(image);
this.AssignResolution(image);
@ -275,7 +277,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
for (int i = 0; i < this.components.Components.Length; i++)
{
ref var frameComponent = ref this.Frame.Components[i];
FrameComponent frameComponent = this.Frame.Components[i];
var component = new Component
{
Scale = new System.Numerics.Vector2(
@ -285,13 +287,24 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
BlocksPerColumn = frameComponent.BlocksPerColumn
};
this.BuildComponentData(ref component, ref frameComponent);
// this.QuantizeAndInverseComponentData(ref component, frameComponent);
this.components.Components[i] = component;
}
this.NumberOfComponents = this.components.Components.Length;
}
internal void QuantizeAndInverseAllComponents()
{
for (int i = 0; i < this.components.Components.Length; i++)
{
FrameComponent frameComponent = this.Frame.Components[i];
Component component = this.components.Components[i];
this.QuantizeAndInverseComponentData(component, frameComponent);
}
}
/// <summary>
/// Fills the given image with the color data
/// </summary>
@ -648,13 +661,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
maxV = v;
}
var component = new FrameComponent();
this.Frame.Components[i] = component;
component.Id = this.temp[index];
component.HorizontalFactor = h;
component.VerticalFactor = v;
component.QuantizationIdentifier = this.temp[index + 2];
var component = new FrameComponent(this.Frame, this.temp[index], h, v, this.temp[index + 2]);
this.Frame.Components[i] = component;
this.Frame.ComponentIds[i] = component.Id;
index += 3;
@ -662,7 +671,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
this.Frame.MaxHorizontalFactor = maxH;
this.Frame.MaxVerticalFactor = maxV;
this.PrepareComponents();
this.Frame.InitComponents();
}
/// <summary>
@ -784,7 +793,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
/// </summary>
/// <param name="component">The component</param>
/// <param name="frameComponent">The frame component</param>
private void BuildComponentData(ref Component component, ref FrameComponent frameComponent)
private void QuantizeAndInverseComponentData(Component component, FrameComponent frameComponent)
{
int blocksPerLine = component.BlocksPerLine;
int blocksPerColumn = component.BlocksPerColumn;
@ -830,34 +839,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
tables[index] = new HuffmanTable(codeLengths, values);
}
/// <summary>
/// Allocates the frame component blocks
/// </summary>
private void PrepareComponents()
{
int mcusPerLine = (int)MathF.Ceiling(this.Frame.SamplesPerLine / 8F / this.Frame.MaxHorizontalFactor);
int mcusPerColumn = (int)MathF.Ceiling(this.Frame.Scanlines / 8F / this.Frame.MaxVerticalFactor);
for (int i = 0; i < this.Frame.ComponentCount; i++)
{
ref var component = ref this.Frame.Components[i];
int blocksPerLine = (int)MathF.Ceiling(MathF.Ceiling(this.Frame.SamplesPerLine / 8F) * component.HorizontalFactor / this.Frame.MaxHorizontalFactor);
int blocksPerColumn = (int)MathF.Ceiling(MathF.Ceiling(this.Frame.Scanlines / 8F) * component.VerticalFactor / this.Frame.MaxVerticalFactor);
int blocksPerLineForMcu = mcusPerLine * component.HorizontalFactor;
int blocksPerColumnForMcu = mcusPerColumn * component.VerticalFactor;
int blocksBufferSize = 64 * blocksPerColumnForMcu * (blocksPerLineForMcu + 1);
// Pooled. Disposed via frame disposal
component.BlockData = Buffer<short>.CreateClean(blocksBufferSize);
component.BlocksPerLine = blocksPerLine;
component.BlocksPerColumn = blocksPerColumn;
}
this.Frame.McusPerLine = mcusPerLine;
this.Frame.McusPerColumn = mcusPerColumn;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void FillGrayScaleImage<TPixel>(Image<TPixel> image)
where TPixel : struct, IPixel<TPixel>

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

@ -11,12 +11,13 @@ namespace SixLabors.ImageSharp.Tests
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
using Xunit;
internal static class LibJpegTools
{
public unsafe struct Block
public unsafe struct Block : IEquatable<Block>
{
public Block(short[] data)
{
@ -24,28 +25,45 @@ namespace SixLabors.ImageSharp.Tests
}
public short[] Data { get; }
//public fixed short Data[64];
//public Block8x8(short[] data)
//{
// fixed (short* p = Data)
// {
// for (int i = 0; i < 64; i++)
// {
// p[i] = data[i];
// }
// }
//}
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
public class SpectralData : IEquatable<SpectralData>
{
public int ComponentCount { get; private set; }
@ -132,13 +150,116 @@ namespace SixLabors.ImageSharp.Tests
public static SpectralData LoadFromImageSharpDecoder(JpegDecoderCore decoder)
{
FrameComponent[] srcComponents = decoder.Frame.Components;
ComponentData[] destComponents = new ComponentData[srcComponents.Length];
throw new NotImplementedException();
ComponentData[] destComponents = srcComponents.Select(ComponentData.Load).ToArray();
return new SpectralData(destComponents);
}
public Image<Rgba32> TryCreateRGBSpectralImage()
{
if (this.ComponentCount != 3) return null;
ComponentData c0 = this.Components[0];
ComponentData c1 = this.Components[1];
ComponentData c2 = this.Components[2];
if (c0.Size != c1.Size || c1.Size != c2.Size)
{
return null;
}
Image<Rgba32> result = new Image<Rgba32>(c0.XCount * 8, c0.YCount * 8);
for (int by = 0; by < c0.YCount; by++)
{
for (int bx = 0; bx < c0.XCount; bx++)
{
this.WriteToImage(bx, by, result);
}
}
return result;
}
internal void WriteToImage(int bx, int by, Image<Rgba32> image)
{
ComponentData c0 = this.Components[0];
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];
float d0 = (c0.MaxVal - c0.MinVal);
float d1 = (c1.MaxVal - c1.MinVal);
float d2 = (c2.MaxVal - c2.MinVal);
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
float val0 = c0.GetBlockValue(block0, x, y);
float val1 = c0.GetBlockValue(block1, x, y);
float val2 = c0.GetBlockValue(block2, x, y);
Vector4 v = new Vector4(val0, val1, val2, 1);
Rgba32 color = default(Rgba32);
color.PackFromVector4(v);
int yy = by * 8 + y;
int xx = bx * 8 + x;
image[xx, yy] = color;
}
}
}
public bool Equals(SpectralData other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
if (this.ComponentCount != other.ComponentCount)
{
return false;
}
for (int i = 0; i < this.ComponentCount; i++)
{
ComponentData a = this.Components[i];
ComponentData b = other.Components[i];
if (!a.Equals(b)) return false;
}
return true;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((SpectralData)obj);
}
public override int GetHashCode()
{
unchecked
{
return (this.ComponentCount * 397) ^ (this.Components != null ? this.Components[0].GetHashCode() : 0);
}
}
public static bool operator ==(SpectralData left, SpectralData right)
{
return Equals(left, right);
}
public static bool operator !=(SpectralData left, SpectralData right)
{
return !Equals(left, right);
}
}
public class ComponentData
public class ComponentData : IEquatable<ComponentData>
{
public ComponentData(int yCount, int xCount, int index)
{
@ -148,6 +269,8 @@ namespace SixLabors.ImageSharp.Tests
this.Blocks = new Block[this.YCount, this.XCount];
}
public Size Size => new Size(this.XCount, this.YCount);
public int Index { get; }
public int YCount { get; }
@ -172,16 +295,44 @@ namespace SixLabors.ImageSharp.Tests
private void Init(Array bloxSource)
{
for (int i = 0; i < bloxSource.Length; i++)
for (int y = 0; y < bloxSource.Length; y++)
{
Array row = (Array)bloxSource.GetValue(i);
for (int j = 0; j < row.Length; j++)
Array row = (Array)bloxSource.GetValue(y);
for (int x = 0; x < row.Length; x++)
{
object jBlock = row.GetValue(j);
object jBlock = row.GetValue(x);
short[] data = (short[])GetNonPublicMember(jBlock, "data");
this.MinVal = Math.Min(this.MinVal, data.Min());
this.MaxVal = Math.Max(this.MaxVal, data.Max());
this.Blocks[i, j] = new Block(data);
this.MakeBlock(data, y, x);
}
}
}
private void MakeBlock(short[] data, int y, int x)
{
this.MinVal = Math.Min(this.MinVal, data.Min());
this.MaxVal = Math.Max(this.MaxVal, data.Max());
this.Blocks[y, x] = new Block(data);
}
public static ComponentData Load(FrameComponent sc, int index)
{
var result = new ComponentData(
sc.BlocksPerColumnForMcu,
sc.BlocksPerLineForMcu,
index
);
result.Init(sc);
return result;
}
private void Init(FrameComponent sc)
{
for (int y = 0; y < this.YCount; y++)
{
for (int x = 0; x < this.XCount; x++)
{
short[] data = sc.GetBlockBuffer(y, x).ToArray();
this.MakeBlock(data, y, x);
}
}
}
@ -194,33 +345,93 @@ namespace SixLabors.ImageSharp.Tests
{
for (int bx = 0; bx < this.XCount; bx++)
{
WriteToImage(this.Blocks[by, bx], bx, by, result);
this.WriteToImage(bx, by, result);
}
}
return result;
}
private void WriteToImage(Block block, int bx, int by, Image<Rgba32> image)
internal void WriteToImage(int bx, int by, Image<Rgba32> image)
{
float d = (this.MaxVal - this.MinVal);
Block block = this.Blocks[by, bx];
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
int yy = by * 8 + y;
int xx = bx * 8 + x;
float val = block[x, y];
val -= this.MinVal;
val /= d;
var val = this.GetBlockValue(block, x, y);
Vector4 v = new Vector4(val, val, val, 1);
Rgba32 color = default(Rgba32);
color.PackFromVector4(v);
int yy = by * 8 + y;
int xx = bx * 8 + x;
image[xx, yy] = color;
}
}
}
internal float GetBlockValue(Block block, int x, int y)
{
float d = (this.MaxVal - this.MinVal);
float val = block[x, y];
val -= this.MinVal;
val /= d;
return val;
}
public bool Equals(ComponentData other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
bool ok = this.Index == other.Index && this.YCount == other.YCount && this.XCount == other.XCount
&& this.MinVal == other.MinVal
&& this.MaxVal == other.MaxVal;
if (!ok) return false;
for (int i = 0; i < this.YCount; i++)
{
for (int j = 0; j < this.XCount; j++)
{
Block a = this.Blocks[i, j];
Block b = other.Blocks[i, j];
if (!a.Equals(b)) return false;
}
}
return true;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((ComponentData)obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = this.Index;
hashCode = (hashCode * 397) ^ this.YCount;
hashCode = (hashCode * 397) ^ this.XCount;
hashCode = (hashCode * 397) ^ this.MinVal.GetHashCode();
hashCode = (hashCode * 397) ^ this.MaxVal.GetHashCode();
return hashCode;
}
}
public static bool operator ==(ComponentData left, ComponentData right)
{
return Equals(left, right);
}
public static bool operator !=(ComponentData left, ComponentData right)
{
return !Equals(left, right);
}
}
internal static FieldInfo GetNonPublicField(object obj, string fieldName)

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

@ -1,11 +1,14 @@
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests
{
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit;
using Xunit.Abstractions;
@ -34,6 +37,8 @@ namespace SixLabors.ImageSharp.Tests
TestImages.Jpeg.Progressive.Festzug, TestImages.Jpeg.Progressive.Bad.BadEOF
};
public static readonly string[] AllTestJpegs = BaselineTestJpegs.Concat(ProgressiveTestJpegs).ToArray();
[Theory]
[WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Rgba32)]
public void BuildLibJpegSpectralResult<TPixel>(TestImageProvider<TPixel> provider)
@ -68,14 +73,36 @@ namespace SixLabors.ImageSharp.Tests
this.SaveSpectralImage(provider, data);
}
}
[Theory]
[WithFileCollection(nameof(AllTestJpegs), PixelTypes.Rgba32)]
public void CompareSpectralResults<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
JpegDecoderCore decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder());
byte[] sourceBytes = TestFile.Create(provider.SourceFileOrDescription).Bytes;
using (var ms = new MemoryStream(sourceBytes))
{
decoder.ParseStream(ms);
var imageSharpData = LibJpegTools.SpectralData.LoadFromImageSharpDecoder(decoder);
ms.Seek(0, SeekOrigin.Begin);
var libJpegData = LibJpegTools.SpectralData.Load(ms);
Assert.Equal(libJpegData, imageSharpData);
}
}
private void SaveSpectralImage<TPixel>(TestImageProvider<TPixel> provider, LibJpegTools.SpectralData data)
where TPixel : struct, IPixel<TPixel>
{
foreach (LibJpegTools.ComponentData comp in data.Components)
{
this.Output.WriteLine("Min: " + comp.MinVal);
this.Output.WriteLine("MAx: " + comp.MaxVal);
this.Output.WriteLine("Max: " + comp.MaxVal);
using (Image<Rgba32> image = comp.CreateGrayScaleImage())
{
@ -83,6 +110,14 @@ namespace SixLabors.ImageSharp.Tests
image.DebugSave(provider, details, appendPixelTypeToFileName: false);
}
}
Image<Rgba32> fullImage = data.TryCreateRGBSpectralImage();
if (fullImage != null)
{
fullImage.DebugSave(provider, "FULL", appendPixelTypeToFileName: false);
fullImage.Dispose();
}
}
}

Loading…
Cancel
Save