Browse Source

Merge branch 'master' into js/fix-390

af/merge-core
James Jackson-South 8 years ago
parent
commit
dfd5dace83
  1. 2
      src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
  2. 45
      src/ImageSharp/Formats/Png/Zlib/Adler32.cs
  3. 35
      src/ImageSharp/Formats/Png/Zlib/Crc32.cs
  4. 2
      src/ImageSharp/Memory/Buffer2DExtensions.cs
  5. 6
      src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs
  6. 4
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
  7. 5
      src/ImageSharp/Quantizers/Box.cs
  8. 178
      src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs
  9. 20
      tests/ImageSharp.Benchmarks/Image/DecodePng.cs
  10. 1
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  11. 1
      tests/ImageSharp.Tests/TestImages.cs
  12. 2
      tests/Images/External
  13. 3
      tests/Images/Input/Jpg/issues/Issue394-MultiHuffmanBaseline-Speakers.jpg

2
src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs

@ -688,7 +688,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
int th = this.Temp[0] & 0x0f;
if (th > OrigHuffmanTree.MaxTh || (!this.IsProgressive && (th > 1)))
if (th > OrigHuffmanTree.MaxTh)
{
throw new ImageFormatException("Bad Th value");
}

45
src/ImageSharp/Formats/Png/Zlib/Adler32.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Png.Zlib
{
@ -74,9 +75,17 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
/// <inheritdoc/>
public long Value => this.checksum;
public long Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.checksum;
}
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset()
{
this.checksum = 1;
@ -88,6 +97,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// <param name="value">
/// The data value to add. The high byte of the int is ignored.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(int value)
{
// We could make a length 1 byte array and call update again, but I
@ -102,6 +112,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(byte[] buffer)
{
if (buffer == null)
@ -113,32 +124,14 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(byte[] buffer, int offset, int count)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
if (offset < 0)
{
throw new ArgumentOutOfRangeException(nameof(offset), "cannot be negative");
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count), "cannot be negative");
}
if (offset >= buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset), "not a valid index into buffer");
}
if (offset + count > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(count), "exceeds buffer size");
}
DebugGuard.NotNull(buffer, nameof(buffer));
DebugGuard.MustBeGreaterThanOrEqualTo(offset, 0, nameof(offset));
DebugGuard.MustBeGreaterThanOrEqualTo(count, 0, nameof(count));
DebugGuard.MustBeLessThan(offset, buffer.Length, nameof(offset));
DebugGuard.MustBeLessThanOrEqualTo(offset + count, buffer.Length, nameof(count));
// (By Per Bothner)
uint s1 = this.checksum & 0xFFFF;
@ -169,4 +162,4 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
this.checksum = (s2 << 16) | s1;
}
}
}
}

