< Summary

Line coverage
96%
Covered lines: 215
Uncovered lines: 7
Coverable lines: 222
Total lines: 599
Line coverage: 96.8%
Branch coverage
93%
Covered branches: 67
Total branches: 72
Branch coverage: 93%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor()100%1100%
Quantize(...)100%1100%
Quantize(...)100%6100%
GetIndex(...)100%1100%
Volume(...)100%1100%
Bottom(...)75%492.3%
Top(...)75%492.3%
Clear()100%1100%
Build3DHistogram(...)100%2100%
Get3DMoments()100%6100%
Variance(...)100%1100%
Maximize(...)100%8100%
Cut(...)100%14100%
Mark(...)100%6100%
BuildCube(...)87.5%1695.65%
GenerateResult(...)83.33%680%

File(s)

https://raw.githubusercontent.com/JeremyAnsel/JeremyAnsel.ColorQuant/6d66b33d08452017f55aed57c4f1133aa87f71ea/JeremyAnsel.ColorQuant/JeremyAnsel.ColorQuant/WuColorQuantizer.cs

#LineLine coverage
 1// <copyright file="WuColorQuantizer.cs" company="Jérémy Ansel">
 2// Copyright (c) 2014-2019 Jérémy Ansel
 3// </copyright>
 4// <license>
 5// Licensed under the MIT license. See LICENSE.txt
 6// </license>
 7
 8namespace JeremyAnsel.ColorQuant
 9{
 10    using System;
 11    using System.Diagnostics.CodeAnalysis;
 12
 13    /// <summary>
 14    /// A Wu's color quantizer.
 15    /// </summary>
 16    /// <remarks>
 17    /// <para>
 18    /// Based on C Implementation of Xiaolin Wu's Color Quantizer (v. 2)
 19    /// (see Graphics Gems volume II, pages 126-133)
 20    /// (<see href="http://www.ece.mcmaster.ca/~xwu/cq.c"/>).
 21    /// </para>
 22    /// <para>
 23    /// Algorithm: Greedy orthogonal bipartition of RGB space for variance
 24    /// minimization aided by inclusion-exclusion tricks.
 25    /// For speed no nearest neighbor search is done. Slightly
 26    /// better performance can be expected by more sophisticated
 27    /// but more expensive versions.
 28    /// </para>
 29    /// </remarks>
 30    [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Wu", Justification = "
 31    public sealed class WuColorQuantizer : IColorQuantizer
 32    {
 33        /// <summary>
 34        /// The index bits.
 35        /// </summary>
 36        private const int IndexBits = 7;
 37
 38        /// <summary>
 39        /// The index count.
 40        /// </summary>
 41        private const int IndexCount = (1 << WuColorQuantizer.IndexBits) + 1;
 42
 43        /// <summary>
 44        /// The table length.
 45        /// </summary>
 46        private const int TableLength = WuColorQuantizer.IndexCount * WuColorQuantizer.IndexCount * WuColorQuantizer.Ind
 47
 48        /// <summary>
 49        /// Moment of <c>P(c)</c>.
 50        /// </summary>
 251        private readonly long[] vwt = new long[WuColorQuantizer.TableLength];
 52
 53        /// <summary>
 54        /// Moment of <c>r*P(c)</c>.
 55        /// </summary>
 256        private readonly long[] vmr = new long[WuColorQuantizer.TableLength];
 57
 58        /// <summary>
 59        /// Moment of <c>g*P(c)</c>.
 60        /// </summary>
 261        private readonly long[] vmg = new long[WuColorQuantizer.TableLength];
 62
 63        /// <summary>
 64        /// Moment of <c>b*P(c)</c>.
 65        /// </summary>
 266        private readonly long[] vmb = new long[WuColorQuantizer.TableLength];
 67
 68        /// <summary>
 69        /// Moment of <c>c^2*P(c)</c>.
 70        /// </summary>
 271        private readonly double[] m2 = new double[WuColorQuantizer.TableLength];
 72
 73        /// <summary>
 74        /// Color space tag.
 75        /// </summary>
 276        private readonly byte[] tag = new byte[WuColorQuantizer.TableLength];
 77
 78        /// <summary>
 79        /// Quantizes an image.
 80        /// </summary>
 81        /// <param name="image">The image (XRGB).</param>
 82        /// <returns>The result.</returns>
 83        public ColorQuantizerResult Quantize(byte[] image)
 84        {
 1485            return this.Quantize(image, 256);
 86        }
 87
 88        /// <summary>
 89        /// Quantizes an image.
 90        /// </summary>
 91        /// <param name="image">The image (XRGB).</param>
 92        /// <param name="colorCount">The color count.</param>
 93        /// <returns>The result.</returns>
 94        public ColorQuantizerResult Quantize(byte[] image, int colorCount)
 95        {
 2096            if (image == null)
 97            {
 498                throw new ArgumentNullException(nameof(image));
 99            }
 100
 16101            if (colorCount < 1 || colorCount > 256)
 102            {
 4103                throw new ArgumentOutOfRangeException(nameof(colorCount));
 104            }
 105
 12106            this.Clear();
 107
 12108            this.Build3DHistogram(image);
 12109            this.Get3DMoments();
 110
 111            Box[] cube;
 12112            this.BuildCube(out cube, ref colorCount);
 113
 12114            return this.GenerateResult(image, colorCount, cube);
 115        }
 116
 117        /// <summary>
 118        /// Gets an index.
 119        /// </summary>
 120        /// <param name="r">The red value.</param>
 121        /// <param name="g">The green value.</param>
 122        /// <param name="b">The blue value.</param>
 123        /// <returns>The index.</returns>
 124        private static int GetIndex(int r, int g, int b)
 125        {
 85106644126            return (r << (WuColorQuantizer.IndexBits * 2)) + (r << (WuColorQuantizer.IndexBits + 1)) + (g << WuColorQuan
 127        }
 128
 129        /// <summary>
 130        /// Computes sum over a box of any given statistic.
 131        /// </summary>
 132        /// <param name="cube">The cube.</param>
 133        /// <param name="moment">The moment.</param>
 134        /// <returns>The result.</returns>
 135        private static double Volume(Box cube, long[] moment)
 136        {
 28560137            return moment[WuColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B1)]
 28560138               - moment[WuColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0)]
 28560139               - moment[WuColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1)]
 28560140               + moment[WuColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0)]
 28560141               - moment[WuColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1)]
 28560142               + moment[WuColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0)]
 28560143               + moment[WuColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1)]
 28560144               - moment[WuColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0)];
 145        }
 146
 147        /// <summary>
 148        /// Computes part of Volume(cube, moment) that doesn't depend on r1, g1, or b1 (depending on direction).
 149        /// </summary>
 150        /// <param name="cube">The cube.</param>
 151        /// <param name="direction">The direction.</param>
 152        /// <param name="moment">The moment.</param>
 153        /// <returns>The result.</returns>
 154        private static long Bottom(Box cube, int direction, long[] moment)
 155        {
 156            switch (direction)
 157            {
 158                // Red
 159                case 2:
 10208160                    return -moment[WuColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1)]
 10208161                        + moment[WuColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0)]
 10208162                        + moment[WuColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1)]
 10208163                        - moment[WuColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0)];
 164
 165                // Green
 166                case 1:
 10208167                    return -moment[WuColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1)]
 10208168                        + moment[WuColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0)]
 10208169                        + moment[WuColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1)]
 10208170                        - moment[WuColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0)];
 171
 172                // Blue
 173                case 0:
 10208174                    return -moment[WuColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0)]
 10208175                        + moment[WuColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0)]
 10208176                        + moment[WuColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0)]
 10208177                        - moment[WuColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0)];
 178
 179                default:
 0180                    throw new ArgumentOutOfRangeException(nameof(direction));
 181            }
 182        }
 183
 184        /// <summary>
 185        /// Computes remainder of Volume(cube, moment), substituting position for r1, g1, or b1 (depending on direction)
 186        /// </summary>
 187        /// <param name="cube">The cube.</param>
 188        /// <param name="direction">The direction.</param>
 189        /// <param name="position">The position.</param>
 190        /// <param name="moment">The moment.</param>
 191        /// <returns>The result.</returns>
 192        private static long Top(Box cube, int direction, int position, long[] moment)
 193        {
 194            switch (direction)
 195            {
 196                // Red
 197                case 2:
 587808198                    return moment[WuColorQuantizer.GetIndex(position, cube.G1, cube.B1)]
 587808199                       - moment[WuColorQuantizer.GetIndex(position, cube.G1, cube.B0)]
 587808200                       - moment[WuColorQuantizer.GetIndex(position, cube.G0, cube.B1)]
 587808201                       + moment[WuColorQuantizer.GetIndex(position, cube.G0, cube.B0)];
 202
 203                // Green
 204                case 1:
 852000205                    return moment[WuColorQuantizer.GetIndex(cube.R1, position, cube.B1)]
 852000206                       - moment[WuColorQuantizer.GetIndex(cube.R1, position, cube.B0)]
 852000207                       - moment[WuColorQuantizer.GetIndex(cube.R0, position, cube.B1)]
 852000208                       + moment[WuColorQuantizer.GetIndex(cube.R0, position, cube.B0)];
 209
 210                // Blue
 211                case 0:
 867360212                    return moment[WuColorQuantizer.GetIndex(cube.R1, cube.G1, position)]
 867360213                       - moment[WuColorQuantizer.GetIndex(cube.R1, cube.G0, position)]
 867360214                       - moment[WuColorQuantizer.GetIndex(cube.R0, cube.G1, position)]
 867360215                       + moment[WuColorQuantizer.GetIndex(cube.R0, cube.G0, position)];
 216
 217                default:
 0218                    throw new ArgumentOutOfRangeException(nameof(direction));
 219            }
 220        }
 221
 222        /// <summary>
 223        /// Clears the tables.
 224        /// </summary>
 225        private void Clear()
 226        {
 12227            Array.Clear(this.vwt, 0, WuColorQuantizer.TableLength);
 12228            Array.Clear(this.vmr, 0, WuColorQuantizer.TableLength);
 12229            Array.Clear(this.vmg, 0, WuColorQuantizer.TableLength);
 12230            Array.Clear(this.vmb, 0, WuColorQuantizer.TableLength);
 12231            Array.Clear(this.m2, 0, WuColorQuantizer.TableLength);
 232
 12233            Array.Clear(this.tag, 0, WuColorQuantizer.TableLength);
 12234        }
 235
 236        /// <summary>
 237        /// Builds a 3-D color histogram of <c>counts, r/g/b, c^2</c>.
 238        /// </summary>
 239        /// <param name="image">The image.</param>
 240        private void Build3DHistogram(byte[] image)
 241        {
 5148242            for (int i = 0; i < image.Length; i += 4)
 243            {
 2562244                int r = image[i + 2];
 2562245                int g = image[i + 1];
 2562246                int b = image[i];
 247
 2562248                int inr = r >> (8 - WuColorQuantizer.IndexBits);
 2562249                int ing = g >> (8 - WuColorQuantizer.IndexBits);
 2562250                int inb = b >> (8 - WuColorQuantizer.IndexBits);
 251
 2562252                int ind = WuColorQuantizer.GetIndex(inr + 1, ing + 1, inb + 1);
 253
 2562254                this.vwt[ind]++;
 2562255                this.vmr[ind] += r;
 2562256                this.vmg[ind] += g;
 2562257                this.vmb[ind] += b;
 2562258                this.m2[ind] += (r * r) + (g * g) + (b * b);
 259            }
 12260        }
 261
 262        /// <summary>
 263        /// Converts the histogram into moments so that we can rapidly calculate
 264        /// the sums of the above quantities over any desired box.
 265        /// </summary>
 266        private void Get3DMoments()
 267        {
 12268            long[] area = new long[WuColorQuantizer.IndexCount];
 12269            long[] areaR = new long[WuColorQuantizer.IndexCount];
 12270            long[] areaG = new long[WuColorQuantizer.IndexCount];
 12271            long[] areaB = new long[WuColorQuantizer.IndexCount];
 12272            double[] area2 = new double[WuColorQuantizer.IndexCount];
 273
 3096274            for (int r = 1; r < WuColorQuantizer.IndexCount; r++)
 275            {
 1536276                Array.Clear(area, 0, WuColorQuantizer.IndexCount);
 1536277                Array.Clear(areaR, 0, WuColorQuantizer.IndexCount);
 1536278                Array.Clear(areaG, 0, WuColorQuantizer.IndexCount);
 1536279                Array.Clear(areaB, 0, WuColorQuantizer.IndexCount);
 1536280                Array.Clear(area2, 0, WuColorQuantizer.IndexCount);
 281
 396288282                for (int g = 1; g < WuColorQuantizer.IndexCount; g++)
 283                {
 196608284                    long line = 0;
 196608285                    long lineR = 0;
 196608286                    long lineG = 0;
 196608287                    long lineB = 0;
 196608288                    double line2 = 0;
 289
 50724864290                    for (int b = 1; b < WuColorQuantizer.IndexCount; b++)
 291                    {
 25165824292                        int ind1 = WuColorQuantizer.GetIndex(r, g, b);
 293
 25165824294                        line += this.vwt[ind1];
 25165824295                        lineR += this.vmr[ind1];
 25165824296                        lineG += this.vmg[ind1];
 25165824297                        lineB += this.vmb[ind1];
 25165824298                        line2 += this.m2[ind1];
 299
 25165824300                        area[b] += line;
 25165824301                        areaR[b] += lineR;
 25165824302                        areaG[b] += lineG;
 25165824303                        areaB[b] += lineB;
 25165824304                        area2[b] += line2;
 305
 25165824306                        int ind2 = ind1 - WuColorQuantizer.GetIndex(1, 0, 0);
 307
 25165824308                        this.vwt[ind1] = this.vwt[ind2] + area[b];
 25165824309                        this.vmr[ind1] = this.vmr[ind2] + areaR[b];
 25165824310                        this.vmg[ind1] = this.vmg[ind2] + areaG[b];
 25165824311                        this.vmb[ind1] = this.vmb[ind2] + areaB[b];
 25165824312                        this.m2[ind1] = this.m2[ind2] + area2[b];
 313                    }
 314                }
 315            }
 12316        }
 317
 318        /// <summary>
 319        /// Computes the weighted variance of a box.
 320        /// </summary>
 321        /// <param name="cube">The cube.</param>
 322        /// <returns>The result.</returns>
 323        private double Variance(Box cube)
 324        {
 3050325            double dr = WuColorQuantizer.Volume(cube, this.vmr);
 3050326            double dg = WuColorQuantizer.Volume(cube, this.vmg);
 3050327            double db = WuColorQuantizer.Volume(cube, this.vmb);
 328
 3050329            double xx = this.m2[WuColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B1)]
 3050330             - this.m2[WuColorQuantizer.GetIndex(cube.R1, cube.G1, cube.B0)]
 3050331             - this.m2[WuColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B1)]
 3050332             + this.m2[WuColorQuantizer.GetIndex(cube.R1, cube.G0, cube.B0)]
 3050333             - this.m2[WuColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B1)]
 3050334             + this.m2[WuColorQuantizer.GetIndex(cube.R0, cube.G1, cube.B0)]
 3050335             + this.m2[WuColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B1)]
 3050336             - this.m2[WuColorQuantizer.GetIndex(cube.R0, cube.G0, cube.B0)];
 337
 3050338            return xx - (((dr * dr) + (dg * dg) + (db * db)) / WuColorQuantizer.Volume(cube, this.vwt));
 339        }
 340
 341        /// <summary>
 342        /// We want to minimize the sum of the variances of two sub-boxes.
 343        /// The sum(c^2) terms can be ignored since their sum over both sub-boxes
 344        /// is the same (the sum for the whole box) no matter where we split.
 345        /// The remaining terms have a minus sign in the variance formula,
 346        /// so we drop the minus sign and maximize the sum of the two terms.
 347        /// </summary>
 348        /// <param name="cube">The cube.</param>
 349        /// <param name="direction">The direction.</param>
 350        /// <param name="first">The first position.</param>
 351        /// <param name="last">The last position.</param>
 352        /// <param name="cut">The cutting point.</param>
 353        /// <param name="wholeR">The whole red.</param>
 354        /// <param name="wholeG">The whole green.</param>
 355        /// <param name="wholeB">The whole blue.</param>
 356        /// <param name="wholeW">The whole weight.</param>
 357        /// <returns>The result.</returns>
 358        private double Maximize(Box cube, int direction, int first, int last, out int cut, double wholeR, double wholeG,
 359        {
 7656360            long baseR = WuColorQuantizer.Bottom(cube, direction, this.vmr);
 7656361            long baseG = WuColorQuantizer.Bottom(cube, direction, this.vmg);
 7656362            long baseB = WuColorQuantizer.Bottom(cube, direction, this.vmb);
 7656363            long baseW = WuColorQuantizer.Bottom(cube, direction, this.vwt);
 364
 7656365            double max = 0.0;
 7656366            cut = -1;
 367
 1168896368            for (int i = first; i < last; i++)
 369            {
 576792370                double halfR = baseR + WuColorQuantizer.Top(cube, direction, i, this.vmr);
 576792371                double halfG = baseG + WuColorQuantizer.Top(cube, direction, i, this.vmg);
 576792372                double halfB = baseB + WuColorQuantizer.Top(cube, direction, i, this.vmb);
 576792373                double halfW = baseW + WuColorQuantizer.Top(cube, direction, i, this.vwt);
 374
 576792375                if (halfW == 0)
 376                {
 377                    continue;
 378                }
 379
 485512380                double temp = ((halfR * halfR) + (halfG * halfG) + (halfB * halfB)) / halfW;
 381
 485512382                halfR = wholeR - halfR;
 485512383                halfG = wholeG - halfG;
 485512384                halfB = wholeB - halfB;
 485512385                halfW = wholeW - halfW;
 386
 485512387                if (halfW == 0)
 388                {
 389                    continue;
 390                }
 391
 32618392                temp += ((halfR * halfR) + (halfG * halfG) + (halfB * halfB)) / halfW;
 393
 32618394                if (temp > max)
 395                {
 6400396                    max = temp;
 6400397                    cut = i;
 398                }
 399            }
 400
 7656401            return max;
 402        }
 403
 404        /// <summary>
 405        /// Cuts a box.
 406        /// </summary>
 407        /// <param name="set1">The first set.</param>
 408        /// <param name="set2">The second set.</param>
 409        /// <returns>Returns a value indicating whether the box has been split.</returns>
 410        private bool Cut(Box set1, Box set2)
 411        {
 2552412            double wholeR = WuColorQuantizer.Volume(set1, this.vmr);
 2552413            double wholeG = WuColorQuantizer.Volume(set1, this.vmg);
 2552414            double wholeB = WuColorQuantizer.Volume(set1, this.vmb);
 2552415            double wholeW = WuColorQuantizer.Volume(set1, this.vwt);
 416
 417            int cutr;
 418            int cutg;
 419            int cutb;
 420
 2552421            double maxr = this.Maximize(set1, 2, set1.R0 + 1, set1.R1, out cutr, wholeR, wholeG, wholeB, wholeW);
 2552422            double maxg = this.Maximize(set1, 1, set1.G0 + 1, set1.G1, out cutg, wholeR, wholeG, wholeB, wholeW);
 2552423            double maxb = this.Maximize(set1, 0, set1.B0 + 1, set1.B1, out cutb, wholeR, wholeG, wholeB, wholeW);
 424
 425            int dir;
 426
 2552427            if ((maxr >= maxg) && (maxr >= maxb))
 428            {
 1698429                dir = 2;
 430
 1698431                if (cutr < 0)
 432                {
 1026433                    return false;
 434                }
 435            }
 854436            else if ((maxg >= maxr) && (maxg >= maxb))
 437            {
 272438                dir = 1;
 439            }
 440            else
 441            {
 582442                dir = 0;
 443            }
 444
 1526445            set2.R1 = set1.R1;
 1526446            set2.G1 = set1.G1;
 1526447            set2.B1 = set1.B1;
 448
 449            switch (dir)
 450            {
 451                // Red
 452                case 2:
 672453                    set2.R0 = set1.R1 = cutr;
 672454                    set2.G0 = set1.G0;
 672455                    set2.B0 = set1.B0;
 672456                    break;
 457
 458                // Green
 459                case 1:
 272460                    set2.G0 = set1.G1 = cutg;
 272461                    set2.R0 = set1.R0;
 272462                    set2.B0 = set1.B0;
 272463                    break;
 464
 465                // Blue
 466                case 0:
 582467                    set2.B0 = set1.B1 = cutb;
 582468                    set2.R0 = set1.R0;
 582469                    set2.G0 = set1.G0;
 470                    break;
 471            }
 472
 1526473            set1.Volume = (set1.R1 - set1.R0) * (set1.G1 - set1.G0) * (set1.B1 - set1.B0);
 1526474            set2.Volume = (set2.R1 - set2.R0) * (set2.G1 - set2.G0) * (set2.B1 - set2.B0);
 475
 1526476            return true;
 477        }
 478
 479        /// <summary>
 480        /// Marks a color space tag.
 481        /// </summary>
 482        /// <param name="cube">The cube.</param>
 483        /// <param name="label">A label.</param>
 484        private void Mark(Box cube, byte label)
 485        {
 152068486            for (int r = cube.R0 + 1; r <= cube.R1; r++)
 487            {
 9324032488                for (int g = cube.G0 + 1; g <= cube.G1; g++)
 489                {
 59506688490                    for (int b = cube.B0 + 1; b <= cube.B1; b++)
 491                    {
 25165824492                        this.tag[WuColorQuantizer.GetIndex(r, g, b)] = label;
 493                    }
 494                }
 495            }
 1538496        }
 497
 498        /// <summary>
 499        /// Builds the cube.
 500        /// </summary>
 501        /// <param name="cube">The cube.</param>
 502        /// <param name="colorCount">The color count.</param>
 503        private void BuildCube(out Box[] cube, ref int colorCount)
 504        {
 12505            cube = new Box[colorCount];
 12506            double[] vv = new double[colorCount];
 507
 6168508            for (int i = 0; i < colorCount; i++)
 509            {
 3072510                cube[i] = new Box();
 511            }
 512
 12513            cube[0].R0 = cube[0].G0 = cube[0].B0 = 0;
 12514            cube[0].R1 = cube[0].G1 = cube[0].B1 = WuColorQuantizer.IndexCount - 1;
 515
 12516            int next = 0;
 517
 5104518            for (int i = 1; i < colorCount; i++)
 519            {
 2552520                if (this.Cut(cube[next], cube[i]))
 521                {
 1526522                    vv[next] = cube[next].Volume > 1 ? this.Variance(cube[next]) : 0.0;
 1526523                    vv[i] = cube[i].Volume > 1 ? this.Variance(cube[i]) : 0.0;
 524                }
 525                else
 526                {
 1026527                    vv[next] = 0.0;
 1026528                    i--;
 529                }
 530
 2552531                next = 0;
 532
 2552533                double temp = vv[0];
 525808534                for (int k = 1; k <= i; k++)
 535                {
 260352536                    if (vv[k] > temp)
 537                    {
 2470538                        temp = vv[k];
 2470539                        next = k;
 540                    }
 541                }
 542
 2552543                if (temp <= 0.0)
 544                {
 12545                    colorCount = i + 1;
 12546                    break;
 547                }
 548            }
 0549        }
 550
 551        /// <summary>
 552        /// Generates the quantized result.
 553        /// </summary>
 554        /// <param name="image">The image.</param>
 555        /// <param name="colorCount">The color count.</param>
 556        /// <param name="cube">The cube.</param>
 557        /// <returns>The result.</returns>
 558        private ColorQuantizerResult GenerateResult(byte[] image, int colorCount, Box[] cube)
 559        {
 12560            var quantizedImage = new ColorQuantizerResult(image.Length / 4, colorCount);
 561
 3100562            for (int k = 0; k < colorCount; k++)
 563            {
 1538564                this.Mark(cube[k], (byte)k);
 565
 1538566                double weight = WuColorQuantizer.Volume(cube[k], this.vwt);
 567
 1538568                if (weight != 0)
 569                {
 1538570                    quantizedImage.Palette[(k * 4) + 3] = 0xff;
 1538571                    quantizedImage.Palette[(k * 4) + 2] = (byte)(WuColorQuantizer.Volume(cube[k], this.vmr) / weight);
 1538572                    quantizedImage.Palette[(k * 4) + 1] = (byte)(WuColorQuantizer.Volume(cube[k], this.vmg) / weight);
 1538573                    quantizedImage.Palette[k * 4] = (byte)(WuColorQuantizer.Volume(cube[k], this.vmb) / weight);
 574                }
 575                else
 576                {
 0577                    quantizedImage.Palette[(k * 4) + 3] = 0xff;
 0578                    quantizedImage.Palette[(k * 4) + 2] = 0;
 0579                    quantizedImage.Palette[(k * 4) + 1] = 0;
 0580                    quantizedImage.Palette[k * 4] = 0;
 581                }
 582            }
 583
 5148584            for (int i = 0; i < image.Length / 4; i++)
 585            {
 2562586                int r = image[(i * 4) + 2] >> (8 - WuColorQuantizer.IndexBits);
 2562587                int g = image[(i * 4) + 1] >> (8 - WuColorQuantizer.IndexBits);
 2562588                int b = image[i * 4] >> (8 - WuColorQuantizer.IndexBits);
 589
 2562590                int ind = WuColorQuantizer.GetIndex(r + 1, g + 1, b + 1);
 591
 2562592                quantizedImage.Bytes[i] = this.tag[ind];
 593            }
 594
 12595            return quantizedImage;
 596        }
 597    }
 598}
 599