/// <summary>
        /// #### Vignette
        /// (red,green,blue) of the vignette effect to apply
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="r">The r.</param>
        /// <param name="g">The g.</param>
        /// <param name="b">The b.</param>
        /// <returns>BitmapWorker.</returns>
        public static BitmapWorker Vignetter(BitmapWorker image, int r, int g, int b)
        {
            float cr = 0, cg = 0, cb = 0, ca;
            int   i = 0, j = 0,
                  h       = image.Height(),
                  w       = image.Width(),
                  centerw = w / 2,
                  centerh = h / 2,
                  maxdist = dist(0, 0, centerw, centerh);


            maxdist = (int)(maxdist * 0.6f);
            int radius = maxdist / 2;

            for (i = 0; i < w; i++)
            {
                for (j = 0; j < h; j++)
                {
                    Color temp = image.GetPixel(i, j);
                    cr = temp.R; cg = temp.G; cb = temp.B; ca = temp.A;
                    int distance = dist(i, j, centerw, centerh);
                    distance = (distance > radius)?distance - radius:0;

                    float ratio = ((distance / (float)(maxdist)));
                    cr = (1 - ratio) * cr + (ratio * r);
                    cg = (1 - ratio) * cg + (ratio * g);
                    cb = (1 - ratio) * cb + (ratio * b);

                    image.SetPixel(i, j, Color.FromArgb((int)Util.clamp(ca, 0, 255), (int)Util.clamp(cr, 0, 255),
                                                        (int)Util.clamp(cg, 0, 255), (int)Util.clamp(cb, 0, 255)));
                }
            }
            return(image);
        }
        /// <summary>
        /// Opacities the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="bottom">The bottom.</param>
        /// <param name="top">The top.</param>
        /// <returns>BitmapWorker.</returns>
        public BitmapWorker opacity(int value, BitmapWorker bottom, BitmapWorker top) // in Form1.cs for example: "layer3 = layers.opacity(50,layer2, layer1);" *"50" = 50% the value from 0-100
        {
            if (value >= 0 && value <= 100)
            {
                float percentge = (float)value / 100;
                int   i = 0, j = 0,
                      h = Math.Min(bottom.Height(), top.Height()),
                      w = Math.Min(bottom.Width(), top.Width());

                for (i = 0; i < w; i++)
                {
                    for (j = 0; j < h; j++)
                    {
                        Color b = bottom.GetPixel(i, j);
                        Color t = top.GetPixel(i, j);
                        float cr = 0, cg = 0, cb = 0, ca = 0;
                        ca = b.A * (1 - percentge) + t.A * percentge;
                        cr = b.R * (1 - percentge) + t.R * percentge;
                        cg = b.G * (1 - percentge) + t.G * percentge;
                        cb = b.B * (1 - percentge) + t.B * percentge;

                        bottom.SetPixel(i, j, Color.FromArgb((int)Util.clamp(ca, 0, 255), (int)Util.clamp(cr, 0, 255), (int)Util.clamp(cg, 0, 255), (int)Util.clamp(cb, 0, 255)));
                    }
                }
            }
            return(bottom);
        }
        /// <summary>
        /// #### Noise [0 - 100]
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="p">The p.</param>
        /// <returns>BitmapWorker.</returns>
        public static BitmapWorker Noise(BitmapWorker image, int p)
        {
            int    adjust   = (int)(p * 2.55f);
            Random rand     = new Random(adjust);
            int    temprand = 0;

            float cr = 0, cg = 0, cb = 0, ca;
            int   i = 0, j = 0,
                  h = image.Height(),
                  w = image.Width();

            for (i = 0; i < w; i++)
            {
                for (j = 0; j < h; j++)
                {
                    Color temp = image.GetPixel(i, j);
                    cr = temp.R; cg = temp.G; cb = temp.B; ca = temp.A;

                    temprand = rand.Next(adjust * -1, adjust);

                    cr += temprand;
                    cg += temprand;
                    cb += temprand;

                    image.SetPixel(i, j, Color.FromArgb((int)Util.clamp(ca, 0, 255), (int)Util.clamp(cr, 0, 255),
                                                        (int)Util.clamp(cg, 0, 255), (int)Util.clamp(cb, 0, 255)));
                }
            }
            return(image);
        }
        /// <summary>
        /// #### Constrast [-100, 100]
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="p">The p.</param>
        /// <returns>BitmapWorker.</returns>
        public static BitmapWorker Contrast(BitmapWorker image, float p)
        {
            p = Util.normalize(p, 0, 2, -100, 100);

            float cr = 0, cg = 0, cb = 0, ca;
            int   i = 0, j = 0,
                  h = image.Height(),
                  w = image.Width();

            for (i = 0; i < w; i++)
            {
                for (j = 0; j < h; j++)
                {
                    Color temp = image.GetPixel(i, j);
                    cr = temp.R; cg = temp.G; cb = temp.B; ca = temp.A;

                    cr = 255 * ContrastC(cr / 255, p);
                    cg = 255 * ContrastC(cg / 255, p);
                    cb = 255 * ContrastC(cb / 255, p);

                    image.SetPixel(i, j, Color.FromArgb((int)Util.clamp(ca, 0, 255), (int)Util.clamp(cr, 0, 255),
                                                        (int)Util.clamp(cg, 0, 255), (int)Util.clamp(cb, 0, 255)));
                }
            }
            return(image);
        }
        /// <summary>
        /// Curveses the specified image.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="s">The s.</param>
        /// <param name="c1">The c1.</param>
        /// <param name="c2">The c2.</param>
        /// <param name="e">The e.</param>
        /// <returns>BitmapWorker.</returns>
        static BitmapWorker Curves(BitmapWorker image, Point s, Point c1, Point c2, Point e)
        {
            Bezier bezier = new Bezier(s, c1, c2, e);

            int[] points = bezier.genColorTable();

            float cr = 0, cg = 0, cb = 0, ca;
            int   i = 0, j = 0,
                  h = image.Height(),
                  w = image.Width();

            for (i = 0; i < w; i++)
            {
                for (j = 0; j < h; j++)
                {
                    Color temp = image.GetPixel(i, j);
                    cr = temp.R; cg = temp.G; cb = temp.B; ca = temp.A;

                    cr = points[(int)cr];
                    cg = points[(int)cg];
                    cb = points[(int)cb];

                    image.SetPixel(i, j, Color.FromArgb((int)Util.clamp(ca, 0, 255), (int)Util.clamp(cr, 0, 255),
                                                        (int)Util.clamp(cg, 0, 255), (int)Util.clamp(cb, 0, 255)));
                }
            }
            return(image);
        }
        /// <summary>
        /// #### Posterize [1, 255]
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="p">The p.</param>
        /// <returns>BitmapWorker.</returns>
        public static BitmapWorker Posterize(BitmapWorker image, float p)
        {
            p = Util.clamp(p, 1, 255);
            int   step = (int)Math.Floor(255 / p);
            float cr = 0, cg = 0, cb = 0, ca;
            int   i = 0, j = 0,
                  h = image.Height(),
                  w = image.Width();

            for (i = 0; i < w; i++)
            {
                for (j = 0; j < h; j++)
                {
                    Color temp = image.GetPixel(i, j);
                    cr = temp.R; cg = temp.G; cb = temp.B; ca = temp.A;


                    cr = (float)Math.Floor(cr / (float)(step)) * step;
                    cg = (float)Math.Floor(cg / (float)(step)) * step;
                    cb = (float)Math.Floor(cb / (float)(step)) * step;

                    image.SetPixel(i, j, Color.FromArgb((int)Util.clamp(ca, 0, 255), (int)Util.clamp(cr, 0, 255),
                                                        (int)Util.clamp(cg, 0, 255), (int)Util.clamp(cb, 0, 255)));
                }
            }
            return(image);
        }
        /// <summary>
        /// #### Saturate [-100, 100]
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="p">The p.</param>
        /// <returns>BitmapWorker.</returns>
        public static BitmapWorker Saturate(BitmapWorker image, float p)
        {
            p = Util.normalize(p, 0, 2, -100, 100);
            float cr = 0, cg = 0, cb = 0, ca;
            int   i = 0, j = 0,
                  h = image.Height(),
                  w = image.Width();

            for (i = 0; i < w; i++)
            {
                for (j = 0; j < h; j++)
                {
                    Color temp = image.GetPixel(i, j);
                    cr = temp.R; cg = temp.G; cb = temp.B; ca = temp.A;
                    float avg = (cr + cg + cb) / 3;

                    cr = avg + p * (cr - avg);
                    cg = avg + p * (cg - avg);
                    cb = avg + p * (cb - avg);

                    image.SetPixel(i, j, Color.FromArgb((int)Util.clamp(ca, 0, 255), (int)Util.clamp(cr, 0, 255),
                                                        (int)Util.clamp(cg, 0, 255), (int)Util.clamp(cb, 0, 255)));
                }
            }
            return(image);
        }
        /// <summary>
        /// Applies the specified bottom.
        /// </summary>
        /// <param name="bottom">The bottom.</param>
        /// <param name="top">The top.</param>
        /// <param name="fn">The function.</param>
        /// <returns>BitmapWorker.</returns>
        BitmapWorker apply(BitmapWorker bottom, BitmapWorker top, string fn)
        {
            int i = 0, j = 0,
                h = Math.Min(bottom.Height(), top.Height()),
                w = Math.Min(bottom.Width(), top.Width());

            for (i = 0; i < w; i++)
            {
                for (j = 0; j < h; j++)
                {
                    // Execute blend on each pixel.
                    bottom.SetPixel(i, j, func(fn, bottom.GetPixel(i, j), top.GetPixel(i, j)));
                }
            }
            return(bottom);
        }
        //public Blur CustomBlur = new Blur(); //the use in Form1.cs for example: "layer1 = effects.CustomBlur.Gaussain(layer1, 10);"

        /// <summary>
        /// Convolves the specified image.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="kernel">The kernel.</param>
        /// <param name="kw">The kw.</param>
        /// <param name="kh">The kh.</param>
        /// <returns>BitmapWorker.</returns>
        static BitmapWorker Convolve(BitmapWorker image, float[,] kernel, int kw, int kh)
        {
            BitmapWorker temp = image.Clone();

            // int kh = kernel;
            //int kw = kh; //kernel[0].Length / 2;
            int i = 0, j = 0, n = 0, m = 0, cr, cg, cb, ca,
                h = image.Height(),
                w = image.Width();

            for (i = 0; i < h; i++)
            {
                for (j = 0; j < w; j++)
                {
                    //kernel loop
                    float r = 0, g = 0, b = 0, a = 0;
                    for (n = -kh; n <= kh; n++)
                    {
                        for (m = -kw; m <= kw; m++)
                        {
                            if (i + n >= 0 && i + n < h)
                            {
                                if (j + m >= 0 && j + m < w)
                                {
                                    float f = kernel[m + kw, n + kh];
                                    if (f == 0)
                                    {
                                        continue;
                                    }
                                    Color colortemp = image.GetPixel(j + m, i + n);
                                    cr = colortemp.R; cg = colortemp.G; cb = colortemp.B; ca = colortemp.A;

                                    r += cr * f;
                                    g += cg * f;
                                    b += cb * f;
                                    a += ca * f;
                                }
                            }
                        }
                    }
                    //kernel loop end

                    temp.SetPixel(j, i, Color.FromArgb((int)Util.clamp(a, 0, 255), (int)Util.clamp(r, 0, 255), (int)Util.clamp(g, 0, 255), (int)Util.clamp(b, 0, 255)));
                }
            }
            return(temp);
        }
        /// <summary>
        /// #### Fill [No Range]
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="r">The r.</param>
        /// <param name="g">The g.</param>
        /// <param name="b">The b.</param>
        /// <returns>BitmapWorker.</returns>
        public static BitmapWorker Fill(BitmapWorker image, int r, int g, int b)
        {
            float cr = 0, cg = 0, cb = 0, ca;
            int   i = 0, j = 0,
                  h = image.Height(),
                  w = image.Width();

            for (i = 0; i < w; i++)
            {
                for (j = 0; j < h; j++)
                {
                    Color temp = image.GetPixel(i, j);
                    cr = temp.R; cg = temp.G; cb = temp.B; ca = temp.A;

                    cr = r;
                    cg = g;
                    cb = b;

                    image.SetPixel(i, j, Color.FromArgb((int)Util.clamp(ca, 0, 255), (int)Util.clamp(cr, 0, 255),
                                                        (int)Util.clamp(cg, 0, 255), (int)Util.clamp(cb, 0, 255)));
                }
            }
            return(image);
        }
        /// <summary>
        /// #### Sepia
        /// </summary>
        /// <param name="image">The image.</param>
        /// <returns>BitmapWorker.</returns>
        public static BitmapWorker Sepia(BitmapWorker image)
        {
            float cr = 0, cg = 0, cb = 0, ca;
            int   i = 0, j = 0,
                  h = image.Height(),
                  w = image.Width();

            for (i = 0; i < w; i++)
            {
                for (j = 0; j < h; j++)
                {
                    Color temp = image.GetPixel(i, j);
                    cr = temp.R; cg = temp.G; cb = temp.B; ca = temp.A;
                    float tcr = cr, tcg = cg, tcb = cb;
                    cr = (tcr * 0.393f) + (tcg * 0.769f) + (tcb * 0.189f);
                    cg = (tcr * 0.349f) + (tcg * 0.686f) + (tcb * 0.168f);
                    cb = (tcr * 0.272f) + (tcg * 0.534f) + (tcb * 0.131f);

                    image.SetPixel(i, j, Color.FromArgb((int)Util.clamp(ca, 0, 255), (int)Util.clamp(cr, 0, 255),
                                                        (int)Util.clamp(cg, 0, 255), (int)Util.clamp(cb, 0, 255)));
                }
            }
            return(image);
        }
        /// <summary>
        /// #### Adjust [-255,255 for each channel]
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="pr">The pr.</param>
        /// <param name="pg">The pg.</param>
        /// <param name="pb">The pb.</param>
        /// <param name="pa">The pa.</param>
        /// <returns>BitmapWorker.</returns>
        public static BitmapWorker Adjust(BitmapWorker image, float pr, float pg, float pb, float pa)
        {
            float cr = 0, cg = 0, cb = 0, ca = 0;

            pr /= 100; pg /= 100; pb /= 100; pa /= 100;
            int i = 0, j = 0,
                h = image.Height(),
                w = image.Width();

            for (i = 0; i < w; i++)
            {
                for (j = 0; j < h; j++)
                {
                    Color temp = image.GetPixel(i, j);
                    cr = temp.R; cg = temp.G; cb = temp.B; ca = temp.A;

                    if (pr > 0)
                    {
                        cr += (255 - cr) * pr;
                    }
                    else
                    {
                        cr -= cr * Math.Abs(pr);
                    }
                    if (pg > 0)
                    {
                        cg += (255 - cg) * pg;
                    }
                    else
                    {
                        cg -= cg * Math.Abs(pg);
                    }
                    if (pb > 0)
                    {
                        cb += (255 - cb) * pb;
                    }
                    else
                    {
                        cb -= cb * Math.Abs(pb);
                    }
                    if (pa > 0)
                    {
                        ca += (255 - ca) * pa;
                    }
                    else
                    {
                        ca -= ca * Math.Abs(pa);
                    }

                    /*
                     * cr *= (1.0f + pr);
                     * cg *= (1.0f + pg);
                     * cb *= (1.0f + pb);
                     * ca *= (1.0f + ca);
                     */


                    image.SetPixel(i, j, Color.FromArgb((int)Util.clamp(ca, 0, 255), (int)Util.clamp(cr, 0, 255), (int)Util.clamp(cg, 0, 255), (int)Util.clamp(cb, 0, 255)));
                }
            }
            return(image);
        }
        /// <summary>
        /// Fasts the box blur.
        /// </summary>
        /// <param name="img">The img.</param>
        /// <param name="radius">The radius.</param>
        /// <returns>BitmapWorker.</returns>
        private static BitmapWorker FastBoxBlur(BitmapWorker img, int radius)
        {
            int kSize = radius;

            if (kSize % 2 == 0)
            {
                kSize++;
            }
            BitmapWorker Hblur = img.Clone();
            float        Avg   = (float)1 / kSize;

            for (int j = 0; j < img.Height(); j++)
            {
                float[] hSum = new float[] { 0f, 0f, 0f, 0f };
                float[] iAvg = new float[] { 0f, 0f, 0f, 0f };

                for (int x = 0; x < kSize; x++)
                {
                    Color tmpColor = img.GetPixel(x, j);
                    hSum[0] += tmpColor.A;
                    hSum[1] += tmpColor.R;
                    hSum[2] += tmpColor.G;
                    hSum[3] += tmpColor.B;
                }

                iAvg[0] = hSum[0] * Avg;
                iAvg[1] = hSum[1] * Avg;
                iAvg[2] = hSum[2] * Avg;
                iAvg[3] = hSum[3] * Avg;


                for (int i = 0; i < img.Width(); i++)
                {
                    if (i - kSize / 2 >= 0 && i + 1 + kSize / 2 < img.Width())
                    {
                        Color tmp_pColor = img.GetPixel(i - kSize / 2, j);
                        hSum[0] -= tmp_pColor.A;
                        hSum[1] -= tmp_pColor.R;
                        hSum[2] -= tmp_pColor.G;
                        hSum[3] -= tmp_pColor.B;
                        Color tmp_nColor = img.GetPixel(i + 1 + kSize / 2, j);
                        hSum[0] += tmp_nColor.A;
                        hSum[1] += tmp_nColor.R;
                        hSum[2] += tmp_nColor.G;
                        hSum[3] += tmp_nColor.B;
                        //
                        iAvg[0] = hSum[0] * Avg;
                        iAvg[1] = hSum[1] * Avg;
                        iAvg[2] = hSum[2] * Avg;
                        iAvg[3] = hSum[3] * Avg;
                    }


                    Hblur.SetPixel(i, j, Color.FromArgb((int)iAvg[0], (int)iAvg[1], (int)iAvg[2], (int)iAvg[3]));
                }
            }

            BitmapWorker total = Hblur.Clone();

            for (int i = 0; i < Hblur.Width(); i++)
            {
                float[] tSum = new float[] { 0f, 0f, 0f, 0f };
                float[] iAvg = new float[] { 0f, 0f, 0f, 0f };
                for (int y = 0; y < kSize; y++)
                {
                    Color tmpColor = Hblur.GetPixel(i, y);
                    tSum[0] += tmpColor.A;
                    tSum[1] += tmpColor.R;
                    tSum[2] += tmpColor.G;
                    tSum[3] += tmpColor.B;
                }
                iAvg[0] = tSum[0] * Avg;
                iAvg[1] = tSum[1] * Avg;
                iAvg[2] = tSum[2] * Avg;
                iAvg[3] = tSum[3] * Avg;

                for (int j = 0; j < Hblur.Height(); j++)
                {
                    if (j - kSize / 2 >= 0 && j + 1 + kSize / 2 < Hblur.Height())
                    {
                        Color tmp_pColor = Hblur.GetPixel(i, j - kSize / 2);
                        tSum[0] -= tmp_pColor.A;
                        tSum[1] -= tmp_pColor.R;
                        tSum[2] -= tmp_pColor.G;
                        tSum[3] -= tmp_pColor.B;
                        Color tmp_nColor = Hblur.GetPixel(i, j + 1 + kSize / 2);
                        tSum[0] += tmp_nColor.A;
                        tSum[1] += tmp_nColor.R;
                        tSum[2] += tmp_nColor.G;
                        tSum[3] += tmp_nColor.B;
                        //
                        iAvg[0] = tSum[0] * Avg;
                        iAvg[1] = tSum[1] * Avg;
                        iAvg[2] = tSum[2] * Avg;
                        iAvg[3] = tSum[3] * Avg;
                    }
                    total.SetPixel(i, j, Color.FromArgb((int)iAvg[0], (int)iAvg[1], (int)iAvg[2], (int)iAvg[3]));
                }
            }
            return(total);
        }