35
src/ImageSharp/Formats/Png/Zlib/Crc32.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Png.Zlib
{
@ -108,18 +109,15 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// <inheritdoc/>
public long Value
{
get
{
return this.crc;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.crc;
set
{
this.crc = (uint)value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => this.crc = (uint)value;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset()
{
this.crc = 0;
@ -129,6 +127,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// Updates the checksum with the given value.
/// </summary>
/// <param name="value">The byte is taken as the lower 8 bits of value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(int value)
{
this.crc ^= CrcSeed;
@ -137,6 +136,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(byte[] buffer)
{
if (buffer == null)
@ -148,22 +148,13 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(byte[] buffer, int offset, int count)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count), "Count cannot be less than zero");
}
if (offset < 0 || offset + count > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
DebugGuard.NotNull(buffer, nameof(buffer));
DebugGuard.MustBeGreaterThanOrEqualTo(count, 0, nameof(count));
DebugGuard.MustBeGreaterThanOrEqualTo(offset, 0, nameof(offset));
DebugGuard.MustBeLessThanOrEqualTo(offset + count, buffer.Length, nameof(count));
this.crc ^= CrcSeed;

2
src/ImageSharp/Memory/Buffer2DExtensions.cs

@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Memory
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="buffer">The <see cref="IBuffer2D{T}"/></param>
/// <param name="rectangle">The rectangel subarea</param>
/// <param name="rectangle">The rectangle subarea</param>
/// <returns>The <see cref="BufferArea{T}"/></returns>
public static BufferArea<T> GetArea<T>(this IBuffer2D<T> buffer, Rectangle rectangle)
where T : struct => new BufferArea<T>(buffer, rectangle);

6
src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
internal abstract partial class ResamplingWeightedProcessor<TPixel>
{
/// <summary>
/// Points to a collection of of weights allocated in <see cref="WeightsBuffer"/>.
/// Points to a collection of weights allocated in <see cref="WeightsBuffer"/>.
/// </summary>
internal struct WeightsWindow
{
@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
}
/// <summary>
/// Holds the <see cref="WeightsWindow"/> values in an optimized contigous memory region.
/// Holds the <see cref="WeightsWindow"/> values in an optimized contiguous memory region.
/// </summary>
internal class WeightsBuffer : IDisposable
{
@ -196,4 +196,4 @@ namespace SixLabors.ImageSharp.Processing.Processors
}
}
}
}
}

4
src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

@ -58,9 +58,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
// We will always be creating the clone even for mutate because thats the way this base processor works
// ------------
// For resize we know we are going to populate every pixel with fresh data and we want a different target size so
// let's manually clone an empty set of images at the correct target and then have the base class processs them in turn.
// let's manually clone an empty set of images at the correct target and then have the base class process them in turn.
IEnumerable<ImageFrame<TPixel>> frames = source.Frames.Select(x => new ImageFrame<TPixel>(this.Width, this.Height, x.MetaData.Clone())); // this will create places holders
var image = new Image<TPixel>(config, source.MetaData.Clone(), frames); // base the place holder images in to prevet a extra frame being added
var image = new Image<TPixel>(config, source.MetaData.Clone(), frames); // base the place holder images in to prevent a extra frame being added
return image;
}

5
src/ImageSharp/Quantizers/Box.cs

@ -5,9 +5,8 @@ namespace SixLabors.ImageSharp.Quantizers
{
/// <summary>
/// Represents a box color cube.
/// TODO: This should be a struct for performance
/// </summary>
internal sealed class Box
internal struct Box
{
/// <summary>
/// Gets or sets the min red value, exclusive.
@ -54,4 +53,4 @@ namespace SixLabors.ImageSharp.Quantizers
/// </summary>
public int Volume { get; set; }
}
}
}

178
src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs

@ -168,20 +168,19 @@ namespace SixLabors.ImageSharp.Quantizers
this.palette = new TPixel[this.colors];
for (int k = 0; k < this.colors; k++)
{
this.Mark(this.colorCube[k], (byte)k);
this.Mark(ref this.colorCube[k], (byte)k);
float weight = Volume(this.colorCube[k], this.vwt);
float weight = Volume(ref this.colorCube[k], this.vwt);
if (MathF.Abs(weight) > Constants.Epsilon)
{
float r = Volume(this.colorCube[k], this.vmr) / weight;
float g = Volume(this.colorCube[k], this.vmg) / weight;
float b = Volume(this.colorCube[k], this.vmb) / weight;
float a = Volume(this.colorCube[k], this.vma) / weight;
var color = default(TPixel);
color.PackFromVector4(new Vector4(r, g, b, a) / 255F);
this.palette[k] = color;
float r = Volume(ref this.colorCube[k], this.vmr);
float g = Volume(ref this.colorCube[k], this.vmg);
float b = Volume(ref this.colorCube[k], this.vmb);
float a = Volume(ref this.colorCube[k], this.vma);
ref TPixel color = ref this.palette[k];
color.PackFromVector4(new Vector4(r, g, b, a) / weight / 255F);
}
}
}
@ -197,19 +196,21 @@ namespace SixLabors.ImageSharp.Quantizers
var rgba = default(Rgba32);
pixel.ToRgba32(ref rgba);
int r = rgba.R >> 2; // 8 - IndexBits
int g = rgba.G >> 2;
int b = rgba.B >> 2;
int a = rgba.A >> 5; // 8 - IndexAlphaBits
int r = rgba.R >> (8 - IndexBits);
int g = rgba.G >> (8 - IndexBits);
int b = rgba.B >> (8 - IndexBits);
int a = rgba.A >> (8 - IndexAlphaBits);
int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
int ind = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
this.vwt[index]++;
this.vmr[index] += rgba.R;
this.vmg[index] += rgba.G;
this.vmb[index] += rgba.B;
this.vma[index] += rgba.A;
this.vwt[ind]++;
this.vmr[ind] += r;
this.vmg[ind] += g;
this.vmb[ind] += b;
this.vma[ind] += a;
this.m2[ind] += (r * r) + (g * g) + (b * b) + (a * a);
var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A);
this.m2[index] += Vector4.Dot(vector, vector);
}
/// <inheritdoc/>
@ -301,7 +302,7 @@ namespace SixLabors.ImageSharp.Quantizers
/// <param name="cube">The cube.</param>
/// <param name="moment">The moment.</param>
/// <returns>The result.</returns>
private static float Volume(Box cube, long[] moment)
private static float Volume(ref Box cube, long[] moment)
{
return moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)]
- moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A0)]
@ -328,12 +329,12 @@ namespace SixLabors.ImageSharp.Quantizers
/// <param name="direction">The direction.</param>
/// <param name="moment">The moment.</param>
/// <returns>The result.</returns>
private static long Bottom(Box cube, int direction, long[] moment)
private static long Bottom(ref Box cube, int direction, long[] moment)
{
switch (direction)
{
// Red
case 0:
case 3:
return -moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A1)]
+ moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)]
@ -344,7 +345,7 @@ namespace SixLabors.ImageSharp.Quantizers
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
// Green
case 1:
case 2:
return -moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A1)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)]
@ -355,7 +356,7 @@ namespace SixLabors.ImageSharp.Quantizers
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
// Blue
case 2:
case 1:
return -moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A1)]
+ moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)]
@ -366,7 +367,7 @@ namespace SixLabors.ImageSharp.Quantizers
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
// Alpha
case 3:
case 0:
return -moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)]
@ -389,12 +390,12 @@ namespace SixLabors.ImageSharp.Quantizers
/// <param name="position">The position.</param>
/// <param name="moment">The moment.</param>
/// <returns>The result.</returns>
private static long Top(Box cube, int direction, int position, long[] moment)
private static long Top(ref Box cube, int direction, int position, long[] moment)
{
switch (direction)
{
// Red
case 0:
case 3:
return moment[GetPaletteIndex(position, cube.G1, cube.B1, cube.A1)]
- moment[GetPaletteIndex(position, cube.G1, cube.B1, cube.A0)]
- moment[GetPaletteIndex(position, cube.G1, cube.B0, cube.A1)]
@ -405,7 +406,7 @@ namespace SixLabors.ImageSharp.Quantizers
- moment[GetPaletteIndex(position, cube.G0, cube.B0, cube.A0)];
// Green
case 1:
case 2:
return moment[GetPaletteIndex(cube.R1, position, cube.B1, cube.A1)]
- moment[GetPaletteIndex(cube.R1, position, cube.B1, cube.A0)]
- moment[GetPaletteIndex(cube.R1, position, cube.B0, cube.A1)]
@ -416,7 +417,7 @@ namespace SixLabors.ImageSharp.Quantizers
- moment[GetPaletteIndex(cube.R0, position, cube.B0, cube.A0)];
// Blue
case 2:
case 1:
return moment[GetPaletteIndex(cube.R1, cube.G1, position, cube.A1)]
- moment[GetPaletteIndex(cube.R1, cube.G1, position, cube.A0)]
- moment[GetPaletteIndex(cube.R1, cube.G0, position, cube.A1)]
@ -427,7 +428,7 @@ namespace SixLabors.ImageSharp.Quantizers
- moment[GetPaletteIndex(cube.R0, cube.G0, position, cube.A0)];
// Alpha
case 3:
case 0:
return moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, position)]
- moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, position)]
- moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, position)]
@ -553,12 +554,12 @@ namespace SixLabors.ImageSharp.Quantizers
/// </summary>
/// <param name="cube">The cube.</param>
/// <returns>The <see cref="float"/>.</returns>
private float Variance(Box cube)
private float Variance(ref Box cube)
{
float dr = Volume(cube, this.vmr);
float dg = Volume(cube, this.vmg);
float db = Volume(cube, this.vmb);
float da = Volume(cube, this.vma);
float dr = Volume(ref cube, this.vmr);
float dg = Volume(ref cube, this.vmg);
float db = Volume(ref cube, this.vmb);
float da = Volume(ref cube, this.vma);
float xx =
this.m2[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)]
@ -578,7 +579,8 @@ namespace SixLabors.ImageSharp.Quantizers
- this.m2[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
+ this.m2[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
return xx - (((dr * dr) + (dg * dg) + (db * db) + (da * da)) / Volume(cube, this.vwt));
var vector = new Vector4(dr, dg, db, da);
return xx - (Vector4.Dot(vector, vector) / Volume(ref cube, this.vwt));
}
/// <summary>
@ -599,38 +601,33 @@ namespace SixLabors.ImageSharp.Quantizers
/// <param name="wholeA">The whole alpha.</param>
/// <param name="wholeW">The whole weight.</param>
/// <returns>The <see cref="float"/>.</returns>
private float Maximize(Box cube, int direction, int first, int last, out int cut, float wholeR, float wholeG, float wholeB, float wholeA, float wholeW)
private float Maximize(ref Box cube, int direction, int first, int last, out int cut, float wholeR, float wholeG, float wholeB, float wholeA, float wholeW)
{
long baseR = Bottom(cube, direction, this.vmr);
long baseG = Bottom(cube, direction, this.vmg);
long baseB = Bottom(cube, direction, this.vmb);
long baseA = Bottom(cube, direction, this.vma);
long baseW = Bottom(cube, direction, this.vwt);
long baseR = Bottom(ref cube, direction, this.vmr);
long baseG = Bottom(ref cube, direction, this.vmg);
long baseB = Bottom(ref cube, direction, this.vmb);
long baseA = Bottom(ref cube, direction, this.vma);
long baseW = Bottom(ref cube, direction, this.vwt);
float max = 0F;
cut = -1;
for (int i = first; i < last; i++)
{
float halfR = baseR + Top(cube, direction, i, this.vmr);
float halfG = baseG + Top(cube, direction, i, this.vmg);
float halfB = baseB + Top(cube, direction, i, this.vmb);
float halfA = baseA + Top(cube, direction, i, this.vma);
float halfW = baseW + Top(cube, direction, i, this.vwt);
float temp;
float halfR = baseR + Top(ref cube, direction, i, this.vmr);
float halfG = baseG + Top(ref cube, direction, i, this.vmg);
float halfB = baseB + Top(ref cube, direction, i, this.vmb);
float halfA = baseA + Top(ref cube, direction, i, this.vma);
float halfW = baseW + Top(ref cube, direction, i, this.vwt);
if (MathF.Abs(halfW) < Constants.Epsilon)
{
continue;
}
temp = ((halfR * halfR) + (halfG * halfG) + (halfB * halfB) + (halfA * halfA)) / halfW;
var vector = new Vector4(halfR, halfG, halfB, halfA);
float temp = Vector4.Dot(vector, vector) / halfW;
halfR = wholeR - halfR;
halfG = wholeG - halfG;
halfB = wholeB - halfB;
halfA = wholeA - halfA;
halfW = wholeW - halfW;
if (MathF.Abs(halfW) < Constants.Epsilon)
@ -638,7 +635,14 @@ namespace SixLabors.ImageSharp.Quantizers
continue;
}
temp += ((halfR * halfR) + (halfG * halfG) + (halfB * halfB) + (halfA * halfA)) / halfW;
halfR = wholeR - halfR;
halfG = wholeG - halfG;
halfB = wholeB - halfB;
halfA = wholeA - halfA;
vector = new Vector4(halfR, halfG, halfB, halfA);
temp += Vector4.Dot(vector, vector) / halfW;
if (temp > max)
{
@ -656,24 +660,24 @@ namespace SixLabors.ImageSharp.Quantizers
/// <param name="set1">The first set.</param>
/// <param name="set2">The second set.</param>
/// <returns>Returns a value indicating whether the box has been split.</returns>
private bool Cut(Box set1, Box set2)
private bool Cut(ref Box set1, ref Box set2)
{
float wholeR = Volume(set1, this.vmr);
float wholeG = Volume(set1, this.vmg);
float wholeB = Volume(set1, this.vmb);
float wholeA = Volume(set1, this.vma);
float wholeW = Volume(set1, this.vwt);
float wholeR = Volume(ref set1, this.vmr);
float wholeG = Volume(ref set1, this.vmg);
float wholeB = Volume(ref set1, this.vmb);
float wholeA = Volume(ref set1, this.vma);
float wholeW = Volume(ref set1, this.vwt);
float maxr = this.Maximize(set1, 0, set1.R0 + 1, set1.R1, out int cutr, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxg = this.Maximize(set1, 1, set1.G0 + 1, set1.G1, out int cutg, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxb = this.Maximize(set1, 2, set1.B0 + 1, set1.B1, out int cutb, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxa = this.Maximize(set1, 3, set1.A0 + 1, set1.A1, out int cuta, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxr = this.Maximize(ref set1, 3, set1.R0 + 1, set1.R1, out int cutr, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxg = this.Maximize(ref set1, 2, set1.G0 + 1, set1.G1, out int cutg, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxb = this.Maximize(ref set1, 1, set1.B0 + 1, set1.B1, out int cutb, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxa = this.Maximize(ref set1, 0, set1.A0 + 1, set1.A1, out int cuta, wholeR, wholeG, wholeB, wholeA, wholeW);
int dir;
if ((maxr >= maxg) && (maxr >= maxb) && (maxr >= maxa))
{
dir = 0;
dir = 3;
if (cutr < 0)
{
@ -682,15 +686,15 @@ namespace SixLabors.ImageSharp.Quantizers
}
else if ((maxg >= maxr) && (maxg >= maxb) && (maxg >= maxa))
{
dir = 1;
dir = 2;
}
else if ((maxb >= maxr) && (maxb >= maxg) && (maxb >= maxa))
{
dir = 2;
dir = 1;
}
else
{
dir = 3;
dir = 0;
}
set2.R1 = set1.R1;
@ -701,7 +705,7 @@ namespace SixLabors.ImageSharp.Quantizers
switch (dir)
{
// Red
case 0:
case 3:
set2.R0 = set1.R1 = cutr;
set2.G0 = set1.G0;
set2.B0 = set1.B0;
@ -709,7 +713,7 @@ namespace SixLabors.ImageSharp.Quantizers
break;
// Green
case 1:
case 2:
set2.G0 = set1.G1 = cutg;
set2.R0 = set1.R0;
set2.B0 = set1.B0;
@ -717,7 +721,7 @@ namespace SixLabors.ImageSharp.Quantizers
break;
// Blue
case 2:
case 1:
set2.B0 = set1.B1 = cutb;
set2.R0 = set1.R0;
set2.G0 = set1.G0;
@ -725,7 +729,7 @@ namespace SixLabors.ImageSharp.Quantizers
break;
// Alpha
case 3:
case 0:
set2.A0 = set1.A1 = cuta;
set2.R0 = set1.R0;
set2.G0 = set1.G0;
@ -744,7 +748,7 @@ namespace SixLabors.ImageSharp.Quantizers
/// </summary>
/// <param name="cube">The cube.</param>
/// <param name="label">A label.</param>
private void Mark(Box cube, byte label)
private void Mark(ref Box cube, byte label)
{
for (int r = cube.R0 + 1; r <= cube.R1; r++)
{
@ -769,23 +773,21 @@ namespace SixLabors.ImageSharp.Quantizers
this.colorCube = new Box[this.colors];
float[] vv = new float[this.colors];
for (int i = 0; i < this.colors; i++)
{
this.colorCube[i] = new Box();
}
this.colorCube[0].R0 = this.colorCube[0].G0 = this.colorCube[0].B0 = this.colorCube[0].A0 = 0;
this.colorCube[0].R1 = this.colorCube[0].G1 = this.colorCube[0].B1 = IndexCount - 1;
this.colorCube[0].A1 = IndexAlphaCount - 1;
ref var cube = ref this.colorCube[0];
cube.R0 = cube.G0 = cube.B0 = cube.A0 = 0;
cube.R1 = cube.G1 = cube.B1 = IndexCount - 1;
cube.A1 = IndexAlphaCount - 1;
int next = 0;
for (int i = 1; i < this.colors; i++)
{
if (this.Cut(this.colorCube[next], this.colorCube[i]))
ref var nextCube = ref this.colorCube[next];
ref var currentCube = ref this.colorCube[i];
if (this.Cut(ref nextCube, ref currentCube))
{
vv[next] = this.colorCube[next].Volume > 1 ? this.Variance(this.colorCube[next]) : 0F;
vv[i] = this.colorCube[i].Volume > 1 ? this.Variance(this.colorCube[i]) : 0F;
vv[next] = nextCube.Volume > 1 ? this.Variance(ref nextCube) : 0F;
vv[i] = currentCube.Volume > 1 ? this.Variance(ref currentCube) : 0F;
}
else
{
@ -805,7 +807,7 @@ namespace SixLabors.ImageSharp.Quantizers
}
}
if (temp <= 0.0)
if (temp <= 0F)
{
this.colors = i + 1;
break;

20
tests/ImageSharp.Benchmarks/Image/DecodePng.cs

@ -10,29 +10,39 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Tests;
using CoreImage = ImageSharp.Image;
using CoreSize = SixLabors.Primitives.Size;
[Config(typeof(Config.ShortClr))]
public class DecodePng : BenchmarkBase
{
private byte[] pngBytes;
private string TestImageFullPath => Path.Combine(
TestEnvironment.InputImagesDirectoryFullPath,
this.TestImage);
[Params(TestImages.Png.Splash)]
public string TestImage { get; set; }
[GlobalSetup]
public void ReadImages()
{
if (this.pngBytes == null)
{
this.pngBytes = File.ReadAllBytes("../ImageSharp.Tests/TestImages/Formats/Png/splash.png");
this.pngBytes = File.ReadAllBytes(this.TestImageFullPath);
}
}
[Benchmark(Baseline = true, Description = "System.Drawing Png")]
public Size PngSystemDrawing()
{
using (MemoryStream memoryStream = new MemoryStream(this.pngBytes))
using (var memoryStream = new MemoryStream(this.pngBytes))
{
using (Image image = Image.FromStream(memoryStream))
using (var image = Image.FromStream(memoryStream))
{
return image.Size;
}
@ -42,9 +52,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
[Benchmark(Description = "ImageSharp Png")]
public CoreSize PngCore()
{
using (MemoryStream memoryStream = new MemoryStream(this.pngBytes))
using (var memoryStream = new MemoryStream(this.pngBytes))
{
using (Image<Rgba32> image = CoreImage.Load<Rgba32>(memoryStream))
using (var image = CoreImage.Load<Rgba32>(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}

1
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs

@ -42,6 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Baseline.Jpeg444,
TestImages.Jpeg.Baseline.Bad.BadEOF,
TestImages.Jpeg.Baseline.Bad.ExifUndefType,
TestImages.Jpeg.Issues.MultiHuffmanBaseline394,
};
public static string[] ProgressiveTestJpegs =

1
tests/ImageSharp.Tests/TestImages.cs

@ -124,6 +124,7 @@ namespace SixLabors.ImageSharp.Tests
public const string MissingFF00ProgressiveGirl159 = "Jpg/issues/Issue159-MissingFF00-Progressive-Girl.jpg";
public const string BadCoeffsProgressive178 = "Jpg/issues/Issue178-BadCoeffsProgressive-Lemon.jpg";
public const string BadZigZagProgressive385 = "Jpg/issues/Issue385-BadZigZag-Progressive.jpg";
public const string MultiHuffmanBaseline394 = "Jpg/issues/Issue394-MultiHuffmanBaseline-Speakers.jpg";
}
public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray();

2
tests/Images/External

@ -1 +1 @@
Subproject commit ab7c90362a4881c790c6f264f400dcf4b4dea0ce
Subproject commit dc5479d00b2312f691e6249b9f7765e2316d4a30

3
tests/Images/Input/Jpg/issues/Issue394-MultiHuffmanBaseline-Speakers.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8e90cf157d8e2599598c1bea1b8e2bf262651b004cc6261d87bbb49bd6131034
size 257401
Loading…
Cancel
Save