Browse Source

minor cache optimiziation + benchmarks

af/merge-core
Anton Firszov 9 years ago
parent
commit
ee5d3ac38f
  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. 628
      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. 3
      tests/ConsoleBenchmark/TestImages/Formats/Bmp/Car.bmp
  16. 3
      tests/ConsoleBenchmark/TestImages/Formats/Bmp/F.bmp
  17. 3
      tests/ConsoleBenchmark/TestImages/Formats/Bmp/neg_height.bmp
  18. 3
      tests/ConsoleBenchmark/TestImages/Formats/Gif/giphy.gif
  19. 3
      tests/ConsoleBenchmark/TestImages/Formats/Gif/rings.gif
  20. 3
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/Calliphora.jpg
  21. 3
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/Floorplan.jpeg
  22. 3
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/cmyk.jpg
  23. 3
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/exif.jpg
  24. 3
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/fb.jpg
  25. 3
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg
  26. 3
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/progress.jpg
  27. 3
      tests/ConsoleBenchmark/TestImages/Formats/Jpg/turtle.jpg
  28. 3
      tests/ConsoleBenchmark/TestImages/Formats/Png/blur.png
  29. 3
      tests/ConsoleBenchmark/TestImages/Formats/Png/indexed.png
  30. 3
      tests/ConsoleBenchmark/TestImages/Formats/Png/pd.png
  31. 3
      tests/ConsoleBenchmark/TestImages/Formats/Png/pl.png
  32. 3
      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
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Tests46", "tests\ImageSharp.Tests46\ImageSharp.Tests46.csproj", "{635E0A15-3893-4763-A7F6-FCCFF85BCCA4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleBenchmark", "tests\ConsoleBenchmark\ConsoleBenchmark.csproj", "{8783E3A1-79F1-4E37-AA79-F06C48BED5E7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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}.Release|Any CPU.ActiveCfg = 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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

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

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

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

@ -8,26 +8,26 @@ namespace ImageSharp.Formats
/// <summary>
/// Represents a single color component
/// </summary>
internal class Component
internal struct Component
{
/// <summary>
/// Gets or sets the horizontal sampling factor.
/// </summary>
public int HorizontalFactor { get; set; }
public int HorizontalFactor;
/// <summary>
/// Gets or sets the vertical sampling factor.
/// </summary>
public int VerticalFactor { get; set; }
public int VerticalFactor;
/// <summary>
/// Gets or sets the identifier
/// </summary>
public byte Identifier { get; set; }
public byte Identifier;
/// <summary>
/// Gets or sets the quantization table destination selector.
/// </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.
/// </summary>
/// <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.
for (int y = 0; y < 8; y++)

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

@ -8,7 +8,7 @@ namespace ImageSharp.Formats
/// <summary>
/// Represents a Huffman tree
/// </summary>
internal class Huffman
internal struct Huffman
{
/// <summary>
/// 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="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>
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.Values = new byte[maxNCodes];
this.MinCodes = new int[maxCodeLength];
this.MaxCodes = new int[maxCodeLength];
this.Indices = new int[maxCodeLength];
this.Length = 0;
}
/// <summary>
/// Gets or sets the number of codes in the tree.
/// </summary>
public int Length { get; set; }
public int Length;
/// <summary>
/// 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
/// lutSize bits.
/// </summary>
public ushort[] Lut { get; }
public ushort[] Lut;
/// <summary>
/// Gets the the decoded values, sorted by their encoding.
/// </summary>
public byte[] Values { get; }
public byte[] Values;
/// <summary>
/// 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.
/// </summary>
public int[] MinCodes { get; }
public int[] MinCodes;
/// <summary>
/// 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.
/// </summary>
public int[] MaxCodes { get; }
public int[] MaxCodes;
/// <summary>
/// Gets the array of indices. Indices[i] is the index into Values of MinCodes[i].
/// </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.
// </copyright>
using System.Numerics;
namespace ImageSharp.Formats
{
/// <summary>
@ -39,8 +41,10 @@ namespace ImageSharp.Formats
/// ASSP, Vol. ASSP- 32, pp. 803-816, Aug. 1984.
/// </summary>
/// <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.
for (int y = 0; y < 8; y++)
{

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

@ -44,6 +44,8 @@ namespace ImageSharp.Formats
/// </summary>
private const int MaxTh = 3;
private const int ThRowSize = MaxTh + 1;
/// <summary>
/// The maximum number of quantization tables
/// </summary>
@ -85,7 +87,9 @@ namespace ImageSharp.Formats
/// <summary>
/// The huffman trees
/// </summary>
private readonly Huffman[,] huffmanTrees;
//private readonly Huffman[,] huffmanTrees;
private readonly Huffman[] huffmanTrees;
/// <summary>
/// Quantization tables, in zigzag order.
@ -187,12 +191,16 @@ namespace ImageSharp.Formats
/// </summary>
private short verticalResolution;
private int blockIndex;
/// <summary>
/// Initializes a new instance of the <see cref="JpegDecoderCore"/> class.
/// </summary>
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.temp = new byte[2 * Block.BlockSize];
this.componentArray = new Component[MaxComponents];
@ -201,23 +209,26 @@ namespace ImageSharp.Formats
this.bytes = new Bytes();
// TODO: This looks like it could be static.
for (int i = 0; i < MaxTc + 1; i++)
{
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++)
{
this.quantizationTables[i] = new Block();
//this.quantizationTables[i] = new Block();
this.quantizationTables[i].Init();
}
for (int i = 0; i < this.componentArray.Length; i++)
{
this.componentArray[i] = new Component();
}
//for (int i = 0; i < this.componentArray.Length; i++)
//{
// this.componentArray[i] = new Component();
//}
}
@ -502,92 +513,96 @@ namespace ImageSharp.Formats
throw new ImageFormatException("Bad Th value");
}
Huffman huffman = this.huffmanTrees[tc, th];
ProcessDefineHuffmanTablesMarkerLoop(ref this.huffmanTrees[tc* ThRowSize + th], ref remaining);
}
}
// Read nCodes and huffman.Valuess (and derive h.Length).
// nCodes[i] is the number of codes with code length i.
// h.Length is the total number of codes.
huffman.Length = 0;
private void ProcessDefineHuffmanTablesMarkerLoop(ref Huffman huffman, ref int remaining)
{
int[] ncodes = new int[MaxCodeLength];
for (int i = 0; i < ncodes.Length; i++)
{
ncodes[i] = this.temp[i + 1];
huffman.Length += ncodes[i];
}
// Read nCodes and huffman.Valuess (and derive h.Length).
// nCodes[i] is the number of codes with code length i.
// h.Length is the total number of codes.
huffman.Length = 0;
if (huffman.Length == 0)
{
throw new ImageFormatException("Huffman table has zero length");
}
int[] ncodes = new int[MaxCodeLength];
for (int i = 0; i < ncodes.Length; i++)
{
ncodes[i] = this.temp[i + 1];
huffman.Length += ncodes[i];
}
if (huffman.Length > MaxNCodes)
{
throw new ImageFormatException("Huffman table has excessive length");
}
if (huffman.Length == 0)
{
throw new ImageFormatException("Huffman table has zero length");
}
remaining -= huffman.Length + 17;
if (remaining < 0)
{
throw new ImageFormatException("DHT has wrong length");
}
if (huffman.Length > MaxNCodes)
{
throw new ImageFormatException("Huffman table has excessive length");
}
this.ReadFull(huffman.Values, 0, huffman.Length);
remaining -= huffman.Length + 17;
if (remaining < 0)
{
throw new ImageFormatException("DHT has wrong length");
}
// Derive the look-up table.
for (int i = 0; i < huffman.Lut.Length; i++)
{
huffman.Lut[i] = 0;
}
this.ReadFull(huffman.Values, 0, huffman.Length);
// Derive the look-up table.
for (int i = 0; i < huffman.Lut.Length; i++)
{
huffman.Lut[i] = 0;
}
uint x = 0, code = 0;
uint x = 0, code = 0;
for (int i = 0; i < LutSize; i++)
for (int i = 0; i < LutSize; i++)
{
code <<= 1;
for (int j = 0; j < ncodes[i]; j++)
{
code <<= 1;
// The codeLength is 1+i, so shift code by 8-(1+i) to
// calculate the high bits for every 8-bit sequence
// whose codeLength's high bits matches code.
// The high 8 bits of lutValue are the encoded value.
// The low 8 bits are 1 plus the codeLength.
byte base2 = (byte) (code << (7 - i));
ushort lutValue = (ushort) ((huffman.Values[x] << 8) | (2 + i));
for (int j = 0; j < ncodes[i]; j++)
for (int k = 0; k < 1 << (7 - i); k++)
{
// The codeLength is 1+i, so shift code by 8-(1+i) to
// calculate the high bits for every 8-bit sequence
// whose codeLength's high bits matches code.
// The high 8 bits of lutValue are the encoded value.
// The low 8 bits are 1 plus the codeLength.
byte base2 = (byte)(code << (7 - i));
ushort lutValue = (ushort)((huffman.Values[x] << 8) | (2 + i));
for (int k = 0; k < 1 << (7 - i); k++)
{
huffman.Lut[base2 | k] = lutValue;
}
code++;
x++;
huffman.Lut[base2 | k] = lutValue;
}
code++;
x++;
}
}
// Derive minCodes, maxCodes, and indices.
int c = 0, index = 0;
for (int i = 0; i < ncodes.Length; i++)
// Derive minCodes, maxCodes, and indices.
int c = 0, index = 0;
for (int i = 0; i < ncodes.Length; i++)
{
int nc = ncodes[i];
if (nc == 0)
{
int nc = ncodes[i];
if (nc == 0)
{
huffman.MinCodes[i] = -1;
huffman.MaxCodes[i] = -1;
huffman.Indices[i] = -1;
}
else
{
huffman.MinCodes[i] = c;
huffman.MaxCodes[i] = c + nc - 1;
huffman.Indices[i] = index;
c += nc;
index += nc;
}
c <<= 1;
huffman.MinCodes[i] = -1;
huffman.MaxCodes[i] = -1;
huffman.Indices[i] = -1;
}
else
{
huffman.MinCodes[i] = c;
huffman.MaxCodes[i] = c + nc - 1;
huffman.Indices[i] = index;
c += nc;
index += nc;
}
c <<= 1;
}
}
@ -596,7 +611,7 @@ namespace ImageSharp.Formats
/// </summary>
/// <param name="huffman">The huffman value</param>
/// <returns>The <see cref="byte"/></returns>
private byte DecodeHuffman(Huffman huffman)
private byte DecodeHuffman(ref Huffman huffman)
{
if (huffman.Length == 0)
{
@ -1480,7 +1495,8 @@ namespace ImageSharp.Formats
this.ReadFull(this.temp, 0, remaining);
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");
}
@ -1490,51 +1506,7 @@ namespace ImageSharp.Formats
for (int i = 0; i < scanComponentCount; i++)
{
// Component selector.
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");
}
ProcessScanImpl(i, ref scan[i], scan, ref totalHv);
}
// 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)
{
zigStart = this.temp[1 + (2 * scanComponentCount)];
zigEnd = this.temp[2 + (2 * scanComponentCount)];
ah = this.temp[3 + (2 * scanComponentCount)] >> 4;
al = this.temp[3 + (2 * scanComponentCount)] & 0x0f;
zigStart = this.temp[1 + scanComponentCountBy2];
zigEnd = this.temp[2 + scanComponentCountBy2];
ah = this.temp[3 + scanComponentCountBy2] >> 4;
al = this.temp[3 + scanComponentCountBy2] & 0x0f;
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++)
{
this.progCoeffs[compIndex][j] = new Block();
this.progCoeffs[compIndex][j].Init();
}
}
}
@ -1620,7 +1592,7 @@ namespace ImageSharp.Formats
byte expectedRst = JpegConstants.Markers.RST0;
// b is the decoded coefficients block, in natural (not zig-zag) order.
Block b;
//Block b;
int[] dc = new int[MaxComponents];
// 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 hi = this.componentArray[compIndex].HorizontalFactor;
int vi = this.componentArray[compIndex].VerticalFactor;
Block qt = this.quantizationTables[this.componentArray[compIndex].Selector];
for (int j = 0; j < hi * vi; j++)
{
@ -1679,168 +1651,28 @@ namespace ImageSharp.Formats
}
}
var qtIndex = this.componentArray[compIndex].Selector;
// Load the previous partially decoded coefficients, if applicable.
b = this.isProgressive ? this.progCoeffs[compIndex][((@by * mxx) * hi) + bx] : new Block();
if (ah != 0)
{
this.Refine(b, this.huffmanTrees[AcTable, scan[i].AcTableSelector], zigStart, zigEnd, 1 << al);
}
else
{
int zig = zigStart;
if (zig == 0)
{
zig++;
// Decode the DC coefficient, as specified in section F.2.2.1.
byte value = this.DecodeHuffman(this.huffmanTrees[DcTable, scan[i].DcTableSelector]);
if (value > 16)
{
throw new ImageFormatException("Excessive DC component");
}
int deltaDC = this.ReceiveExtend(value);
dc[compIndex] += deltaDC;
b[0] = dc[compIndex] << al;
}
if (zig <= zigEnd && this.eobRun > 0)
{
this.eobRun--;
}
else
{
// Decode the AC coefficients, as specified in section F.2.2.2.
Huffman huffv = this.huffmanTrees[AcTable, scan[i].AcTableSelector];
for (; zig <= zigEnd; zig++)
{
byte value = this.DecodeHuffman(huffv);
byte val0 = (byte)(value >> 4);
byte val1 = (byte)(value & 0x0f);
if (val1 != 0)
{
zig += val0;
if (zig > zigEnd)
{
break;
}
int ac = this.ReceiveExtend(val1);
b[Unzig[zig]] = ac << al;
}
else
{
if (val0 != 0x0f)
{
this.eobRun = (ushort)(1 << val0);
if (val0 != 0)
{
this.eobRun |= (ushort)this.DecodeBits(val0);
}
this.eobRun--;
break;
}
zig += 0x0f;
}
}
}
}
//b = this.isProgressive ? this.progCoeffs[compIndex][blockIndex] : new Block();
if (this.isProgressive)
{
if (zigEnd != Block.BlockSize - 1 || al != 0)
{
// We haven't completely decoded this 8x8 block. Save the coefficients.
this.progCoeffs[compIndex][((by * mxx) * hi) + bx] = b;
// 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
// *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,
// so we "continue" here to avoid wasted computation.
continue;
}
}
// Dequantize, perform the inverse DCT and store the block to the image.
for (int zig = 0; zig < Block.BlockSize; zig++)
{
b[Unzig[zig]] *= qt[zig];
}
IDCT.Transform(b);
byte[] dst;
int offset;
int stride;
if (this.componentCount == 1)
{
dst = this.grayImage.Pixels;
stride = this.grayImage.Stride;
offset = this.grayImage.Offset + (8 * ((by * this.grayImage.Stride) + bx));
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
{
switch (compIndex)
{
case 0:
dst = this.ycbcrImage.YChannel;
stride = this.ycbcrImage.YStride;
offset = this.ycbcrImage.YOffset + (8 * ((by * this.ycbcrImage.YStride) + bx));
break;
case 1:
dst = this.ycbcrImage.CbChannel;
stride = this.ycbcrImage.CStride;
offset = this.ycbcrImage.COffset + (8 * ((by * this.ycbcrImage.CStride) + bx));
break;
case 2:
dst = this.ycbcrImage.CrChannel;
stride = this.ycbcrImage.CStride;
offset = this.ycbcrImage.COffset + (8 * ((by * this.ycbcrImage.CStride) + bx));
break;
case 3:
dst = this.blackPixels;
stride = this.blackStride;
offset = 8 * ((by * this.blackStride) + bx);
break;
default:
throw new ImageFormatException("Too many components");
}
}
// Level shift by +128, clip to [0, 255], and write to dst.
for (int y = 0; y < 8; y++)
{
int y8 = y * 8;
int yStride = y * stride;
for (int x = 0; x < 8; x++)
{
int c = b[y8 + x];
if (c < -128)
{
c = 0;
}
else if (c > 127)
{
c = 255;
}
else
{
c += 128;
}
dst[yStride + x + offset] = (byte)c;
}
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]
);
}
}
@ -1883,6 +1715,226 @@ namespace ImageSharp.Formats
// 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)
{
this.Refine(ref b, ref this.huffmanTrees[AcTable * ThRowSize + scan[i].AcTableSelector], zigStart, zigEnd, 1 << al);
}
else
{
int zig = zigStart;
if (zig == 0)
{
zig++;
// Decode the DC coefficient, as specified in section F.2.2.1.
byte value = this.DecodeHuffman(ref this.huffmanTrees[DcTable * ThRowSize + scan[i].DcTableSelector]);
if (value > 16)
{
throw new ImageFormatException("Excessive DC component");
}
int deltaDC = this.ReceiveExtend(value);
dc[compIndex] += deltaDC;
b[0] = dc[compIndex] << al;
}
if (zig <= zigEnd && this.eobRun > 0)
{
this.eobRun--;
}
else
{
// Decode the AC coefficients, as specified in section F.2.2.2.
//Huffman huffv = ;
for (; zig <= zigEnd; zig++)
{
byte value = this.DecodeHuffman(ref this.huffmanTrees[AcTable * ThRowSize + scan[i].AcTableSelector]);
byte val0 = (byte) (value >> 4);
byte val1 = (byte) (value & 0x0f);
if (val1 != 0)
{
zig += val0;
if (zig > zigEnd)
{
break;
}
int ac = this.ReceiveExtend(val1);
b[Unzig[zig]] = ac << al;
}
else
{
if (val0 != 0x0f)
{
this.eobRun = (ushort) (1 << val0);
if (val0 != 0)
{
this.eobRun |= (ushort) this.DecodeBits(val0);
}
this.eobRun--;
break;
}
zig += 0x0f;
}
}
}
}
if (this.isProgressive)
{
if (zigEnd != Block.BlockSize - 1 || al != 0)
{
// We haven't completely decoded this 8x8 block. Save the coefficients.
this.progCoeffs[compIndex][((@by*mxx)*hi) + bx] = b;
// 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
// *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,
// so we "continue" here to avoid wasted computation.
return;
}
}
// Dequantize, perform the inverse DCT and store the block to the image.
for (int zig = 0; zig < Block.BlockSize; zig++)
{
b[Unzig[zig]] *= qt[zig];
}
IDCT.Transform(ref b);
byte[] dst;
int offset;
int stride;
if (this.componentCount == 1)
{
dst = this.grayImage.Pixels;
stride = this.grayImage.Stride;
offset = this.grayImage.Offset + (8*((@by*this.grayImage.Stride) + bx));
}
else
{
switch (compIndex)
{
case 0:
dst = this.ycbcrImage.YChannel;
stride = this.ycbcrImage.YStride;
offset = this.ycbcrImage.YOffset + (8*((@by*this.ycbcrImage.YStride) + bx));
break;
case 1:
dst = this.ycbcrImage.CbChannel;
stride = this.ycbcrImage.CStride;
offset = this.ycbcrImage.COffset + (8*((@by*this.ycbcrImage.CStride) + bx));
break;
case 2:
dst = this.ycbcrImage.CrChannel;
stride = this.ycbcrImage.CStride;
offset = this.ycbcrImage.COffset + (8*((@by*this.ycbcrImage.CStride) + bx));
break;
case 3:
dst = this.blackPixels;
stride = this.blackStride;
offset = 8*((@by*this.blackStride) + bx);
break;
default:
throw new ImageFormatException("Too many components");
}
}
// Level shift by +128, clip to [0, 255], and write to dst.
for (int y = 0; y < 8; y++)
{
int y8 = y*8;
int yStride = y*stride;
for (int x = 0; x < 8; x++)
{
int c = b[y8 + x];
if (c < -128)
{
c = 0;
}
else if (c > 127)
{
c = 255;
}
else
{
c += 128;
}
dst[yStride + x + offset] = (byte) c;
}
}
}
private void ProcessScanImpl(int i, ref Scan currentScan, Scan[] scan, ref int totalHv)
{
// Component selector.
int cs = this.temp[1 + (2 * i)];
int compIndex = -1;
for (int j = 0; j < this.componentCount; j++)
{
//Component compv = ;
if (cs == this.componentArray[j].Identifier)
{
compIndex = j;
}
}
if (compIndex < 0)
{
throw new ImageFormatException("Unknown component selector");
}
currentScan.Index = (byte)compIndex;
ProcessComponentImpl(i, ref currentScan, scan, ref totalHv, ref this.componentArray[compIndex]);
}
private void ProcessComponentImpl(int i, ref Scan currentScan, Scan[] scan, ref int totalHv, ref Component currentComponent)
{
// 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");
}
}
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");
}
currentScan.AcTableSelector = (byte) (this.temp[2 + (2*i)] & 0x0f);
if (currentScan.AcTableSelector > MaxTh)
{
throw new ImageFormatException("Bad AC table selector value");
}
}
/// <summary>
/// Decodes a successive approximation refinement block, as specified in section G.1.2.
/// </summary>
@ -1891,7 +1943,7 @@ namespace ImageSharp.Formats
/// <param name="zigStart">The zig-zag start index</param>
/// <param name="zigEnd">The zig-zag end index</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.
if (zigStart == 0)
@ -1918,7 +1970,7 @@ namespace ImageSharp.Formats
{
bool done = false;
int z = 0;
byte val = this.DecodeHuffman(h);
byte val = this.DecodeHuffman(ref h);
int val0 = val >> 4;
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="prevDC">The previous DC value.</param>
/// <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.
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="crBlock">The blue chroma block.</param>
// 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
where TColor : struct, IPackedPixel<TPacked>
where TPacked : struct
@ -858,10 +859,10 @@ namespace ImageSharp.Formats
{
for (int x = 0; x < pixels.Width; x += 8)
{
this.ToYCbCr(pixels, x, y, b, cb, cr);
prevDCY = this.WriteBlock(b, QuantIndex.Luminance, prevDCY);
prevDCCb = this.WriteBlock(cb, QuantIndex.Chrominance, prevDCCb);
prevDCCr = this.WriteBlock(cr, QuantIndex.Chrominance, prevDCCr);
this.ToYCbCr(pixels, x, y, ref b, ref cb, ref cr);
prevDCY = this.WriteBlock(ref b, QuantIndex.Luminance, prevDCY);
prevDCCb = this.WriteBlock(ref cb, QuantIndex.Chrominance, prevDCCb);
prevDCCr = this.WriteBlock(ref cr, QuantIndex.Chrominance, prevDCCr);
}
}
}
@ -902,14 +903,14 @@ namespace ImageSharp.Formats
int xOff = (i & 1) * 8;
int yOff = (i & 2) * 4;
this.ToYCbCr(pixels, x + xOff, y + yOff, b, cb[i], cr[i]);
prevDCY = this.WriteBlock(b, QuantIndex.Luminance, prevDCY);
this.ToYCbCr(pixels, x + xOff, y + yOff, ref b, ref cb[i], ref cr[i]);
prevDCY = this.WriteBlock(ref b, QuantIndex.Luminance, prevDCY);
}
this.Scale16X16To8X8(b, cb);
prevDCCb = this.WriteBlock(b, QuantIndex.Chrominance, prevDCCb);
prevDCCb = this.WriteBlock(ref b, QuantIndex.Chrominance, prevDCCb);
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>
</Reference>
<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">
<HintPath>..\..\packages\System.Runtime.CompilerServices.Unsafe.4.0.0\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
<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.Primitives" version="4.0.11" 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.Reflection" version="4.1.0" 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")]

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9d3a4a30cd67db6ded1e57126c7ba275404703e64b3dfb1c9c711128c15b0124
size 810054

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6da008d2b285b2db946e6d4ebf8569b0ddd4a05ef273b38304cb65afccac87b3
size 65502

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:81437b88a5d92fcb545fae4991643a0c73d95d0277dac0b79074971780008c8c
size 6220854

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3f42abd9f3e493a0acd5303ab0d37a6179835c5a14364a1f001abd9d9e906f96
size 53655

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:716448da88152225767c024aac498f5b7562b6e8391907cefc9d03dba40050fd
size 53435

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:67172fcab405f914587b88cd1106328e6b24ab59d622ba509dcc99509951ff5c
size 254766

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:de00b34b78dfa0886c93d8dd5cede27b4940d5c620e44631e77e6dc8838befc3
size 161577

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:33e3546a64df7fa1d528441926421b193e399a83490a6307762fb7eee9640bf0
size 611572

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8a9d04b92d0de5836c59ede8ae421235488e4031e893e07b1fe7e4b78f6a9901
size 32764

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:93bb4d6281dc1e845db57e836e0dca30b7a4062e81044efb27ad4d8b1a33130c
size 15787

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3d92a88b04518e266b98d9d2f5b4eb88f3f91c332d3397ea859bab8cabc41185
size 84887

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a9a1f0da3c5b3a3e7e7f35abe9f5b458163b48ca56226227b3d3cffe06af1971
size 44884

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9e5c576b0c5e743cfd498b110305268ecbae63c62061ba6c7eb8e060728191f1
size 55126

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:10df946d3d6a9832bacd9ac2587b890c348d17731412c8fd17c34f66f35d9c94
size 183768

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:65566cde707c02757a26fb5fb7702be9c53f55c17a1748d81c384559de2d1173
size 33529

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:91dd938fb916d368738826741551aea694b340ba3362f56200c5d3c5e5510267
size 1406

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:aa550e61fe276d2ebee8666d0cbb811449433edb76e01bcd38cb00c1aafc417e
size 91

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f4c13422913f1c1910f8dd607236e79b4a5c7053deb8ce1c8be8372eca7465fb
size 245033

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")]
public Size JpegSystemDrawing()
{
using (MemoryStream memoryStream = new MemoryStream(this.jpegBytes))
{
using (Image image = Image.FromStream(memoryStream))
{
return image.Size;
}
}
}
//[Benchmark(Baseline = true, Description = "System.Drawing Jpeg")]
//public Size JpegSystemDrawing()
//{
// using (MemoryStream memoryStream = new MemoryStream(this.jpegBytes))
// {
// using (Image image = Image.FromStream(memoryStream))
// {
// return image.Size;
// }
// }
//}
[Benchmark(Description = "ImageSharp Jpeg")]
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 CoreSize = ImageSharp.Size;
public class DecodeJpeg
public class DecodeJpegBenchmark
{
private static byte[] jpegBytes = File.ReadAllBytes(TestImages.Jpeg.Calliphora);
private ITestOutputHelper _output;
public DecodeJpeg(ITestOutputHelper output)
public DecodeJpegBenchmark(ITestOutputHelper output)
{
_output = output;
}
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();
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"?>
<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')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -12,6 +13,8 @@
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -37,7 +40,10 @@
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<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.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@ -62,7 +68,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Benchmark\DecodeJpeg.cs" />
<Compile Include="Benchmark\DecodeJpegBenchmark.cs" />
<Compile Include="Colors\ColorConversionTests.cs" />
<Compile Include="Colors\ColorTests.cs" />
<Compile Include="FileTestBase.cs" />
@ -148,8 +154,16 @@
<Content Include="TestImages\Formats\Png\pl.png" />
<Content Include="TestImages\Formats\Png\splash.png" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<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.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

38
tests/ImageSharp.Tests46/JpegSandbox.cs

@ -1,14 +1,26 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using ImageSharp.Formats;
using Xunit;
using Xunit.Abstractions;
namespace ImageSharp.Tests
{
public class JpegSandbox
{
public const string SandboxOutputDirectory = "_SandboxOutput";
private ITestOutputHelper Output { get; }
public JpegSandbox(ITestOutputHelper output)
{
Output = output;
}
protected string CreateTestOutputFile(string fileName)
{
if (!Directory.Exists(SandboxOutputDirectory))
@ -27,18 +39,36 @@ namespace ImageSharp.Tests
protected Stream CreateOutputStream(string fileName)
{
fileName = CreateTestOutputFile(fileName);
Output?.WriteLine("Opened for write: "+fileName);
return File.OpenWrite(fileName);
}
[Fact]
public void OpenJpeg_SaveBmp()
//public static string[][] AllJpegFiles = new[]
//{
// 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());
}
}
[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
{
private static readonly string folder = "../../TestImages/Formats/Jpg/";
public static string Cmyk => folder + "cmyk.jpg";
public static string Exif => folder + "exif.jpeg";
public static string Floorplan => folder + "Floorplan.jpeg";
public static string Calliphora => folder + "Calliphora.jpg";
public static string Turtle => folder + "turtle.jpg";
public static string Fb => folder + "fb.jpg";
public static string Progress => folder + "progress.jpg";
public static string GammaDalaiLamaGray => folder + "gamma_dalai_lama_gray.jpg";
private const string Folder = "../../TestImages/Formats/Jpg/";
public const string Cmyk = Folder + "cmyk.jpg";
public const string Exif = Folder + "exif.jpg";
public const string Floorplan = Folder + "Floorplan.jpeg";
public const string Calliphora = Folder + "Calliphora.jpg";
public const string Turtle = Folder + "turtle.jpg";
public const string Fb = Folder + "fb.jpg";
public const string Progress = Folder + "progress.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

2
tests/ImageSharp.Tests46/packages.config

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="System.Numerics.Vectors" version="4.1.1" targetFramework="net461" />
<package id="xunit" version="2.1.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.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.runner.visualstudio" version="2.1.0" targetFramework="net461" />
</packages>
Loading…
Cancel
Save