Browse Source

minor cache optimiziation + benchmarks

pull/34/head
Anton Firszov 10 years ago
parent
commit
a5eb0e825f
  1. 6
      ImageSharp.46.sln
  2. 21
      src/ImageSharp46/Formats/Jpg/Components/Block.cs
  3. 10
      src/ImageSharp46/Formats/Jpg/Components/Component.cs
  4. 2
      src/ImageSharp46/Formats/Jpg/Components/FDCT.cs
  5. 29
      src/ImageSharp46/Formats/Jpg/Components/Huffman.cs
  6. 6
      src/ImageSharp46/Formats/Jpg/Components/IDCT.cs
  7. 274
      src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs
  8. 23
      src/ImageSharp46/Formats/Jpg/JpegEncoderCore.cs
  9. 5
      src/ImageSharp46/ImageSharp46.csproj
  10. 1
      src/ImageSharp46/packages.config
  11. 22
      tests/ConsoleBenchmark/App.config
  12. 89
      tests/ConsoleBenchmark/ConsoleBenchmark.csproj
  13. 36
      tests/ConsoleBenchmark/Program.cs
  14. 36
      tests/ConsoleBenchmark/Properties/AssemblyInfo.cs
  15. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Bmp/Car.bmp
  16. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Bmp/F.bmp
  17. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Bmp/neg_height.bmp
  18. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Gif/giphy.gif
  19. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Gif/rings.gif
  20. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/Calliphora.jpg
  21. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/Floorplan.jpeg
  22. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/cmyk.jpg
  23. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/exif.jpg
  24. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/fb.jpg
  25. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg
  26. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/progress.jpg
  27. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/turtle.jpg
  28. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Png/blur.png
  29. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Png/indexed.png
  30. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Png/pd.png
  31. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Png/pl.png
  32. BIN
      tests/ConsoleBenchmark/TestImages/Formats/Png/splash.png
  33. 8
      tests/ConsoleBenchmark/packages.config
  34. 22
      tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs
  35. 6
      tests/ImageSharp.Tests46/Benchmark/DecodeJpegBenchmark.cs
  36. 20
      tests/ImageSharp.Tests46/ImageSharp.Tests46.csproj
  37. 38
      tests/ImageSharp.Tests46/JpegSandbox.cs
  38. 23
      tests/ImageSharp.Tests46/TestImages.cs
  39. 2
      tests/ImageSharp.Tests46/packages.config

6
ImageSharp.46.sln

