Exemplo n.º 1
0
        MixingPlan DeviseBestMixingPlan(int color)
        {
            Vector3 clampMin = Vector3.Zero;
            Vector3 clampMax = new Vector3(255, 255, 255);

            MixingPlan result = new MixingPlan
            {
                colors = new int[64]
            };

            Vector3 src = new Vector3(color >> 16, (color >> 8) & 0xFF, color & 0xFF);

            const float X = 0.09f;        // Error multiplier
            Vector3     e = Vector3.Zero; // Error accumulator

            for (int c = 0; c < 64; ++c)
            {
                // Current temporary value
                Vector3 t = src + Vector3.Multiply(e, X);
                // Clamp it in the allowed RGB range
                t = Vector3.Clamp(t, clampMin, clampMax);
                // Find the closest color from the palette
                float least_penalty = float.MaxValue;
                int   chosen        = c % 16;
                for (int index = 0; index < 16; ++index)
                {
                    int     color1 = pal[index];
                    Vector3 pc1;
                    pc1 = new Vector3(color1 >> 16, (color1 >> 8) & 0xFF, color1 & 0xFF);
                    float penalty = ColorCompare(pc1, t);
                    if (penalty < least_penalty)
                    {
                        least_penalty = penalty; chosen = index;
                    }
                }
                // Add it to candidates and update the error
                result.colors[c] = chosen;
                color            = pal[chosen];
                Vector3 pc = new Vector3(color >> 16, (color >> 8) & 0xFF, color & 0xFF);
                e += src - pc;
            }
            // Sort the colors according to luminance
            Array.Sort(result.colors, PaletteCompareLuma);
            return(result);
        }
Exemplo n.º 2
0
        MixingPlan DeviseBestMixingPlan(int color)
        {
            MixingPlan result = new MixingPlan();

            result.colors = new int[64];

            int[] src = new int[] { color >> 16, (color >> 8) & 0xFF, color & 0xFF };

            const double X = 0.09;           // Error multiplier

            int[] e = new int[] { 0, 0, 0 }; // Error accumulator
            for (int c = 0; c < 64; ++c)
            {
                // Current temporary value
                int[] t = new int[] { (int)(src[0] + e[0] * X), (int)(src[1] + e[1] * X), (int)(src[2] + e[2] * X) };
                // Clamp it in the allowed RGB range
                if (t[0] < 0)
                {
                    t[0] = 0;
                }
                else if (t[0] > 255)
                {
                    t[0] = 255;
                }
                if (t[1] < 0)
                {
                    t[1] = 0;
                }
                else if (t[1] > 255)
                {
                    t[1] = 255;
                }
                if (t[2] < 0)
                {
                    t[2] = 0;
                }
                else if (t[2] > 255)
                {
                    t[2] = 255;
                }
                // Find the closest color from the palette
                double least_penalty = 1e99;
                int    chosen        = c % 16;
                for (int index = 0; index < 16; ++index)
                {
                    color = pal[index];
                    int[]  pc      = new int[] { color >> 16, (color >> 8) & 0xFF, color & 0xFF };
                    double penalty = ColorCompare(pc[0], pc[1], pc[2], t[0], t[1], t[2]);
                    if (penalty < least_penalty)
                    {
                        least_penalty = penalty; chosen = index;
                    }
                }
                // Add it to candidates and update the error
                result.colors[c] = chosen;
                color            = pal[chosen];
                int[] pc1 = new int[] { color >> 16, (color >> 8) & 0xFF, color & 0xFF };
                e[0] += src[0] - pc1[0];
                e[1] += src[1] - pc1[1];
                e[2] += src[2] - pc1[2];
            }
            // Sort the colors according to luminance
            Array.Sort(result.colors, PaletteCompareLuma);
            return(result);
        }
Exemplo n.º 3
0
        public override Bitmap DitherImage(Bitmap input)
        {
            //get depth and bytes-per-pixel for input
            int depth  = Image.GetPixelFormatSize(input.PixelFormat);
            int cCount = depth / 8;

            Bitmap result = new Bitmap(input.Width, input.Height, PixelFormat.Format8bppIndexed);

            //prepare result's palette using pre-defined palette
            ColorPalette resultPalette = result.Palette;

            Parallel.For(0, pal.Length, c =>
            {
                int r = pal[c] >> 16, g = (pal[c] >> 8) & 0xFF, b = pal[c] & 0xFF;
                resultPalette.Entries[c] = friendlyPal[c];
                luma[c] = r * 299 + g * 587 + b * 114;
            });

            //load palette into result
            result.Palette = resultPalette;

            //lock the input data into memory
            BitmapData inputData = input.LockBits(new Rectangle(0, 0, input.Width, input.Height), ImageLockMode.ReadOnly, input.PixelFormat);

            BitmapData resultData = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

            //create byte arrays for data
            byte[] resultColorData = new byte[resultData.Stride * resultData.Height];
            byte[] inputColorData  = new byte[inputData.Width * inputData.Height * cCount];

            //store inputs' height and width in thread-safe variables
            int inputHeight    = input.Height;
            int inputWidth     = input.Width;
            int inputDataWidth = inputData.Width;

            //copy data into byte arrays
            Marshal.Copy(inputData.Scan0, inputColorData, 0, inputColorData.Length);

            Marshal.Copy(resultData.Scan0, resultColorData, 0, resultColorData.Length);

#if DEBUG
            try
            {
                Parallel.For(0, inputHeight, y =>
                {
                    for (int x = 0; x < inputWidth; x++)
                    {
                        //get current position in the array
                        int i                       = ((y * inputDataWidth) + x) * cCount;
                        int color                   = inputColorData[i] + (inputColorData[i + 1] << 8) + (inputColorData[i + 2] << 16);
                        int map_value               = map[(x & 7) + ((y & 7) << 3)];
                        MixingPlan plan             = DeviseBestMixingPlan(color);
                        resultColorData[i / cCount] = (byte)plan.colors[map_value];
                    }
                    ;
                });

                ////Scalar testing code
                //for (int y = 0; y < input.Height; ++y)
                //{
                //    for (int x = 0; x < input.Width; ++x)
                //    {
                //        int i = ((y * inputData.Width) + x) * cCount;
                //        int color = inputColorData[i] + (inputColorData[i + 1] << 8) + (inputColorData[i + 2] << 16);
                //        int map_value = map[(x & 7) + ((y & 7) << 3)];
                //        MixingPlan plan = DeviseBestMixingPlan(color);
                //        resultColorData[i / cCount] = (byte)plan.colors[map_value];
                //    };
                //};
                Marshal.Copy(resultColorData, 0, resultData.Scan0, resultColorData.Length);
            }
            finally
            {
                result.UnlockBits(resultData);
                input.UnlockBits(inputData);
            }
#endif
#if !DEBUG
            Parallel.For(0, inputHeight, y =>
            {
                for (int x = 0; x < inputWidth; x++)
                {
                    //get current position in the array
                    int i                       = ((y * inputDataWidth) + x) * cCount;
                    int color                   = inputColorData[i] + (inputColorData[i + 1] << 8) + (inputColorData[i + 2] << 16);
                    int map_value               = map[(x & 7) + ((y & 7) << 3)];
                    MixingPlan plan             = DeviseBestMixingPlan(color);
                    resultColorData[i / cCount] = (byte)plan.colors[map_value];
                }
                ;
            });
            Marshal.Copy(resultColorData, 0, resultData.Scan0, resultColorData.Length);
#endif
            return(result);
        }