diff --git a/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs b/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs
index 6eef9633c4..47e41e84aa 100644
--- a/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs
+++ b/src/ImageSharp/Quantizers/Wu/WuQuantizer.cs
@@ -65,6 +65,21 @@ namespace ImageSharp.Quantizers
///
private const int TableLength = IndexCount * IndexCount * IndexCount * IndexAlphaCount;
+ ///
+ /// The long array pool.
+ ///
+ private static readonly ArrayPool LongPool = ArrayPool.Create(TableLength, 25);
+
+ ///
+ /// The double array pool.
+ ///
+ private static readonly ArrayPool DoublePool = ArrayPool.Create(TableLength, 5);
+
+ ///
+ /// The byte array pool.
+ ///
+ private static readonly ArrayPool BytePool = ArrayPool.Create(TableLength, 5);
+
///
/// Moment of P(c).
///
@@ -100,18 +115,24 @@ namespace ImageSharp.Quantizers
///
private readonly byte[] tag;
+ ///
+ /// A buffer for storing pixels
+ ///
+ private readonly byte[] rgbaBuffer = new byte[4];
+
///
/// Initializes a new instance of the class.
///
public WuQuantizer()
{
- this.vwt = new long[TableLength];
- this.vmr = new long[TableLength];
- this.vmg = new long[TableLength];
- this.vmb = new long[TableLength];
- this.vma = new long[TableLength];
- this.m2 = new double[TableLength];
- this.tag = new byte[TableLength];
+ // TODO: We might have to use a custom pool here. The default doesn't appear to save memory
+ this.vwt = LongPool.Rent(TableLength);
+ this.vmr = LongPool.Rent(TableLength);
+ this.vmg = LongPool.Rent(TableLength);
+ this.vmb = LongPool.Rent(TableLength);
+ this.vma = LongPool.Rent(TableLength);
+ this.m2 = DoublePool.Rent(TableLength);
+ this.tag = BytePool.Rent(TableLength);
}
///
@@ -145,14 +166,9 @@ namespace ImageSharp.Quantizers
/// The index.
private static int GetPaletteIndex(int r, int g, int b, int a)
{
- return (r << ((IndexBits * 2) + IndexAlphaBits))
- + (r << (IndexBits + IndexAlphaBits + 1))
- + (g << (IndexBits + IndexAlphaBits))
- + (r << (IndexBits * 2))
- + (r << (IndexBits + 1))
- + (g << IndexBits)
- + ((r + g + b) << IndexAlphaBits)
- + r + g + b + a;
+ return (r << ((IndexBits * 2) + IndexAlphaBits)) + (r << (IndexBits + IndexAlphaBits + 1))
+ + (g << (IndexBits + IndexAlphaBits)) + (r << (IndexBits * 2)) + (r << (IndexBits + 1))
+ + (g << IndexBits) + ((r + g + b) << IndexAlphaBits) + r + g + b + a;
}
///
@@ -164,21 +180,21 @@ namespace ImageSharp.Quantizers
private static double Volume(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)]
- - 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.B1, cube.A1)]
- + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)]
- + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)]
- - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
- - 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)]
- - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
- + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)]
- - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
- - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
- + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
+ - moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A0)]
+ - 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.B1, cube.A1)]
+ + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)]
+ + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)]
+ - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
+ - 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)]
+ - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
+ + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)]
+ - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
+ - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
+ + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
}
///
@@ -195,46 +211,46 @@ namespace ImageSharp.Quantizers
// Red
case 0:
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)]
- - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
- + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)]
- - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
- - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
- + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
+ + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)]
+ + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)]
+ - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
+ + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)]
+ - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
+ - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
+ + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
// Green
case 1:
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)]
- - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
- + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)]
- - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
- - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
- + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
+ + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)]
+ + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)]
+ - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
+ + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)]
+ - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
+ - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
+ + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
// Blue
case 2:
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)]
- - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
- + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)]
- - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
- - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
- + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
+ + moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)]
+ + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)]
+ - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
+ + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)]
+ - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
+ - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
+ + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
// Alpha
case 3:
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)]
- - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
- + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)]
- - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
- - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
- + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
+ + moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)]
+ + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)]
+ - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)]
+ + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)]
+ - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)]
+ - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)]
+ + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
default:
throw new ArgumentOutOfRangeException(nameof(direction));
@@ -256,46 +272,46 @@ namespace ImageSharp.Quantizers
// Red
case 0:
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)]
- + moment[GetPaletteIndex(position, cube.G1, cube.B0, cube.A0)]
- - moment[GetPaletteIndex(position, cube.G0, cube.B1, cube.A1)]
- + moment[GetPaletteIndex(position, cube.G0, cube.B1, cube.A0)]
- + moment[GetPaletteIndex(position, cube.G0, cube.B0, cube.A1)]
- - moment[GetPaletteIndex(position, cube.G0, cube.B0, cube.A0)];
+ - moment[GetPaletteIndex(position, cube.G1, cube.B1, cube.A0)]
+ - moment[GetPaletteIndex(position, cube.G1, cube.B0, cube.A1)]
+ + moment[GetPaletteIndex(position, cube.G1, cube.B0, cube.A0)]
+ - moment[GetPaletteIndex(position, cube.G0, cube.B1, cube.A1)]
+ + moment[GetPaletteIndex(position, cube.G0, cube.B1, cube.A0)]
+ + moment[GetPaletteIndex(position, cube.G0, cube.B0, cube.A1)]
+ - moment[GetPaletteIndex(position, cube.G0, cube.B0, cube.A0)];
// Green
case 1:
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)]
- + moment[GetPaletteIndex(cube.R1, position, cube.B0, cube.A0)]
- - moment[GetPaletteIndex(cube.R0, position, cube.B1, cube.A1)]
- + moment[GetPaletteIndex(cube.R0, position, cube.B1, cube.A0)]
- + moment[GetPaletteIndex(cube.R0, position, cube.B0, cube.A1)]
- - moment[GetPaletteIndex(cube.R0, position, cube.B0, cube.A0)];
+ - moment[GetPaletteIndex(cube.R1, position, cube.B1, cube.A0)]
+ - moment[GetPaletteIndex(cube.R1, position, cube.B0, cube.A1)]
+ + moment[GetPaletteIndex(cube.R1, position, cube.B0, cube.A0)]
+ - moment[GetPaletteIndex(cube.R0, position, cube.B1, cube.A1)]
+ + moment[GetPaletteIndex(cube.R0, position, cube.B1, cube.A0)]
+ + moment[GetPaletteIndex(cube.R0, position, cube.B0, cube.A1)]
+ - moment[GetPaletteIndex(cube.R0, position, cube.B0, cube.A0)];
// Blue
case 2:
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)]
- + moment[GetPaletteIndex(cube.R1, cube.G0, position, cube.A0)]
- - moment[GetPaletteIndex(cube.R0, cube.G1, position, cube.A1)]
- + moment[GetPaletteIndex(cube.R0, cube.G1, position, cube.A0)]
- + moment[GetPaletteIndex(cube.R0, cube.G0, position, cube.A1)]
- - moment[GetPaletteIndex(cube.R0, cube.G0, position, cube.A0)];
+ - moment[GetPaletteIndex(cube.R1, cube.G1, position, cube.A0)]
+ - moment[GetPaletteIndex(cube.R1, cube.G0, position, cube.A1)]
+ + moment[GetPaletteIndex(cube.R1, cube.G0, position, cube.A0)]
+ - moment[GetPaletteIndex(cube.R0, cube.G1, position, cube.A1)]
+ + moment[GetPaletteIndex(cube.R0, cube.G1, position, cube.A0)]
+ + moment[GetPaletteIndex(cube.R0, cube.G0, position, cube.A1)]
+ - moment[GetPaletteIndex(cube.R0, cube.G0, position, cube.A0)];
// Alpha
case 3:
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)]
- + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, position)]
- - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, position)]
- + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, position)]
- + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, position)]
- - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, position)];
+ - moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, position)]
+ - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, position)]
+ + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, position)]
+ - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, position)]
+ + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, position)]
+ + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, position)]
+ - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, position)];
default:
throw new ArgumentOutOfRangeException(nameof(direction));
@@ -313,7 +329,6 @@ namespace ImageSharp.Quantizers
Array.Clear(this.vmb, 0, TableLength);
Array.Clear(this.vma, 0, TableLength);
Array.Clear(this.m2, 0, TableLength);
-
Array.Clear(this.tag, 0, TableLength);
}
@@ -323,18 +338,17 @@ namespace ImageSharp.Quantizers
/// The pixel accessor.
private void Build3DHistogram(PixelAccessor pixels)
{
- byte[] rgba = new byte[4];
for (int y = 0; y < pixels.Height; y++)
{
for (int x = 0; x < pixels.Width; x++)
{
// Colors are expected in r->g->b->a format
- pixels[x, y].ToBytes(rgba, 0, ComponentOrder.XYZW);
+ pixels[x, y].ToBytes(this.rgbaBuffer, 0, ComponentOrder.XYZW);
- byte r = rgba[0];
- byte g = rgba[1];
- byte b = rgba[2];
- byte a = rgba[3];
+ byte r = this.rgbaBuffer[0];
+ byte g = this.rgbaBuffer[1];
+ byte b = this.rgbaBuffer[2];
+ byte a = this.rgbaBuffer[3];
int inr = r >> (8 - IndexBits);
int ing = g >> (8 - IndexBits);
@@ -354,91 +368,109 @@ namespace ImageSharp.Quantizers
}
///
- /// Converts the histogram into moments so that we can rapidly calculate
- /// the sums of the above quantities over any desired box.
+ /// Converts the histogram into moments so that we can rapidly calculate the sums of the above quantities over any desired box.
///
private void Get3DMoments()
{
- long[] volume = new long[IndexCount * IndexAlphaCount];
- long[] volumeR = new long[IndexCount * IndexAlphaCount];
- long[] volumeG = new long[IndexCount * IndexAlphaCount];
- long[] volumeB = new long[IndexCount * IndexAlphaCount];
- long[] volumeA = new long[IndexCount * IndexAlphaCount];
- double[] volume2 = new double[IndexCount * IndexAlphaCount];
-
- long[] area = new long[IndexAlphaCount];
- long[] areaR = new long[IndexAlphaCount];
- long[] areaG = new long[IndexAlphaCount];
- long[] areaB = new long[IndexAlphaCount];
- long[] areaA = new long[IndexAlphaCount];
- double[] area2 = new double[IndexAlphaCount];
-
- for (int r = 1; r < IndexCount; r++)
+ long[] volume = ArrayPool.Shared.Rent(IndexCount * IndexAlphaCount);
+ long[] volumeR = ArrayPool.Shared.Rent(IndexCount * IndexAlphaCount);
+ long[] volumeG = ArrayPool.Shared.Rent(IndexCount * IndexAlphaCount);
+ long[] volumeB = ArrayPool.Shared.Rent(IndexCount * IndexAlphaCount);
+ long[] volumeA = ArrayPool.Shared.Rent(IndexCount * IndexAlphaCount);
+ double[] volume2 = ArrayPool.Shared.Rent(IndexCount * IndexAlphaCount);
+
+ long[] area = ArrayPool.Shared.Rent(IndexAlphaCount);
+ long[] areaR = ArrayPool.Shared.Rent(IndexAlphaCount);
+ long[] areaG = ArrayPool.Shared.Rent(IndexAlphaCount);
+ long[] areaB = ArrayPool.Shared.Rent(IndexAlphaCount);
+ long[] areaA = ArrayPool.Shared.Rent(IndexAlphaCount);
+ double[] area2 = ArrayPool.Shared.Rent(IndexAlphaCount);
+
+ try
{
- Array.Clear(volume, 0, IndexCount * IndexAlphaCount);
- Array.Clear(volumeR, 0, IndexCount * IndexAlphaCount);
- Array.Clear(volumeG, 0, IndexCount * IndexAlphaCount);
- Array.Clear(volumeB, 0, IndexCount * IndexAlphaCount);
- Array.Clear(volumeA, 0, IndexCount * IndexAlphaCount);
- Array.Clear(volume2, 0, IndexCount * IndexAlphaCount);
-
- for (int g = 1; g < IndexCount; g++)
+ for (int r = 1; r < IndexCount; r++)
{
- Array.Clear(area, 0, IndexAlphaCount);
- Array.Clear(areaR, 0, IndexAlphaCount);
- Array.Clear(areaG, 0, IndexAlphaCount);
- Array.Clear(areaB, 0, IndexAlphaCount);
- Array.Clear(areaA, 0, IndexAlphaCount);
- Array.Clear(area2, 0, IndexAlphaCount);
-
- for (int b = 1; b < IndexCount; b++)
+ Array.Clear(volume, 0, IndexCount * IndexAlphaCount);
+ Array.Clear(volumeR, 0, IndexCount * IndexAlphaCount);
+ Array.Clear(volumeG, 0, IndexCount * IndexAlphaCount);
+ Array.Clear(volumeB, 0, IndexCount * IndexAlphaCount);
+ Array.Clear(volumeA, 0, IndexCount * IndexAlphaCount);
+ Array.Clear(volume2, 0, IndexCount * IndexAlphaCount);
+
+ for (int g = 1; g < IndexCount; g++)
{
- long line = 0;
- long lineR = 0;
- long lineG = 0;
- long lineB = 0;
- long lineA = 0;
- double line2 = 0;
-
- for (int a = 1; a < IndexAlphaCount; a++)
+ Array.Clear(area, 0, IndexAlphaCount);
+ Array.Clear(areaR, 0, IndexAlphaCount);
+ Array.Clear(areaG, 0, IndexAlphaCount);
+ Array.Clear(areaB, 0, IndexAlphaCount);
+ Array.Clear(areaA, 0, IndexAlphaCount);
+ Array.Clear(area2, 0, IndexAlphaCount);
+
+ for (int b = 1; b < IndexCount; b++)
{
- int ind1 = GetPaletteIndex(r, g, b, a);
-
- line += this.vwt[ind1];
- lineR += this.vmr[ind1];
- lineG += this.vmg[ind1];
- lineB += this.vmb[ind1];
- lineA += this.vma[ind1];
- line2 += this.m2[ind1];
-
- area[a] += line;
- areaR[a] += lineR;
- areaG[a] += lineG;
- areaB[a] += lineB;
- areaA[a] += lineA;
- area2[a] += line2;
-
- int inv = (b * IndexAlphaCount) + a;
-
- volume[inv] += area[a];
- volumeR[inv] += areaR[a];
- volumeG[inv] += areaG[a];
- volumeB[inv] += areaB[a];
- volumeA[inv] += areaA[a];
- volume2[inv] += area2[a];
-
- int ind2 = ind1 - GetPaletteIndex(1, 0, 0, 0);
-
- this.vwt[ind1] = this.vwt[ind2] + volume[inv];
- this.vmr[ind1] = this.vmr[ind2] + volumeR[inv];
- this.vmg[ind1] = this.vmg[ind2] + volumeG[inv];
- this.vmb[ind1] = this.vmb[ind2] + volumeB[inv];
- this.vma[ind1] = this.vma[ind2] + volumeA[inv];
- this.m2[ind1] = this.m2[ind2] + volume2[inv];
+ long line = 0;
+ long lineR = 0;
+ long lineG = 0;
+ long lineB = 0;
+ long lineA = 0;
+ double line2 = 0;
+
+ for (int a = 1; a < IndexAlphaCount; a++)
+ {
+ int ind1 = GetPaletteIndex(r, g, b, a);
+
+ line += this.vwt[ind1];
+ lineR += this.vmr[ind1];
+ lineG += this.vmg[ind1];
+ lineB += this.vmb[ind1];
+ lineA += this.vma[ind1];
+ line2 += this.m2[ind1];
+
+ area[a] += line;
+ areaR[a] += lineR;
+ areaG[a] += lineG;
+ areaB[a] += lineB;
+ areaA[a] += lineA;
+ area2[a] += line2;
+
+ int inv = (b * IndexAlphaCount) + a;
+
+ volume[inv] += area[a];
+ volumeR[inv] += areaR[a];
+ volumeG[inv] += areaG[a];
+ volumeB[inv] += areaB[a];
+ volumeA[inv] += areaA[a];
+ volume2[inv] += area2[a];
+
+ int ind2 = ind1 - GetPaletteIndex(1, 0, 0, 0);
+
+ this.vwt[ind1] = this.vwt[ind2] + volume[inv];
+ this.vmr[ind1] = this.vmr[ind2] + volumeR[inv];
+ this.vmg[ind1] = this.vmg[ind2] + volumeG[inv];
+ this.vmb[ind1] = this.vmb[ind2] + volumeB[inv];
+ this.vma[ind1] = this.vma[ind2] + volumeA[inv];
+ this.m2[ind1] = this.m2[ind2] + volume2[inv];
+ }
}
}
}
}
+ finally
+ {
+ ArrayPool.Shared.Return(volume);
+ ArrayPool.Shared.Return(volumeR);
+ ArrayPool.Shared.Return(volumeG);
+ ArrayPool.Shared.Return(volumeB);
+ ArrayPool.Shared.Return(volumeA);
+ ArrayPool.Shared.Return(volume2);
+
+ ArrayPool.Shared.Return(area);
+ ArrayPool.Shared.Return(areaR);
+ ArrayPool.Shared.Return(areaG);
+ ArrayPool.Shared.Return(areaB);
+ ArrayPool.Shared.Return(areaA);
+ ArrayPool.Shared.Return(area2);
+ }
}
///
@@ -770,6 +802,15 @@ namespace ImageSharp.Quantizers
ArrayPool.Shared.Return(rgba);
});
+ // Cleanup
+ LongPool.Return(this.vwt);
+ LongPool.Return(this.vmr);
+ LongPool.Return(this.vmg);
+ LongPool.Return(this.vmb);
+ LongPool.Return(this.vma);
+ DoublePool.Return(this.m2);
+ BytePool.Return(this.tag);
+
return new QuantizedImage(width, height, pallette, pixels);
}
}