@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp46", "src\ImageSh
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Tests46", "tests\ImageSharp.Tests46\ImageSharp.Tests46.csproj", "{635E0A15-3893-4763-A7F6-FCCFF85BCCA4}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Tests46", "tests\ImageSharp.Tests46\ImageSharp.Tests46.csproj", "{635E0A15-3893-4763-A7F6-FCCFF85BCCA4}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleBenchmark", "tests\ConsoleBenchmark\ConsoleBenchmark.csproj", "{8783E3A1-79F1-4E37-AA79-F06C48BED5E7}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -21,6 +23,10 @@ Global
{635E0A15-3893-4763-A7F6-FCCFF85BCCA4}.Debug|Any CPU.Build.0 = Debug|Any CPU {635E0A15-3893-4763-A7F6-FCCFF85BCCA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{635E0A15-3893-4763-A7F6-FCCFF85BCCA4}.Release|Any CPU.ActiveCfg = Release|Any CPU {635E0A15-3893-4763-A7F6-FCCFF85BCCA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{635E0A15-3893-4763-A7F6-FCCFF85BCCA4}.Release|Any CPU.Build.0 = Release|Any CPU {635E0A15-3893-4763-A7F6-FCCFF85BCCA4}.Release|Any CPU.Build.0 = Release|Any CPU
{8783E3A1-79F1-4E37-AA79-F06C48BED5E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8783E3A1-79F1-4E37-AA79-F06C48BED5E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8783E3A1-79F1-4E37-AA79-F06C48BED5E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8783E3A1-79F1-4E37-AA79-F06C48BED5E7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

21
src/ImageSharp46/Formats/Jpg/Components/Block.cs

@ -3,12 +3,14 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
using System.Buffers;
namespace ImageSharp.Formats namespace ImageSharp.Formats
{ {
/// <summary> /// <summary>
/// Represents an 8x8 block of coefficients to transform and encode. /// Represents an 8x8 block of coefficients to transform and encode.
/// </summary> /// </summary>
internal class Block internal struct Block
{ {
/// <summary> /// <summary>
/// Gets the size of the block. /// Gets the size of the block.
@ -18,16 +20,23 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// The array of block data. /// The array of block data.
/// </summary> /// </summary>
private readonly int[] data; public int[] Data;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Block"/> class. /// Initializes a new instance of the <see cref="Block"/> class.
/// </summary> /// </summary>
public Block() //public Block()
//{
// this.data = new int[BlockSize];
//}
public void Init()
{ {
this.data = new int[BlockSize]; this.Data = new int[BlockSize];
} }
public bool IsInitialized => this.Data != null;
/// <summary> /// <summary>
/// Gets the pixel data at the given block index. /// Gets the pixel data at the given block index.
/// </summary> /// </summary>
@ -37,8 +46,8 @@ namespace ImageSharp.Formats
/// </returns> /// </returns>
public int this[int index] public int this[int index]
{ {
get { return this.data[index]; } get { return this.Data[index]; }
set { this.data[index] = value; } set { this.Data[index] = value; }
} }
} }
} }

10
src/ImageSharp46/Formats/Jpg/Components/Component.cs

@ -8,26 +8,26 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Represents a single color component /// Represents a single color component
/// </summary> /// </summary>
internal class Component internal struct Component
{ {
/// <summary> /// <summary>
/// Gets or sets the horizontal sampling factor. /// Gets or sets the horizontal sampling factor.
/// </summary> /// </summary>
public int HorizontalFactor { get; set; } public int HorizontalFactor;
/// <summary> /// <summary>
/// Gets or sets the vertical sampling factor. /// Gets or sets the vertical sampling factor.
/// </summary> /// </summary>
public int VerticalFactor { get; set; } public int VerticalFactor;
/// <summary> /// <summary>
/// Gets or sets the identifier /// Gets or sets the identifier
/// </summary> /// </summary>
public byte Identifier { get; set; } public byte Identifier;
/// <summary> /// <summary>
/// Gets or sets the quantization table destination selector. /// Gets or sets the quantization table destination selector.
/// </summary> /// </summary>
public byte Selector { get; set; } public byte Selector;
} }
} }

2
src/ImageSharp46/Formats/Jpg/Components/FDCT.cs

@ -45,7 +45,7 @@ namespace ImageSharp.Formats
/// Performs a forward DCT on an 8x8 block of coefficients, including a level shift. /// Performs a forward DCT on an 8x8 block of coefficients, including a level shift.
/// </summary> /// </summary>
/// <param name="block">The block of coefficients.</param> /// <param name="block">The block of coefficients.</param>
public static void Transform(Block block) public static void Transform(ref Block block)
{ {
// Pass 1: process rows. // Pass 1: process rows.
for (int y = 0; y < 8; y++) for (int y = 0; y < 8; y++)

29
src/ImageSharp46/Formats/Jpg/Components/Huffman.cs

@ -8,7 +8,7 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Represents a Huffman tree /// Represents a Huffman tree
/// </summary> /// </summary>
internal class Huffman internal struct Huffman
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Huffman"/> class. /// Initializes a new instance of the <see cref="Huffman"/> class.
@ -16,20 +16,29 @@ namespace ImageSharp.Formats
/// <param name="lutSize">The log-2 size of the Huffman decoder's look-up table.</param> /// <param name="lutSize">The log-2 size of the Huffman decoder's look-up table.</param>
/// <param name="maxNCodes">The maximum (inclusive) number of codes in a Huffman tree.</param> /// <param name="maxNCodes">The maximum (inclusive) number of codes in a Huffman tree.</param>
/// <param name="maxCodeLength">The maximum (inclusive) number of bits in a Huffman code.</param> /// <param name="maxCodeLength">The maximum (inclusive) number of bits in a Huffman code.</param>
public Huffman(int lutSize, int maxNCodes, int maxCodeLength) //public Huffman(int lutSize, int maxNCodes, int maxCodeLength)
//{
// this.Lut = new ushort[1 << lutSize];
// this.Values = new byte[maxNCodes];
// this.MinCodes = new int[maxCodeLength];
// this.MaxCodes = new int[maxCodeLength];
// this.Indices = new int[maxCodeLength];
// this.Length = 0;
//}
public void Init(int lutSize, int maxNCodes, int maxCodeLength)
{ {
this.Lut = new ushort[1 << lutSize]; this.Lut = new ushort[1 << lutSize];
this.Values = new byte[maxNCodes]; this.Values = new byte[maxNCodes];
this.MinCodes = new int[maxCodeLength]; this.MinCodes = new int[maxCodeLength];
this.MaxCodes = new int[maxCodeLength]; this.MaxCodes = new int[maxCodeLength];
this.Indices = new int[maxCodeLength]; this.Indices = new int[maxCodeLength];
this.Length = 0;
} }
/// <summary> /// <summary>
/// Gets or sets the number of codes in the tree. /// Gets or sets the number of codes in the tree.
/// </summary> /// </summary>
public int Length { get; set; } public int Length;
/// <summary> /// <summary>
/// Gets the look-up table for the next LutSize bits in the bit-stream. /// Gets the look-up table for the next LutSize bits in the bit-stream.
@ -37,28 +46,30 @@ namespace ImageSharp.Formats
/// are 1 plus the code length, or 0 if the value is too large to fit in /// are 1 plus the code length, or 0 if the value is too large to fit in
/// lutSize bits. /// lutSize bits.
/// </summary> /// </summary>
public ushort[] Lut { get; } public ushort[] Lut;
/// <summary> /// <summary>
/// Gets the the decoded values, sorted by their encoding. /// Gets the the decoded values, sorted by their encoding.
/// </summary> /// </summary>
public byte[] Values { get; } public byte[] Values;
/// <summary> /// <summary>
/// Gets the array of minimum codes. /// Gets the array of minimum codes.
/// MinCodes[i] is the minimum code of length i, or -1 if there are no codes of that length. /// MinCodes[i] is the minimum code of length i, or -1 if there are no codes of that length.
/// </summary> /// </summary>
public int[] MinCodes { get; } public int[] MinCodes;
/// <summary> /// <summary>
/// Gets the array of maximum codes. /// Gets the array of maximum codes.
/// MaxCodes[i] is the maximum code of length i, or -1 if there are no codes of that length. /// MaxCodes[i] is the maximum code of length i, or -1 if there are no codes of that length.
/// </summary> /// </summary>
public int[] MaxCodes { get; } public int[] MaxCodes;
/// <summary> /// <summary>
/// Gets the array of indices. Indices[i] is the index into Values of MinCodes[i]. /// Gets the array of indices. Indices[i] is the index into Values of MinCodes[i].
/// </summary> /// </summary>
public int[] Indices { get; } public int[] Indices;
} }
} }

6
src/ImageSharp46/Formats/Jpg/Components/IDCT.cs

