private static TextureByteIndexPalette ReduceColorPalette(string name, Bitmap bitmap, List <Color> allColors, ColorPaletteAlgorithm algorithm, int targetColors)
        {
            if (targetColors > 256)
            {
                throw new ArgumentOutOfRangeException(nameof(targetColors));// Indices over byte.MaxValue are not supported
            }
            byte[] indices = new byte[bitmap.Width * bitmap.Height];

            switch (algorithm)
            {
            case ColorPaletteAlgorithm.MostUsedColorsRGB:
            {
                int[] colorUsage = new int[allColors.Count];

                // Calculate usage
                for (int y = 0; y < bitmap.Height; y++)
                {
                    for (int x = 0; x < bitmap.Width; x++)
                    {
                        colorUsage[allColors.IndexOf(bitmap.GetPixel(x, y))]++;
                    }
                }

                var byUsage = allColors.OrderByDescending((col) =>
                    {
                        int index = allColors.IndexOf(col);
                        return(colorUsage[index]);    // How many times was the color used
                    }).ToArray();
                Array.Resize(ref byUsage, targetColors);

                // Get nearest pixel by RGB
                for (int y = 0; y < bitmap.Height; y++)
                {
                    for (int x = 0; x < bitmap.Width; x++)
                    {
                        indices[x + y * bitmap.Width] = (byte)NearestColorRGB(byUsage, bitmap.GetPixel(x, y));
                    }
                }

                return(new TextureByteIndexPalette(name, bitmap.Width, bitmap.Height, indices, byUsage));
            }

            case ColorPaletteAlgorithm.MostUsedColorsHSB:
            {
                int[] colorUsage = new int[allColors.Count];

                // Calculate usage
                for (int y = 0; y < bitmap.Height; y++)
                {
                    for (int x = 0; x < bitmap.Width; x++)
                    {
                        colorUsage[allColors.IndexOf(bitmap.GetPixel(x, y))]++;
                    }
                }

                var byUsage = allColors.OrderByDescending((col) =>
                    {
                        int index = allColors.IndexOf(col);
                        return(colorUsage[index]);    // How many times was the color used
                    }).ToArray();
                Array.Resize(ref byUsage, targetColors);

                // Get nearest pixel by HSB
                for (int y = 0; y < bitmap.Height; y++)
                {
                    for (int x = 0; x < bitmap.Width; x++)
                    {
                        indices[x + y * bitmap.Width] = (byte)NearestColorHSB(byUsage, bitmap.GetPixel(x, y));
                    }
                }

                return(new TextureByteIndexPalette(name, bitmap.Width, bitmap.Height, indices, byUsage));
            }

            case ColorPaletteAlgorithm.BasicPaletteNearestRGB:
            {
                if (targetColors != 256)
                {
                    throw new ArgumentOutOfRangeException(nameof(targetColors));
                }

                var palette = BasicPalette;

                // Get nearest pixel by RGB
                for (int y = 0; y < bitmap.Height; y++)
                {
                    for (int x = 0; x < bitmap.Width; x++)
                    {
                        indices[x + y * bitmap.Width] = (byte)NearestColorRGB(palette, bitmap.GetPixel(x, y));
                    }
                }

                return(new TextureByteIndexPalette(name, bitmap.Width, bitmap.Height, indices, palette));
            }

            case ColorPaletteAlgorithm.BasicPaletteNearestHSB:
            {
                if (targetColors != 256)
                {
                    throw new ArgumentOutOfRangeException(nameof(targetColors));
                }

                var palette = BasicPalette;

                // Get nearest pixel by HSB
                for (int y = 0; y < bitmap.Height; y++)
                {
                    for (int x = 0; x < bitmap.Width; x++)
                    {
                        indices[x + y * bitmap.Width] = (byte)NearestColorHSB(palette, bitmap.GetPixel(x, y));
                    }
                }

                return(new TextureByteIndexPalette(name, bitmap.Width, bitmap.Height, indices, palette));
            }
            }
            throw new NotSupportedException();
        }
        public static TextureByteIndexPalette CreateFromBitmap(string name, Bitmap bitmap, ColorPaletteAlgorithm algorithm = ColorPaletteAlgorithm.BasicPaletteNearestHSB)
        {
            var indices = new byte[bitmap.Width * bitmap.Height];
            var colors  = new List <Color>();

            // Add all colors into the palette (to count them)
            for (int y = 0; y < bitmap.Height; y++)
            {
                for (int x = 0; x < bitmap.Width; x++)
                {
                    var c = bitmap.GetPixel(x, y);
                    if (!colors.Contains(c))
                    {
                        colors.Add(c);
                    }
                }
            }

            if (colors.Count <= 256)
            {
                for (int y = 0; y < bitmap.Height; y++)
                {
                    for (int x = 0; x < bitmap.Width; x++)
                    {
                        Color c     = bitmap.GetPixel(x, y);
                        int   index = colors.IndexOf(c);
                        indices[x + y * bitmap.Width] = (byte)index;
                    }
                }

                return(new TextureByteIndexPalette(name, bitmap.Width, bitmap.Height, indices, colors.ToArray()));
            }
            else
            {
                return(ReduceColorPalette(name, bitmap, colors, algorithm, 256));
            }
        }