/// <summary> /// Generates the quantized result. /// </summary> /// <param name="image">The image.</param> /// <param name="colorCount">The color count.</param> /// <param name="width">Width of image</param> /// <param name="height">Height of image</param> /// <param name="destPixels">Pixel values are written here. Must provide width*height memory.</param> /// <param name="padMultiple4">True to write zero padding to make row bytes multiple of 4</param> /// <returns>Receives colors</returns> private unsafe uint[] GenerateResult(uint *image, int colorCount, int width, int height, byte *destPixels, bool padMultiple4) { uint[] palette = new uint[colorCount]; // rows must be a multiple of 4, hence padding up to 3 bytes for 8-bit indexed pixels int widthMod4 = width % 4; int widthZeros = widthMod4 != 0 ? 4 - widthMod4 : 0; for (int k = 0; k < colorCount; k++) { this.Mark(ref this.cube[k], (byte)k); float weight = WuQuant.Volume(ref this.cube[k], this.vwt); if (weight != 0) { uint a = (byte)(WuQuant.Volume(ref this.cube[k], this.vma) / weight); uint r = (byte)(WuQuant.Volume(ref this.cube[k], this.vmr) / weight); uint g = (byte)(WuQuant.Volume(ref this.cube[k], this.vmg) / weight); uint b = (byte)(WuQuant.Volume(ref this.cube[k], this.vmb) / weight); palette[k] = (a << 24) | (r << 16) | (g << 8) | b; } else { palette[k] = 0xFF000000; } } for (int ri = 0; ri < height; ri++) { for (int ci = 0; ci < width; ci++) { uint pix = image[0]; uint a = ((pix & 0xFF000000) >> 24) >> (8 - WuQuant.INDEXALPHABITS); uint r = ((pix & 0x00FF0000) >> 16) >> (8 - WuQuant.INDEXBITS); uint g = ((pix & 0x0000FF00) >> 8) >> (8 - WuQuant.INDEXBITS); uint b = (pix & 0x000000FF) >> (8 - WuQuant.INDEXBITS); int ind = WuQuant.GetIndex((int)r + 1, (int)g + 1, (int)b + 1, (int)a + 1); destPixels[0] = this.tag[ind]; destPixels++; image++; } // write additional zero bytes if requested if (padMultiple4) { for (int c = 0; c < widthZeros; c++) { destPixels[0] = 0x00; destPixels++; } } } return(palette); }
/// <summary> /// Computes the weighted variance of a box. /// </summary> /// <param name="c">The cube.</param> /// <returns>The result.</returns> private float Variance(ref Data.Box c) { float dr = WuQuant.Volume(ref c, this.vmr); float dg = WuQuant.Volume(ref c, this.vmg); float db = WuQuant.Volume(ref c, this.vmb); float da = WuQuant.Volume(ref c, this.vma); float xx = this.m2[WuQuant.GetIndex(c.R1, c.G1, c.B1, c.A1)] - this.m2[WuQuant.GetIndex(c.R1, c.G1, c.B1, c.A0)] - this.m2[WuQuant.GetIndex(c.R1, c.G1, c.B0, c.A1)] + this.m2[WuQuant.GetIndex(c.R1, c.G1, c.B0, c.A0)] - this.m2[WuQuant.GetIndex(c.R1, c.G0, c.B1, c.A1)] + this.m2[WuQuant.GetIndex(c.R1, c.G0, c.B1, c.A0)] + this.m2[WuQuant.GetIndex(c.R1, c.G0, c.B0, c.A1)] - this.m2[WuQuant.GetIndex(c.R1, c.G0, c.B0, c.A0)] - this.m2[WuQuant.GetIndex(c.R0, c.G1, c.B1, c.A1)] + this.m2[WuQuant.GetIndex(c.R0, c.G1, c.B1, c.A0)] + this.m2[WuQuant.GetIndex(c.R0, c.G1, c.B0, c.A1)] - this.m2[WuQuant.GetIndex(c.R0, c.G1, c.B0, c.A0)] + this.m2[WuQuant.GetIndex(c.R0, c.G0, c.B1, c.A1)] - this.m2[WuQuant.GetIndex(c.R0, c.G0, c.B1, c.A0)] - this.m2[WuQuant.GetIndex(c.R0, c.G0, c.B0, c.A1)] + this.m2[WuQuant.GetIndex(c.R0, c.G0, c.B0, c.A0)]; return(xx - (((dr * dr) + (dg * dg) + (db * db) + (da * da)) / WuQuant.Volume(ref c, this.vwt))); }
/// <summary> /// Cuts a box. /// </summary> /// <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(ref Data.Box set1, ref Data.Box set2) { float wholeR = WuQuant.Volume(ref set1, this.vmr); float wholeG = WuQuant.Volume(ref set1, this.vmg); float wholeB = WuQuant.Volume(ref set1, this.vmb); float wholeA = WuQuant.Volume(ref set1, this.vma); float wholeW = WuQuant.Volume(ref set1, this.vwt); int cutr; int cutg; int cutb; int cuta; float maxr = this.Maximize(ref set1, 3, set1.R0 + 1, set1.R1, out cutr, wholeR, wholeG, wholeB, wholeA, wholeW); float maxg = this.Maximize(ref set1, 2, set1.G0 + 1, set1.G1, out cutg, wholeR, wholeG, wholeB, wholeA, wholeW); float maxb = this.Maximize(ref set1, 1, set1.B0 + 1, set1.B1, out cutb, wholeR, wholeG, wholeB, wholeA, wholeW); float maxa = this.Maximize(ref set1, 0, set1.A0 + 1, set1.A1, out cuta, wholeR, wholeG, wholeB, wholeA, wholeW); int dir; if ((maxr >= maxg) && (maxr >= maxb) && (maxr >= maxa)) { dir = 3; if (cutr < 0) { return(false); } } else if ((maxg >= maxr) && (maxg >= maxb) && (maxg >= maxa)) { dir = 2; } else if ((maxb >= maxr) && (maxb >= maxg) && (maxb >= maxa)) { dir = 1; } else { dir = 0; } set2.R1 = set1.R1; set2.G1 = set1.G1; set2.B1 = set1.B1; set2.A1 = set1.A1; switch (dir) { // Red case 3: set2.R0 = set1.R1 = cutr; set2.G0 = set1.G0; set2.B0 = set1.B0; set2.A0 = set1.A0; break; // Green case 2: set2.G0 = set1.G1 = cutg; set2.R0 = set1.R0; set2.B0 = set1.B0; set2.A0 = set1.A0; break; // Blue case 1: set2.B0 = set1.B1 = cutb; set2.R0 = set1.R0; set2.G0 = set1.G0; set2.A0 = set1.A0; break; // Alpha case 0: set2.A0 = set1.A1 = cuta; set2.R0 = set1.R0; set2.G0 = set1.G0; set2.B0 = set1.B0; break; } set1.Volume = (set1.R1 - set1.R0) * (set1.G1 - set1.G0) * (set1.B1 - set1.B0) * (set1.A1 - set1.A0); set2.Volume = (set2.R1 - set2.R0) * (set2.G1 - set2.G0) * (set2.B1 - set2.B0) * (set2.A1 - set2.A0); return(true); }