@ -3,6 +3,8 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
using System.Numerics;
namespace ImageSharp.Formats namespace ImageSharp.Formats
{ {
/// <summary> /// <summary>
@ -39,8 +41,10 @@ namespace ImageSharp.Formats
/// ASSP, Vol. ASSP- 32, pp. 803-816, Aug. 1984. /// ASSP, Vol. ASSP- 32, pp. 803-816, Aug. 1984.
/// </summary> /// </summary>
/// <param name="src">The source block of coefficients</param> /// <param name="src">The source block of coefficients</param>
public static void Transform(Block src) public static void Transform(ref Block block)
{ {
var src = block.Data;
// Horizontal 1-D IDCT. // Horizontal 1-D IDCT.
for (int y = 0; y < 8; y++) for (int y = 0; y < 8; y++)
{ {

274
src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs

@ -44,6 +44,8 @@ namespace ImageSharp.Formats
/// </summary> /// </summary>
private const int MaxTh = 3; private const int MaxTh = 3;
private const int ThRowSize = MaxTh + 1;
/// <summary> /// <summary>
/// The maximum number of quantization tables /// The maximum number of quantization tables
/// </summary> /// </summary>
@ -85,7 +87,9 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// The huffman trees /// The huffman trees
/// </summary> /// </summary>
private readonly Huffman[,] huffmanTrees; //private readonly Huffman[,] huffmanTrees;
private readonly Huffman[] huffmanTrees;
/// <summary> /// <summary>
/// Quantization tables, in zigzag order. /// Quantization tables, in zigzag order.
@ -187,12 +191,16 @@ namespace ImageSharp.Formats
/// </summary> /// </summary>
private short verticalResolution; private short verticalResolution;
private int blockIndex;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="JpegDecoderCore"/> class. /// Initializes a new instance of the <see cref="JpegDecoderCore"/> class.
/// </summary> /// </summary>
public JpegDecoderCore() public JpegDecoderCore()
{ {
this.huffmanTrees = new Huffman[MaxTc + 1, MaxTh + 1]; //this.huffmanTrees = new Huffman[MaxTc + 1, MaxTh + 1];
this.huffmanTrees = new Huffman[(MaxTc + 1)*(MaxTh + 1)];
this.quantizationTables = new Block[MaxTq + 1]; this.quantizationTables = new Block[MaxTq + 1];
this.temp = new byte[2 * Block.BlockSize]; this.temp = new byte[2 * Block.BlockSize];
this.componentArray = new Component[MaxComponents]; this.componentArray = new Component[MaxComponents];
@ -201,23 +209,26 @@ namespace ImageSharp.Formats
this.bytes = new Bytes(); this.bytes = new Bytes();
// TODO: This looks like it could be static. // TODO: This looks like it could be static.
for (int i = 0; i < MaxTc + 1; i++) for (int i = 0; i < MaxTc + 1; i++)
{ {
for (int j = 0; j < MaxTh + 1; j++) for (int j = 0; j < MaxTh + 1; j++)
{ {
this.huffmanTrees[i, j] = new Huffman(LutSize, MaxNCodes, MaxCodeLength); //this.huffmanTrees[i, j].Init(LutSize, MaxNCodes, MaxCodeLength);
this.huffmanTrees[i* ThRowSize + j].Init(LutSize, MaxNCodes, MaxCodeLength);
} }
} }
for (int i = 0; i < this.quantizationTables.Length; i++) for (int i = 0; i < this.quantizationTables.Length; i++)
{ {
this.quantizationTables[i] = new Block(); //this.quantizationTables[i] = new Block();
this.quantizationTables[i].Init();
} }
for (int i = 0; i < this.componentArray.Length; i++) //for (int i = 0; i < this.componentArray.Length; i++)
{ //{
this.componentArray[i] = new Component(); // this.componentArray[i] = new Component();
} //}
} }
@ -502,7 +513,12 @@ namespace ImageSharp.Formats
throw new ImageFormatException("Bad Th value"); throw new ImageFormatException("Bad Th value");
} }
Huffman huffman = this.huffmanTrees[tc, th]; ProcessDefineHuffmanTablesMarkerLoop(ref this.huffmanTrees[tc* ThRowSize + th], ref remaining);
}
}
private void ProcessDefineHuffmanTablesMarkerLoop(ref Huffman huffman, ref int remaining)
{
// Read nCodes and huffman.Valuess (and derive h.Length). // Read nCodes and huffman.Valuess (and derive h.Length).
// nCodes[i] is the number of codes with code length i. // nCodes[i] is the number of codes with code length i.
@ -553,8 +569,8 @@ namespace ImageSharp.Formats
// whose codeLength's high bits matches code. // whose codeLength's high bits matches code.
// The high 8 bits of lutValue are the encoded value. // The high 8 bits of lutValue are the encoded value.
// The low 8 bits are 1 plus the codeLength. // The low 8 bits are 1 plus the codeLength.
byte base2 = (byte)(code << (7 - i)); byte base2 = (byte) (code << (7 - i));
ushort lutValue = (ushort)((huffman.Values[x] << 8) | (2 + i)); ushort lutValue = (ushort) ((huffman.Values[x] << 8) | (2 + i));
for (int k = 0; k < 1 << (7 - i); k++) for (int k = 0; k < 1 << (7 - i); k++)
{ {
@ -589,14 +605,13 @@ namespace ImageSharp.Formats
c <<= 1; c <<= 1;
} }
} }
}
/// <summary> /// <summary>
/// Returns the next Huffman-coded value from the bit-stream, decoded according to the given value. /// Returns the next Huffman-coded value from the bit-stream, decoded according to the given value.
/// </summary> /// </summary>
/// <param name="huffman">The huffman value</param> /// <param name="huffman">The huffman value</param>
/// <returns>The <see cref="byte"/></returns> /// <returns>The <see cref="byte"/></returns>
private byte DecodeHuffman(Huffman huffman) private byte DecodeHuffman(ref Huffman huffman)
{ {
if (huffman.Length == 0) if (huffman.Length == 0)
{ {
@ -1480,7 +1495,8 @@ namespace ImageSharp.Formats
this.ReadFull(this.temp, 0, remaining); this.ReadFull(this.temp, 0, remaining);
byte scanComponentCount = this.temp[0]; byte scanComponentCount = this.temp[0];
if (remaining != 4 + (2 * scanComponentCount)) int scanComponentCountBy2 = 2 * scanComponentCount;
if (remaining != 4 + scanComponentCountBy2)
{ {
throw new ImageFormatException("SOS length inconsistent with number of components"); throw new ImageFormatException("SOS length inconsistent with number of components");
} }
@ -1490,51 +1506,7 @@ namespace ImageSharp.Formats
for (int i = 0; i < scanComponentCount; i++) for (int i = 0; i < scanComponentCount; i++)
{ {
// Component selector. ProcessScanImpl(i, ref scan[i], scan, ref totalHv);
int cs = this.temp[1 + (2 * i)];
int compIndex = -1;
for (int j = 0; j < this.componentCount; j++)
{
Component compv = this.componentArray[j];
if (cs == compv.Identifier)
{
compIndex = j;
}
}
if (compIndex < 0)
{
throw new ImageFormatException("Unknown component selector");
}
scan[i].Index = (byte)compIndex;
// Section B.2.3 states that "the value of Cs_j shall be different from
// the values of Cs_1 through Cs_(j-1)". Since we have previously
// verified that a frame's component identifiers (C_i values in section
// B.2.2) are unique, it suffices to check that the implicit indexes
// into comp are unique.
for (int j = 0; j < i; j++)
{
if (scan[i].Index == scan[j].Index)
{
throw new ImageFormatException("Repeated component selector");
}
}
totalHv += this.componentArray[compIndex].HorizontalFactor * this.componentArray[compIndex].VerticalFactor;
scan[i].DcTableSelector = (byte)(this.temp[2 + (2 * i)] >> 4);
if (scan[i].DcTableSelector > MaxTh)
{
throw new ImageFormatException("Bad DC table selector value");
}
scan[i].AcTableSelector = (byte)(this.temp[2 + (2 * i)] & 0x0f);
if (scan[i].AcTableSelector > MaxTh)
{
throw new ImageFormatException("Bad AC table selector value");
}
} }
// Section B.2.3 states that if there is more than one component then the // Section B.2.3 states that if there is more than one component then the
@ -1565,10 +1537,10 @@ namespace ImageSharp.Formats
if (this.isProgressive) if (this.isProgressive)
{ {
zigStart = this.temp[1 + (2 * scanComponentCount)]; zigStart = this.temp[1 + scanComponentCountBy2];
zigEnd = this.temp[2 + (2 * scanComponentCount)]; zigEnd = this.temp[2 + scanComponentCountBy2];
ah = this.temp[3 + (2 * scanComponentCount)] >> 4; ah = this.temp[3 + scanComponentCountBy2] >> 4;
al = this.temp[3 + (2 * scanComponentCount)] & 0x0f; al = this.temp[3 + scanComponentCountBy2] & 0x0f;
if ((zigStart == 0 && zigEnd != 0) || zigStart > zigEnd || Block.BlockSize <= zigEnd) if ((zigStart == 0 && zigEnd != 0) || zigStart > zigEnd || Block.BlockSize <= zigEnd)
{ {
@ -1608,7 +1580,7 @@ namespace ImageSharp.Formats
for (int j = 0; j < this.progCoeffs[compIndex].Length; j++) for (int j = 0; j < this.progCoeffs[compIndex].Length; j++)
{ {
this.progCoeffs[compIndex][j] = new Block(); this.progCoeffs[compIndex][j].Init();
} }
} }
} }
@ -1620,7 +1592,7 @@ namespace ImageSharp.Formats
byte expectedRst = JpegConstants.Markers.RST0; byte expectedRst = JpegConstants.Markers.RST0;
// b is the decoded coefficients block, in natural (not zig-zag) order. // b is the decoded coefficients block, in natural (not zig-zag) order.
Block b; //Block b;
int[] dc = new int[MaxComponents]; int[] dc = new int[MaxComponents];
// bx and by are the location of the current block, in units of 8x8 // bx and by are the location of the current block, in units of 8x8
@ -1636,7 +1608,7 @@ namespace ImageSharp.Formats
int compIndex = scan[i].Index; int compIndex = scan[i].Index;
int hi = this.componentArray[compIndex].HorizontalFactor; int hi = this.componentArray[compIndex].HorizontalFactor;
int vi = this.componentArray[compIndex].VerticalFactor; int vi = this.componentArray[compIndex].VerticalFactor;
Block qt = this.quantizationTables[this.componentArray[compIndex].Selector];
for (int j = 0; j < hi * vi; j++) for (int j = 0; j < hi * vi; j++)
{ {
@ -1679,12 +1651,76 @@ namespace ImageSharp.Formats
} }
} }
var qtIndex = this.componentArray[compIndex].Selector;
// Load the previous partially decoded coefficients, if applicable. // Load the previous partially decoded coefficients, if applicable.
b = this.isProgressive ? this.progCoeffs[compIndex][((@by * mxx) * hi) + bx] : new Block();
//b = this.isProgressive ? this.progCoeffs[compIndex][blockIndex] : new Block();
if (this.isProgressive)
{
blockIndex = ((@by * mxx) * hi) + bx;
ProcessBlockImpl(ah,
ref this.progCoeffs[compIndex][blockIndex],
scan, i, zigStart, zigEnd, al, dc, compIndex, @by, mxx, hi, bx,
ref this.quantizationTables[qtIndex]
);
}
else
{
var b = new Block();
b.Init();
ProcessBlockImpl(ah, ref b, scan, i, zigStart, zigEnd, al, dc, compIndex, @by, mxx, hi,
bx, ref this.quantizationTables[qtIndex]
);
}
}
// for j
}
// for i
mcu++;
if (this.restartInterval > 0 && mcu % this.restartInterval == 0 && mcu < mxx * myy)
{
// A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input,
// but this one assumes well-formed input, and hence the restart marker follows immediately.
this.ReadFull(this.temp, 0, 2);
if (this.temp[0] != 0xff || this.temp[1] != expectedRst)
{
throw new ImageFormatException("Bad RST marker");
}
expectedRst++;
if (expectedRst == JpegConstants.Markers.RST7 + 1)
{
expectedRst = JpegConstants.Markers.RST0;
}
// Reset the Huffman decoder.
this.bits = new Bits();
// Reset the DC components, as per section F.2.1.3.1.
dc = new int[MaxComponents];
// Reset the progressive decoder state, as per section G.1.2.2.
this.eobRun = 0;
}
}
// for mx
}
// for my
}
private void ProcessBlockImpl(int ah, ref Block b, Scan[] scan, int i, int zigStart, int zigEnd, int al,
int[] dc, int compIndex, int @by, int mxx, int hi, int bx, ref Block qt)
{
if (ah != 0) if (ah != 0)
{ {
this.Refine(b, this.huffmanTrees[AcTable, scan[i].AcTableSelector], zigStart, zigEnd, 1 << al); this.Refine(ref b, ref this.huffmanTrees[AcTable * ThRowSize + scan[i].AcTableSelector], zigStart, zigEnd, 1 << al);
} }
else else
{ {
@ -1694,7 +1730,7 @@ namespace ImageSharp.Formats
zig++; zig++;
// Decode the DC coefficient, as specified in section F.2.2.1. // Decode the DC coefficient, as specified in section F.2.2.1.
byte value = this.DecodeHuffman(this.huffmanTrees[DcTable, scan[i].DcTableSelector]); byte value = this.DecodeHuffman(ref this.huffmanTrees[DcTable * ThRowSize + scan[i].DcTableSelector]);
if (value > 16) if (value > 16)
{ {
throw new ImageFormatException("Excessive DC component"); throw new ImageFormatException("Excessive DC component");
@ -1712,12 +1748,12 @@ namespace ImageSharp.Formats
else else
{ {
// Decode the AC coefficients, as specified in section F.2.2.2. // Decode the AC coefficients, as specified in section F.2.2.2.
Huffman huffv = this.huffmanTrees[AcTable, scan[i].AcTableSelector]; //Huffman huffv = ;
for (; zig <= zigEnd; zig++) for (; zig <= zigEnd; zig++)
{ {
byte value = this.DecodeHuffman(huffv); byte value = this.DecodeHuffman(ref this.huffmanTrees[AcTable * ThRowSize + scan[i].AcTableSelector]);
byte val0 = (byte)(value >> 4); byte val0 = (byte) (value >> 4);
byte val1 = (byte)(value & 0x0f); byte val1 = (byte) (value & 0x0f);
if (val1 != 0) if (val1 != 0)
{ {
zig += val0; zig += val0;
@ -1733,10 +1769,10 @@ namespace ImageSharp.Formats
{ {
if (val0 != 0x0f) if (val0 != 0x0f)
{ {
this.eobRun = (ushort)(1 << val0); this.eobRun = (ushort) (1 << val0);
if (val0 != 0) if (val0 != 0)
{ {
this.eobRun |= (ushort)this.DecodeBits(val0); this.eobRun |= (ushort) this.DecodeBits(val0);
} }
this.eobRun--; this.eobRun--;
@ -1754,14 +1790,14 @@ namespace ImageSharp.Formats
if (zigEnd != Block.BlockSize - 1 || al != 0) if (zigEnd != Block.BlockSize - 1 || al != 0)
{ {
// We haven't completely decoded this 8x8 block. Save the coefficients. // We haven't completely decoded this 8x8 block. Save the coefficients.
this.progCoeffs[compIndex][((by * mxx) * hi) + bx] = b; this.progCoeffs[compIndex][((@by*mxx)*hi) + bx] = b;
// At this point, we could execute the rest of the loop body to dequantize and // At this point, we could execute the rest of the loop body to dequantize and
// perform the inverse DCT, to save early stages of a progressive image to the // perform the inverse DCT, to save early stages of a progressive image to the
// *image.YCbCr buffers (the whole point of progressive encoding), but in Go, // *image.YCbCr buffers (the whole point of progressive encoding), but in Go,
// the jpeg.Decode function does not return until the entire image is decoded, // the jpeg.Decode function does not return until the entire image is decoded,
// so we "continue" here to avoid wasted computation. // so we "continue" here to avoid wasted computation.
continue; return;
} }
} }
@ -1771,7 +1807,7 @@ namespace ImageSharp.Formats
b[Unzig[zig]] *= qt[zig]; b[Unzig[zig]] *= qt[zig];
} }
IDCT.Transform(b); IDCT.Transform(ref b);
byte[] dst; byte[] dst;
int offset; int offset;
@ -1781,7 +1817,7 @@ namespace ImageSharp.Formats
{ {
dst = this.grayImage.Pixels; dst = this.grayImage.Pixels;
stride = this.grayImage.Stride; stride = this.grayImage.Stride;
offset = this.grayImage.Offset + (8 * ((by * this.grayImage.Stride) + bx)); offset = this.grayImage.Offset + (8*((@by*this.grayImage.Stride) + bx));
} }
else else
{ {
@ -1790,26 +1826,26 @@ namespace ImageSharp.Formats
case 0: case 0:
dst = this.ycbcrImage.YChannel; dst = this.ycbcrImage.YChannel;
stride = this.ycbcrImage.YStride; stride = this.ycbcrImage.YStride;
offset = this.ycbcrImage.YOffset + (8 * ((by * this.ycbcrImage.YStride) + bx)); offset = this.ycbcrImage.YOffset + (8*((@by*this.ycbcrImage.YStride) + bx));
break; break;
case 1: case 1:
dst = this.ycbcrImage.CbChannel; dst = this.ycbcrImage.CbChannel;
stride = this.ycbcrImage.CStride; stride = this.ycbcrImage.CStride;
offset = this.ycbcrImage.COffset + (8 * ((by * this.ycbcrImage.CStride) + bx)); offset = this.ycbcrImage.COffset + (8*((@by*this.ycbcrImage.CStride) + bx));
break; break;
case 2: case 2:
dst = this.ycbcrImage.CrChannel; dst = this.ycbcrImage.CrChannel;
stride = this.ycbcrImage.CStride; stride = this.ycbcrImage.CStride;
offset = this.ycbcrImage.COffset + (8 * ((by * this.ycbcrImage.CStride) + bx)); offset = this.ycbcrImage.COffset + (8*((@by*this.ycbcrImage.CStride) + bx));
break; break;
case 3: case 3:
dst = this.blackPixels; dst = this.blackPixels;
stride = this.blackStride; stride = this.blackStride;
offset = 8 * ((by * this.blackStride) + bx); offset = 8*((@by*this.blackStride) + bx);
break; break;
default: default:
@ -1820,8 +1856,8 @@ namespace ImageSharp.Formats
// Level shift by +128, clip to [0, 255], and write to dst. // Level shift by +128, clip to [0, 255], and write to dst.
for (int y = 0; y < 8; y++) for (int y = 0; y < 8; y++)
{ {
int y8 = y * 8; int y8 = y*8;
int yStride = y * stride; int yStride = y*stride;
for (int x = 0; x < 8; x++) for (int x = 0; x < 8; x++)
{ {
@ -1839,48 +1875,64 @@ namespace ImageSharp.Formats
c += 128; c += 128;
} }
dst[yStride + x + offset] = (byte)c; dst[yStride + x + offset] = (byte) c;
}
} }
} }
// for j
} }
// for i private void ProcessScanImpl(int i, ref Scan currentScan, Scan[] scan, ref int totalHv)
mcu++;
if (this.restartInterval > 0 && mcu % this.restartInterval == 0 && mcu < mxx * myy)
{ {
// A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input, // Component selector.
// but this one assumes well-formed input, and hence the restart marker follows immediately. int cs = this.temp[1 + (2 * i)];
this.ReadFull(this.temp, 0, 2); int compIndex = -1;
if (this.temp[0] != 0xff || this.temp[1] != expectedRst) for (int j = 0; j < this.componentCount; j++)
{ {
throw new ImageFormatException("Bad RST marker"); //Component compv = ;
if (cs == this.componentArray[j].Identifier)
{
compIndex = j;
}
} }
expectedRst++; if (compIndex < 0)
if (expectedRst == JpegConstants.Markers.RST7 + 1)
{ {
expectedRst = JpegConstants.Markers.RST0; throw new ImageFormatException("Unknown component selector");
} }
// Reset the Huffman decoder. currentScan.Index = (byte)compIndex;
this.bits = new Bits();
// Reset the DC components, as per section F.2.1.3.1. ProcessComponentImpl(i, ref currentScan, scan, ref totalHv, ref this.componentArray[compIndex]);
dc = new int[MaxComponents]; }
// Reset the progressive decoder state, as per section G.1.2.2. private void ProcessComponentImpl(int i, ref Scan currentScan, Scan[] scan, ref int totalHv, ref Component currentComponent)
this.eobRun = 0; {
// Section B.2.3 states that "the value of Cs_j shall be different from
// the values of Cs_1 through Cs_(j-1)". Since we have previously
// verified that a frame's component identifiers (C_i values in section
// B.2.2) are unique, it suffices to check that the implicit indexes
// into comp are unique.
for (int j = 0; j < i; j++)
{
if (currentScan.Index == scan[j].Index)
{
throw new ImageFormatException("Repeated component selector");
} }
} }
// for mx
totalHv += currentComponent.HorizontalFactor*currentComponent.VerticalFactor;
currentScan.DcTableSelector = (byte) (this.temp[2 + (2*i)] >> 4);
if (currentScan.DcTableSelector > MaxTh)
{
throw new ImageFormatException("Bad DC table selector value");
} }
// for my currentScan.AcTableSelector = (byte) (this.temp[2 + (2*i)] & 0x0f);
if (currentScan.AcTableSelector > MaxTh)
{
throw new ImageFormatException("Bad AC table selector value");
}
} }
/// <summary> /// <summary>
@ -1891,7 +1943,7 @@ namespace ImageSharp.Formats
/// <param name="zigStart">The zig-zag start index</param> /// <param name="zigStart">The zig-zag start index</param>
/// <param name="zigEnd">The zig-zag end index</param> /// <param name="zigEnd">The zig-zag end index</param>
/// <param name="delta">The low transform offset</param> /// <param name="delta">The low transform offset</param>
private void Refine(Block b, Huffman h, int zigStart, int zigEnd, int delta) private void Refine(ref Block b, ref Huffman h, int zigStart, int zigEnd, int delta)
{ {
// Refining a DC component is trivial. // Refining a DC component is trivial.
if (zigStart == 0) if (zigStart == 0)
@ -1918,7 +1970,7 @@ namespace ImageSharp.Formats
{ {
bool done = false; bool done = false;
int z = 0; int z = 0;
byte val = this.DecodeHuffman(h); byte val = this.DecodeHuffman(ref h);
int val0 = val >> 4; int val0 = val >> 4;
int val1 = val & 0x0f; int val1 = val & 0x0f;

23
src/ImageSharp46/Formats/Jpg/JpegEncoderCore.cs

@ -488,9 +488,9 @@ namespace ImageSharp.Formats
/// <param name="index">The quantization table index.</param> /// <param name="index">The quantization table index.</param>
/// <param name="prevDC">The previous DC value.</param> /// <param name="prevDC">The previous DC value.</param>
/// <returns>The <see cref="int"/></returns> /// <returns>The <see cref="int"/></returns>
private int WriteBlock(Block block, QuantIndex index, int prevDC) private int WriteBlock(ref Block block, QuantIndex index, int prevDC)
{ {
FDCT.Transform(block); FDCT.Transform(ref block);
// Emit the DC delta. // Emit the DC delta.
int dc = Round(block[0], 8 * this.quant[(int)index][0]); int dc = Round(block[0], 8 * this.quant[(int)index][0]);
@ -541,7 +541,8 @@ namespace ImageSharp.Formats
/// <param name="cbBlock">The red chroma block.</param> /// <param name="cbBlock">The red chroma block.</param>
/// <param name="crBlock">The blue chroma block.</param> /// <param name="crBlock">The blue chroma block.</param>
// ReSharper disable StyleCop.SA1305 // ReSharper disable StyleCop.SA1305
private void ToYCbCr<TColor, TPacked>(PixelAccessor<TColor, TPacked> pixels, int x, int y, Block yBlock, Block cbBlock, Block crBlock) private void ToYCbCr<TColor, TPacked>(PixelAccessor<TColor, TPacked> pixels, int x, int y,
ref Block yBlock, ref Block cbBlock, ref Block crBlock)
// ReSharper restore StyleCop.SA1305 // ReSharper restore StyleCop.SA1305
where TColor : struct, IPackedPixel<TPacked> where TColor : struct, IPackedPixel<TPacked>
where TPacked : struct where TPacked : struct
@ -858,10 +859,10 @@ namespace ImageSharp.Formats
{ {
for (int x = 0; x < pixels.Width; x += 8) for (int x = 0; x < pixels.Width; x += 8)
{ {
this.ToYCbCr(pixels, x, y, b, cb, cr); this.ToYCbCr(pixels, x, y, ref b, ref cb, ref cr);
prevDCY = this.WriteBlock(b, QuantIndex.Luminance, prevDCY); prevDCY = this.WriteBlock(ref b, QuantIndex.Luminance, prevDCY);
prevDCCb = this.WriteBlock(cb, QuantIndex.Chrominance, prevDCCb); prevDCCb = this.WriteBlock(ref cb, QuantIndex.Chrominance, prevDCCb);
prevDCCr = this.WriteBlock(cr, QuantIndex.Chrominance, prevDCCr); prevDCCr = this.WriteBlock(ref cr, QuantIndex.Chrominance, prevDCCr);
} }
} }
} }
@ -902,14 +903,14 @@ namespace ImageSharp.Formats
int xOff = (i & 1) * 8; int xOff = (i & 1) * 8;
int yOff = (i & 2) * 4; int yOff = (i & 2) * 4;
this.ToYCbCr(pixels, x + xOff, y + yOff, b, cb[i], cr[i]); this.ToYCbCr(pixels, x + xOff, y + yOff, ref b, ref cb[i], ref cr[i]);
prevDCY = this.WriteBlock(b, QuantIndex.Luminance, prevDCY); prevDCY = this.WriteBlock(ref b, QuantIndex.Luminance, prevDCY);
} }
this.Scale16X16To8X8(b, cb); this.Scale16X16To8X8(b, cb);
prevDCCb = this.WriteBlock(b, QuantIndex.Chrominance, prevDCCb); prevDCCb = this.WriteBlock(ref b, QuantIndex.Chrominance, prevDCCb);
this.Scale16X16To8X8(b, cr); this.Scale16X16To8X8(b, cr);
prevDCCr = this.WriteBlock(b, QuantIndex.Chrominance, prevDCCr); prevDCCr = this.WriteBlock(ref b, QuantIndex.Chrominance, prevDCCr);
} }
} }
} }

5
src/ImageSharp46/ImageSharp46.csproj

@ -86,7 +86,10 @@
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System.Numerics" /> <Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors" /> <Reference Include="System.Numerics.Vectors, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Numerics.Vectors.4.1.1\lib\net46\System.Numerics.Vectors.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Runtime.CompilerServices.Unsafe.4.0.0\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath> <HintPath>..\..\packages\System.Runtime.CompilerServices.Unsafe.4.0.0\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
<Private>True</Private> <Private>True</Private>

1
src/ImageSharp46/packages.config

@ -23,6 +23,7 @@
<package id="System.Net.Http" version="4.1.0" targetFramework="net461" /> <package id="System.Net.Http" version="4.1.0" targetFramework="net461" />
<package id="System.Net.Primitives" version="4.0.11" targetFramework="net461" /> <package id="System.Net.Primitives" version="4.0.11" targetFramework="net461" />
<package id="System.Net.Sockets" version="4.1.0" targetFramework="net461" /> <package id="System.Net.Sockets" version="4.1.0" targetFramework="net461" />
<package id="System.Numerics.Vectors" version="4.1.1" targetFramework="net461" />
<package id="System.ObjectModel" version="4.0.12" targetFramework="net461" /> <package id="System.ObjectModel" version="4.0.12" targetFramework="net461" />
<package id="System.Reflection" version="4.1.0" targetFramework="net461" /> <package id="System.Reflection" version="4.1.0" targetFramework="net461" />
<package id="System.Reflection.Extensions" version="4.0.1" targetFramework="net461" /> <package id="System.Reflection.Extensions" version="4.0.1" targetFramework="net461" />

22
tests/ConsoleBenchmark/App.config

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Security.Cryptography.X509Certificates" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Win32.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

89
tests/ConsoleBenchmark/ConsoleBenchmark.csproj

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8783E3A1-79F1-4E37-AA79-F06C48BED5E7}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ConsoleBenchmark</RootNamespace>
<AssemblyName>ConsoleBenchmark</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Numerics.Vectors.4.1.1\lib\net46\System.Numerics.Vectors.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="xunit.core, Version=2.1.0.3179, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="xunit.execution.desktop, Version=2.1.0.3179, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\ImageSharp46\ImageSharp46.csproj">
<Project>{fba0b5f6-09c2-4317-8ef6-6adb9b20e6b1}</Project>
<Name>ImageSharp46</Name>
</ProjectReference>
<ProjectReference Include="..\ImageSharp.Tests46\ImageSharp.Tests46.csproj">
<Project>{635e0a15-3893-4763-a7f6-fccff85bcca4}</Project>
<Name>ImageSharp.Tests46</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

36
tests/ConsoleBenchmark/Program.cs

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ImageSharp.Tests;
using ImageSharp.Tests46.Benchmark;
using Xunit.Abstractions;
namespace ConsoleBenchmark
{
class Program
{
private class Output : ITestOutputHelper
{
public void WriteLine(string message)
{
Console.WriteLine(message);
}
public void WriteLine(string format, params object[] args)
{
Console.WriteLine(format, args);
}
}
static void Main(string[] args)
{
DecodeJpegBenchmark benchmark = new DecodeJpegBenchmark(new Output());
benchmark.JpegCore(100);
//JpegSandbox test = new JpegSandbox(null);
//test.OpenJpeg_SaveBmp(TestImages.Jpeg.Calliphora);
}
}
}

36
tests/ConsoleBenchmark/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ConsoleBenchmark")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Sapa")]
[assembly: AssemblyProduct("ConsoleBenchmark")]
[assembly: AssemblyCopyright("Copyright © Sapa 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("8783e3a1-79f1-4e37-aa79-f06c48bed5e7")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

BIN
tests/ConsoleBenchmark/TestImages/Formats/Bmp/Car.bmp

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Bmp/F.bmp

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Bmp/neg_height.bmp

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 MiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Gif/giphy.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Gif/rings.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Jpg/Calliphora.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Jpg/Floorplan.jpeg

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Jpg/cmyk.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Jpg/exif.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Jpg/fb.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Jpg/progress.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Jpg/turtle.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Png/blur.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Png/indexed.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Png/pd.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
tests/ConsoleBenchmark/TestImages/Formats/Png/pl.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

BIN
tests/ConsoleBenchmark/TestImages/Formats/Png/splash.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

8
tests/ConsoleBenchmark/packages.config

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="System.Numerics.Vectors" version="4.1.1" targetFramework="net461" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net461" />
<package id="xunit.core" version="2.1.0" targetFramework="net461" />
<package id="xunit.extensibility.core" version="2.1.0" targetFramework="net461" />
<package id="xunit.extensibility.execution" version="2.1.0" targetFramework="net461" />
</packages>

22
tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs

@ -26,17 +26,17 @@ namespace ImageSharp.Benchmarks.Image
} }
} }
[Benchmark(Baseline = true, Description = "System.Drawing Jpeg")] //[Benchmark(Baseline = true, Description = "System.Drawing Jpeg")]
public Size JpegSystemDrawing() //public Size JpegSystemDrawing()
{ //{
using (MemoryStream memoryStream = new MemoryStream(this.jpegBytes)) // using (MemoryStream memoryStream = new MemoryStream(this.jpegBytes))
{ // {
using (Image image = Image.FromStream(memoryStream)) // using (Image image = Image.FromStream(memoryStream))
{ // {
return image.Size; // return image.Size;
} // }
} // }
} //}
[Benchmark(Description = "ImageSharp Jpeg")] [Benchmark(Description = "ImageSharp Jpeg")]
public CoreSize JpegCore() public CoreSize JpegCore()

6
tests/ImageSharp.Tests46/Benchmark/DecodeJpeg.cs → tests/ImageSharp.Tests46/Benchmark/DecodeJpegBenchmark.cs

@ -14,20 +14,20 @@ namespace ImageSharp.Tests46.Benchmark
using CoreImage = ImageSharp.Image; using CoreImage = ImageSharp.Image;
using CoreSize = ImageSharp.Size; using CoreSize = ImageSharp.Size;
public class DecodeJpeg public class DecodeJpegBenchmark
{ {
private static byte[] jpegBytes = File.ReadAllBytes(TestImages.Jpeg.Calliphora); private static byte[] jpegBytes = File.ReadAllBytes(TestImages.Jpeg.Calliphora);
private ITestOutputHelper _output; private ITestOutputHelper _output;
public DecodeJpeg(ITestOutputHelper output) public DecodeJpegBenchmark(ITestOutputHelper output)
{ {
_output = output; _output = output;
} }
private void DoBenchmark(int times, Action<Stream> action, [CallerMemberName]string method = null) private void DoBenchmark(int times, Action<Stream> action, [CallerMemberName]string method = null)
{ {
_output.WriteLine($"Starting {method}.. "); _output.WriteLine($"{method} x {times} ... ");
Stopwatch sw = Stopwatch.StartNew(); Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < times; i++) for (int i = 0; i < times; i++)
{ {

20
tests/ImageSharp.Tests46/ImageSharp.Tests46.csproj

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\packages\xunit.runner.visualstudio.2.1.0\build\net20\xunit.runner.visualstudio.props" Condition="Exists('..\..\packages\xunit.runner.visualstudio.2.1.0\build\net20\xunit.runner.visualstudio.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -12,6 +13,8 @@
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -37,7 +40,10 @@
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Numerics" /> <Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors" /> <Reference Include="System.Numerics.Vectors, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Numerics.Vectors.4.1.1\lib\net46\System.Numerics.Vectors.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
@ -62,7 +68,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Benchmark\DecodeJpeg.cs" /> <Compile Include="Benchmark\DecodeJpegBenchmark.cs" />
<Compile Include="Colors\ColorConversionTests.cs" /> <Compile Include="Colors\ColorConversionTests.cs" />
<Compile Include="Colors\ColorTests.cs" /> <Compile Include="Colors\ColorTests.cs" />
<Compile Include="FileTestBase.cs" /> <Compile Include="FileTestBase.cs" />
@ -148,8 +154,16 @@
<Content Include="TestImages\Formats\Png\pl.png" /> <Content Include="TestImages\Formats\Png\pl.png" />
<Content Include="TestImages\Formats\Png\splash.png" /> <Content Include="TestImages\Formats\Png\splash.png" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\xunit.runner.visualstudio.2.1.0\build\net20\xunit.runner.visualstudio.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\xunit.runner.visualstudio.2.1.0\build\net20\xunit.runner.visualstudio.props'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">

38
tests/ImageSharp.Tests46/JpegSandbox.cs

@ -1,14 +1,26 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Numerics;
using ImageSharp.Formats; using ImageSharp.Formats;
using Xunit; using Xunit;
using Xunit.Abstractions;
namespace ImageSharp.Tests namespace ImageSharp.Tests
{ {
public class JpegSandbox public class JpegSandbox
{ {
public const string SandboxOutputDirectory = "_SandboxOutput"; public const string SandboxOutputDirectory = "_SandboxOutput";
private ITestOutputHelper Output { get; }
public JpegSandbox(ITestOutputHelper output)
{
Output = output;
}
protected string CreateTestOutputFile(string fileName) protected string CreateTestOutputFile(string fileName)
{ {
if (!Directory.Exists(SandboxOutputDirectory)) if (!Directory.Exists(SandboxOutputDirectory))
@ -27,18 +39,36 @@ namespace ImageSharp.Tests
protected Stream CreateOutputStream(string fileName) protected Stream CreateOutputStream(string fileName)
{ {
fileName = CreateTestOutputFile(fileName); fileName = CreateTestOutputFile(fileName);
Output?.WriteLine("Opened for write: "+fileName);
return File.OpenWrite(fileName); return File.OpenWrite(fileName);
} }
[Fact] //public static string[][] AllJpegFiles = new[]
public void OpenJpeg_SaveBmp() //{
// TestImages.Jpeg.All
//};
public static IEnumerable<object[]> AllJpegFiles => TestImages.Jpeg.All.Select(fn => new object[] {fn});
[Theory]
[MemberData(nameof(AllJpegFiles))]
public void OpenJpeg_SaveBmp(string jpegFileName)
{ {
var image = new TestFile(TestImages.Jpeg.Calliphora).CreateImage(); var image = new TestFile(jpegFileName).CreateImage();
string bmpFileName = Path.GetFileNameWithoutExtension(jpegFileName) + ".bmp";
using (var stream = CreateOutputStream(nameof(OpenJpeg_SaveBmp)+".bmp")) using (var stream = CreateOutputStream(bmpFileName))
{ {
image.Save(stream, new BmpFormat()); image.Save(stream, new BmpFormat());
} }
} }
[Fact]
public void Boo()
{
Vector<int> hej = new Vector<int>();
}
} }
} }

23
tests/ImageSharp.Tests46/TestImages.cs

@ -23,15 +23,20 @@ namespace ImageSharp.Tests
public static class Jpeg public static class Jpeg
{ {
private static readonly string folder = "../../TestImages/Formats/Jpg/"; private const string Folder = "../../TestImages/Formats/Jpg/";
public static string Cmyk => folder + "cmyk.jpg"; public const string Cmyk = Folder + "cmyk.jpg";
public static string Exif => folder + "exif.jpeg"; public const string Exif = Folder + "exif.jpg";
public static string Floorplan => folder + "Floorplan.jpeg"; public const string Floorplan = Folder + "Floorplan.jpeg";
public static string Calliphora => folder + "Calliphora.jpg"; public const string Calliphora = Folder + "Calliphora.jpg";
public static string Turtle => folder + "turtle.jpg"; public const string Turtle = Folder + "turtle.jpg";
public static string Fb => folder + "fb.jpg"; public const string Fb = Folder + "fb.jpg";
public static string Progress => folder + "progress.jpg"; public const string Progress = Folder + "progress.jpg";
public static string GammaDalaiLamaGray => folder + "gamma_dalai_lama_gray.jpg"; public const string GammaDalaiLamaGray = Folder + "gamma_dalai_lama_gray.jpg";
public static readonly string[] All = new[]
{
Cmyk, Exif, Floorplan, Calliphora, Turtle, Fb, Progress, GammaDalaiLamaGray
};
} }
public static class Bmp public static class Bmp

2
tests/ImageSharp.Tests46/packages.config

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="System.Numerics.Vectors" version="4.1.1" targetFramework="net461" />
<package id="xunit" version="2.1.0" targetFramework="net461" /> <package id="xunit" version="2.1.0" targetFramework="net461" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net461" /> <package id="xunit.abstractions" version="2.0.0" targetFramework="net461" />
<package id="xunit.assert" version="2.1.0" targetFramework="net461" /> <package id="xunit.assert" version="2.1.0" targetFramework="net461" />
<package id="xunit.core" version="2.1.0" targetFramework="net461" /> <package id="xunit.core" version="2.1.0" targetFramework="net461" />
<package id="xunit.extensibility.core" version="2.1.0" targetFramework="net461" /> <package id="xunit.extensibility.core" version="2.1.0" targetFramework="net461" />
<package id="xunit.extensibility.execution" version="2.1.0" targetFramework="net461" /> <package id="xunit.extensibility.execution" version="2.1.0" targetFramework="net461" />
<package id="xunit.runner.visualstudio" version="2.1.0" targetFramework="net461" />
</packages> </packages>
Loading…
Cancel
Save