public static bool HistoStretch(ref Bitmap graybmp, params double[] limit)
        {
            if (graybmp.PixelFormat != PixelFormat.Format8bppIndexed)
                return false;

            int w = graybmp.Width;
            int h = graybmp.Height;

            double stretchfactor = 1.00;

            int threshold = (int)(w * h * 0.015);

            if (limit.Length != 0) threshold = (int)(w * h * limit[0] / 100);

            int[] hist = new int[256];

            BmpProc8 src = new BmpProc8(graybmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                    hist[src[x, y]]++;

            int lt = 0;
            for (int i = 0; i < 256; i++)
            {
                lt += hist[i];
                if (lt > threshold)
                {
                    lt = i;
                    break;
                }
            }

            int ht = 0;
            for (int i = 255; i >= 0; i--)
            {
                ht += hist[i];
                if (ht > threshold)
                {
                    ht = i;
                    break;
                }
            }

            double originalrange = ht - lt + 1;
            double stretchedrange = originalrange + stretchfactor * (255 - originalrange);
            double scalefactor = stretchedrange / originalrange;

            for (int i = 0; i < 256; i++)
                hist[i] = AdjustByte(scalefactor * (i - lt));

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                    src[x, y] = (byte)hist[src[x, y]];

            src.Dispose();

            return true;
        }
        public static bool AlphaSheet(ref Bitmap bmp, bool stretch, bool bInvert)
        {
            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap tmp = new Bitmap(w, h, PixelFormat.Format32bppArgb);
            Graphics g = Graphics.FromImage(tmp);
            g.DrawImageUnscaled(bmp, 0, 0);
            g.Dispose();

            ImageUtility.GrayScale(ref bmp);
            if (stretch) ImageUtility.HistoStretch(ref bmp);

            BmpProc8 src = new BmpProc8(bmp);
            BmpProc32 dst = new BmpProc32(tmp);

            if (bInvert)
                for (int y = 0; y < h; y++)
                    for (int x = 0; x < w; x++)
                        dst[x, y, eRGB.a] = (byte)(255 - src[x, y]);
            else
                for (int y = 0; y < h; y++)
                    for (int x = 0; x < w; x++)
                        dst[x, y, eRGB.a] = src[x, y];

            CallDispose(dst, src, bmp);

            bmp = tmp;

            return true;
        }
        public static bool PaletteHistogram(Bitmap bmp, out Bitmap bmpHist)
        {
            if (bmp.PixelFormat != PixelFormat.Format8bppIndexed)
            {
                bmpHist = null;
                return false;
            }

            int w = bmp.Width;
            int h = bmp.Height;

            int[] hist = new int[256];


            BmpProc8 bd = new BmpProc8(bmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                    hist[bd[x, y]]++;

            bd.Dispose();

            int max = -1;
            for (int i = 0; i < 256; i++)
                if (hist[i] > max) max = hist[i];

            for (int i = 0; i < 256; i++)
                hist[i] = hist[i] * 140 / max;

            bmpHist = new Bitmap(275, 180, PixelFormat.Format24bppRgb);

            Graphics g = Graphics.FromImage(bmpHist);
            g.Clear(Color.AntiqueWhite);

            Pen pen = new Pen(Color.Gray, 1F);

            for (int i = 0; i < 256; i++)
                g.DrawLine(pen, 10 + i, 150, 10 + i, 150 - hist[i]);

            pen.Color = Color.Black;

            g.DrawLine(pen, 8, 150, 8, 10);

            for (int i = 0; i <= 20; i++)
                if ((i % 2) == 0)
                    g.DrawLine(pen, 8, 150 - 7 * i, 4, 150 - 7 * i);
                else
                    g.DrawLine(pen, 8, 150 - 7 * i, 6, 150 - 7 * i);

            g.DrawLine(pen, 10, 150, 10 + 255, 150);

            for (int i = 0; i <= 51; i++)
                if ((i % 2) == 0)
                    g.DrawLine(pen, 10 + 5 * i, 150, 10 + 5 * i, 154);
                else
                    g.DrawLine(pen, 10 + 5 * i, 150, 10 + 5 * i, 152);

            ColorPalette pal = bmp.Palette;

            for (int i = 0; i < 256; i++)
            {
                pen.Color = pal.Entries[i];
                g.DrawLine(pen, 10 + i, 175, 10 + i, 158);
            }

            g.Dispose();

            return true;
        }
        public static bool Rinkaku(ref Bitmap bmp, eEdge edge, double factor)
        {
            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            double edg, sbl, v;

            double[] ff = new double[256];

            for (int i = 0; i < 256; i++)
                ff[i] = factor * Math.Sin((double)i * Math.PI / 160d);

            Bitmap tmp = bmp.Clone() as Bitmap;
            switch (edge)
            {
                case eEdge.Edge2:
                    Edge2(ref tmp, true);
                    break;

                case eEdge.Edge3:
                    Edge3(ref tmp, true);
                    break;
            }
            HistoStretch(ref tmp);

            Contour(ref bmp, true, false);

            BmpProc8 src = new BmpProc8(tmp);
            BmpProc8 dst = new BmpProc8(bmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    edg = 255d - src[x, y];
                    sbl = 255d - dst[x, y];
                    v = Math.Sqrt(edg * sbl);
                    v = v - ff[(int)v];
                    dst[x, y] = AdjustByte(255d - v);
                }

            CallDispose(dst, src, tmp);

            return true;
        }
        public static bool TwoColorGrayScale(ref Bitmap bmp, Color Dark, Color Bright)
        {
            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap tmp = new Bitmap(w, h, PixelFormat.Format8bppIndexed);

            if (!SetTwoColorGrayPalette(tmp, Dark, Bright))
            {
                tmp.Dispose();
                return false;
            }

            BmpProc24 src = new BmpProc24(bmp);
            BmpProc8 dst = new BmpProc8(tmp);

            int ir;

            for (int y = 0; y < h; ++y)
                for (int x = 0; x < w; ++x)
                {
                    ir = src.IndexR(x, y);

                    dst[x, y] = (byte)(src[ir] * 0.299 +
                                         src[ir - 1] * 0.587 + src[ir - 2] * 0.114);

                }
            CallDispose(dst, src, bmp);

            bmp = tmp;
            return true;
        }
        public static bool Gravity(ref Bitmap bmp, int period, float angle,
                                        float factor, Color dark, Color bright)
        {
            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            int f = (int)(period * factor);
            double xx, yy, ff;
            double angle90 = angle + 90d;

            double sn = Math.Sin(angle90 * Math.PI / 180d);
            double cs = Math.Cos(angle90 * Math.PI / 180d);

            Bitmap bw = bmp.Clone() as Bitmap;
            ImageUtility.GrayScale(ref bw);
            ImageUtility.HistoStretch(ref bw);

            Bitmap stripe = MakeGradientPattern(w + f * 2 + 2, h + f * 2 + 2,
                                                                period, angle);

            BmpProc8 mod = new BmpProc8(bw);
            BmpProc24 src = new BmpProc24(stripe);
            BmpProc24 dst = new BmpProc24(bmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    ff = f * (255d - (double)mod[x, y]) / 255d;
                    xx = x + ff * cs;
                    yy = y + ff * sn;
                    intBilinear(dst, src, x, y, xx + f + 1, yy + f + 1);
                }

            CallDispose(dst, src, mod, stripe, bw);

            GrayScale(ref bmp);
            SetTwoColorGrayPalette(bmp, dark, bright);

            return true;
        }
        public static bool Invert8(ref Bitmap bmp)
        {
            if (bmp.PixelFormat != PixelFormat.Format8bppIndexed)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            BmpProc8 src = new BmpProc8(bmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                    src[x, y] = (byte)(255 - src[x, y]);

            src.Dispose();

            return true;
        }
        public static bool OrderedDither(Bitmap bmp, DitherPattern dp, ErrorDiffusion ed,
                bool fStretch, Color dark, Color bright, out Bitmap bmp1)
        {
            bmp1 = null;

            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap tmp = (Bitmap)bmp.Clone();

            ImageUtility.GrayScale(ref tmp);

            if (fStretch) ImageUtility.HistoStretch(ref tmp);

            byte[,] od22 = { { 51, 204},
                             {153, 102} };

            byte[,] od33 = { {131, 182,  105},
                             {157, 236,  26},
                             { 79, 210,  52} };

            byte[,] od332 = { { 64, 128,  64},
                             {128, 196, 128},
                             { 64, 128,  64} };

            byte[,] od44 = { { 15, 195,  60, 240},
                             {135,  75, 180, 120},
                             { 45, 225,  30, 210},
                             {165, 105, 150,  90} };

            byte[,] od442 = { {  51, 102, 204, 153},
                              { 204, 153,  51, 102},
                              { 153, 204, 102,  51},
                              { 102,  51, 153, 204} };

            byte[,] od443 = { {  51, 102, 204, 153},
                              { 204, 153,  51, 102},
                              { 102,  51, 153, 204},
                              { 153, 204, 102,  51} };

            byte[,] msk = od22;

            switch (dp)
            {
                case DitherPattern.od22: msk = od22; break;
                case DitherPattern.od33: msk = od33; break;
                case DitherPattern.od332: msk = od332; break;
                case DitherPattern.od44: msk = od44; break;
                case DitherPattern.od442: msk = od442; break;
                case DitherPattern.od443: msk = od443; break;
            }

            double[,] fs = { {       -1,       -1, 7.0/16.0},
                             { 3.0/16.0, 5.0/16.0, 1.0/16.0} };

            double[,] st = { {-1, -1,  -1, 8.0/42.0, 4.0/42.0},
                             {2.0/42.0, 4.0/42.0, 8.0/42.0, 4.0/42.0, 2.0/42.0},
                             {1.0/42.0, 2.0/42.0, 4.0/42.0, 2.0/42.0, 1.0/42.0} };

            double[,] sr = { {-1, -1,  -1, 5.0/32.0, 3.0/32.0},
                             {2.0/32.0, 4.0/32.0, 5.0/32.0, 4.0/32.0, 2.0/32.0},
                             {-1, 2.0/32.0, 3.0/32.0, 2.0/32.0, -1} };

            double[,] jjn = { {-1, -1, -1, 7.0/48.0, 5.0/48.0},
                              {3.0/48.0, 5.0/48.0, 7.0/48.0, 5.0/48.0, 3.0/48.0},
                              {1.0/48.0, 3.0/48.0, 5.0/48.0, 3.0/48.0, 1.0/48.0} };

            double[,] df = st;

            switch (ed)
            {
                case ErrorDiffusion.FloydSteinberg: df = fs; break;
                case ErrorDiffusion.Stucci: df = st; break;
                case ErrorDiffusion.Sierra: df = sr; break;
                case ErrorDiffusion.JaJuNi: df = jjn; break;
            }

            byte d8;
            bool d;
            double err;
            int xx, yy;

            int row = df.GetLength(0);
            int col = df.GetLength(1);

            int xrange = (col - 1) / 2;

            bmp1 = new Bitmap(w, h, PixelFormat.Format1bppIndexed);

            int dm = msk.GetLength(0);

            BmpProc8 src = new BmpProc8(tmp);
            BmpProc1 dst = new BmpProc1(bmp1);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    d8 = src[x, y];
                    d = (d8 > msk[y % dm, x % dm]);
                    dst[x, y] = d;

                    if (d) { err = d8 - 255; } else { err = d8; }

                    for (int iy = 0; iy < row; iy++)
                        for (int ix = -xrange; ix <= xrange; ix++)
                        {
                            xx = x + ix; if ((xx < 0) | (xx > w - 1)) continue;
                            yy = y + iy; if (yy > h - 1) continue;

                            if (df[iy, ix + xrange] < 0) continue;

                            src[xx, yy] = ImageUtility.AdjustByte(src[xx, yy] +
                                                           err * df[iy, ix + xrange]);
                        }

                }

            CallDispose(dst, src, tmp);

            ColorPalette cp = bmp1.Palette;
            cp.Entries[0] = dark;
            cp.Entries[1] = bright;
            bmp1.Palette = cp;

            return true;
        }
        public static bool Diacross(ref Bitmap bmp, bool bFine,
                                            Color penColor, Color bkColor)
        {
            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            Graphics g;

            GrayScale(ref bmp);
            HistoStretch(ref bmp);

            Bitmap[] pattern = new Bitmap[4];
            TextureBrush[] tb = new TextureBrush[4];

            if (bFine)
            {
                Pen pn = new Pen(penColor, 1.8f);
                pn.Alignment = PenAlignment.Center;

                PointF[] start = { new PointF(0f, 0.5f), new PointF(0.5f, 0F), 
                                            new PointF(0f, 2.5f), new PointF(2.5f, 0f) };
                PointF[] stop = { new PointF(4f, 0.5f), new PointF(0.5f, 4f), 
                                            new PointF(4f, 2.5f), new PointF(2.5f, 4f) };

                float[] angle = { -37f, -53f };

                for (int i = 0; i < 4; i++)
                {
                    pattern[i] = new Bitmap(4, 4, PixelFormat.Format24bppRgb);
                    g = Graphics.FromImage(pattern[i]);
                    g.Clear(Color.White);
                    g.DrawLine(pn, start[i], stop[i]);
                    g.Dispose();

                    tb[i] = MakePatternBrush(pattern[i], angle[i % 2]);
                }

                pn.Dispose();
            }
            else
            {
                Pen pn = new Pen(penColor, 2.2f);
                pn.Alignment = PenAlignment.Center;

                Point[] start = { new Point(0, 1), new Point(1, 0), 
                                        new Point(0, 4), new Point(4, 0) };
                Point[] stop = { new Point(9, 1), new Point(1, 9), 
                                        new Point(9, 4), new Point(4, 9) };

                float[] angle = { -30f, -60f };

                for (int i = 0; i < 4; i++)
                {
                    pattern[i] = new Bitmap(6, 6, PixelFormat.Format32bppArgb);
                    g = Graphics.FromImage(pattern[i]);
                    g.Clear(Color.White);
                    g.DrawLine(pn, start[i], stop[i]);
                    g.Dispose();

                    tb[i] = MakePatternBrush(pattern[i], angle[i % 2]);
                }

                pn.Dispose();
            }

            Bitmap dst = new Bitmap(w, h, PixelFormat.Format24bppRgb);
            Graphics gdst = Graphics.FromImage(dst);
            gdst.Clear(bkColor);

            byte[] th = { 255, 191, 128, 64 };

            Bitmap tgt;

            BmpProc8 mod = new BmpProc8(bmp);

            for (int i = 0; i < 4; i++)
            {

                tgt = new Bitmap(w, h, PixelFormat.Format32bppArgb);

                g = Graphics.FromImage(tgt);
                g.FillRectangle(tb[i], 0, 0, w, h);
                g.Dispose();
                tb[i].Dispose();
                pattern[i].Dispose();

                BmpProc32 src = new BmpProc32(tgt);

                for (int y = 0; y < h; y++)
                    for (int x = 0; x < w; x++)
                    {
                        if (mod[x, y] < th[i])
                            src[x, y, eRGB.a] =
                                AdjustByte((double)(255 - src[x, y, eRGB.r]) *
                                    ((1d - ((double)mod[x, y] / (double)th[i]))));
                        else
                            src[x, y, eRGB.a] = 0;
                    }

                src.Dispose();

                gdst.DrawImageUnscaled(tgt, 0, 0);

                tgt.Dispose();
            }

            mod.Dispose();
            bmp.Dispose();
            gdst.Dispose();

            bmp = dst;
            return true;
        }
        public static bool Contour(ref Bitmap bmp, bool bStretch, bool b24bit)
        {
            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            Rectangle rct = new Rectangle(0, 0, w - 1, h - 1);

            double[] dis = new double[4];

            int[] ix = new int[4];
            int[] iy = new int[4];
            double max;
            double dd = 1.732d;
            byte r, g, b;

            Bitmap tmp = new Bitmap(w, h, PixelFormat.Format8bppIndexed);
            SetGrayPalette(tmp);

            BmpProc24 src = new BmpProc24(bmp);
            BmpProc8 dst = new BmpProc8(tmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    src.SetXY(x, y);
                    r = src.R; g = src.G; b = src.B;

                    ix[0] = x + 1; iy[0] = y - 1;   // upper-right
                    ix[1] = x + 1; iy[1] = y;       // right
                    ix[2] = x + 1; iy[2] = y + 1;   // lower-right
                    ix[3] = x; iy[3] = y + 1;   // lower

                    for (int i = 0; i < 4; i++)
                        if (rct.Contains(ix[i], iy[i]))
                        {
                            src.SetXY(ix[i], iy[i]);
                            dis[i] = (src.R - r) * (src.R - r) +
                                     (src.G - g) * (src.G - g) +
                                     (src.B - b) * (src.B - b);
                        }
                        else
                            dis[i] = 0d;

                    max = 0;

                    for (int i = 0; i < 4; i++)
                        if (dis[i] > max) max = dis[i];

                    dst[x, y] = AdjustByte(255d - Math.Sqrt(max) / dd);
                }

            CallDispose(dst, src);

            if (bStretch) HistoStretch(ref tmp);

            if (b24bit)
            {
                Graphics gr = Graphics.FromImage(bmp);
                gr.DrawImageUnscaled(tmp, 0, 0);
                gr.Dispose();
                tmp.Dispose();
            }
            else
            {
                bmp.Dispose();
                bmp = tmp;
            }

            return true;
        }
        public static bool GrayScale8(ref Bitmap bmp8)
        {
            if (bmp8.PixelFormat != PixelFormat.Format8bppIndexed)
                return false;

            int w = bmp8.Width;
            int h = bmp8.Height;

            ColorPalette pal = bmp8.Palette;

            byte[] cl = new byte[pal.Entries.Length];

            Color c;

            for (int i = 0; i < pal.Entries.Length; i++)
            {
                c = pal.Entries[i];
                cl[i] = (byte)(c.R * 0.299 + c.G * 0.587 + c.B * 0.114);
            }

            BmpProc8 bd = new BmpProc8(bmp8);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                    bd[x, y] = cl[bd[x, y]];

            bd.Dispose();

            return SetGrayPalette(bmp8);
        }
        public static bool KuwaharaGrayScale(ref Bitmap bmp,
                                                int block, bool bDetail)
        {
            if (bmp.PixelFormat != PixelFormat.Format8bppIndexed)
                return false;

            if ((block < 1) | (block > 10)) return false;

            int w = bmp.Width;
            int h = bmp.Height;

            int num = (block + 1) * (block + 1);

            int[] v = new int[4];
            Point[] evP = new Point[4];
            Rectangle rct = new Rectangle(0, 0, w - 1, h - 1);
            int[] xini = new int[4];
            int[] xend = new int[4];
            int[] yini = new int[4];
            int[] yend = new int[4];

            int d, max, min, indx;

            double t;

            Bitmap tmp = bmp.Clone() as Bitmap;

            BmpProc8 src = new BmpProc8(tmp);
            BmpProc8 dst = new BmpProc8(bmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {

                    evP[0].X = x - block; evP[0].Y = y - block; // upper-left
                    xini[0] = x - block; xend[0] = x;
                    yini[0] = y - block; yend[0] = y;

                    evP[1].X = x + block; evP[1].Y = y - block; // upper-right
                    xini[1] = x; xend[1] = x + block;
                    yini[1] = y - block; yend[1] = y;

                    evP[2].X = x + block; evP[2].Y = y + block; // lower-right
                    xini[2] = x; xend[2] = x + block;
                    yini[2] = y; yend[2] = y + block;

                    evP[3].X = x - block; evP[3].Y = y + block; // lower-left
                    xini[3] = x - block; xend[3] = x;
                    yini[3] = y; yend[3] = y + block;

                    for (int i = 0; i <= 3; i++)
                    {
                        v[i] = 1000;
                        if (!rct.Contains(evP[i])) continue;

                        max = 0; min = 255;
                        for (int ix = xini[i]; ix <= xend[i]; ix++)
                            for (int iy = yini[i]; iy <= yend[i]; iy++)
                            {
                                d = src[ix, iy];
                                if (d > max) max = d;
                                if (d < min) min = d;
                            }

                        v[i] = max - min;
                    }

                    min = 1000; indx = 0;
                    for (int i = 0; i <= 3; i++)
                        if (v[i] < min) { min = v[i]; indx = i; }

                    d = 0;

                    for (int ix = xini[indx]; ix <= xend[indx]; ix++)
                        for (int iy = yini[indx]; iy <= yend[indx]; iy++)
                            d += src[ix, iy];

                    if (bDetail)
                    {
                        t = Math.Max(0.5d, (255d - (double)v[indx]) / 255d);
                        dst[x, y] = ImageUtility.AdjustByte(t * (d / num) +
                                                        (1d - t) * dst[x, y]);
                    }
                    else
                        dst[x, y] = ImageUtility.AdjustByte(d / num);
                }

            ImageUtility.CallDispose(dst, src, tmp);

            return true;
        }
        public static bool Oscillo(ref Bitmap bmp, int width, bool bHorizontal,
                                                        Color dark, Color bright)
        {
            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            if ((width < 2) | (width > 10)) return false;

            int w = bmp.Width;
            int h = bmp.Height;

            int interval = width * 2 + 1;

            double sum;
            int count;

            Bitmap tmp = bmp.Clone() as Bitmap;
            GrayScale(ref tmp);
            HistoStretch(ref tmp);

            Pen pn = new Pen(Color.Black, 1.0f);

            Graphics g = Graphics.FromImage(bmp);
            g.Clear(Color.White);
            g.SmoothingMode = SmoothingMode.AntiAlias;

            BmpProc8 src = new BmpProc8(tmp);

            if (bHorizontal)
                for (int y = width; y < h + width; y += interval)
                    for (int x = 0; x < w; x++)
                    {
                        sum = 0; count = 0;
                        for (int iy = y - width; iy <= y + width; iy++)
                        {
                            if (iy > h - 1) break;
                            count++;
                            sum += 255 - src[x, iy];
                        }
                        sum = sum * width / (count * 255d);
                        sum = Math.Max(0.1d, sum);

                        g.DrawLine(pn, (float)x, (float)(y + sum),
                                                   (float)x, (float)(y - sum));
                    }
            else
                for (int x = width; x < w + width; x += interval)
                    for (int y = 0; y < h; y++)
                    {
                        sum = 0; count = 0;
                        for (int ix = x - width; ix <= x + width; ix++)
                        {
                            if (ix > w - 1) break;
                            count++;
                            sum += 255 - src[ix, y];
                        }
                        sum = sum * width / (count * 255d);
                        sum = Math.Max(0.1d, sum);

                        g.DrawLine(pn, (float)(x - sum), (float)y,
                                                  (float)(x + sum), (float)y);
                    }

            src.Dispose();
            g.Dispose();

            GrayScale(ref bmp);

            SetTwoColorGrayPalette(bmp, dark, bright);

            return true;
        }
        public static bool ErrorDiffusionDither(Bitmap bmp, ErrorDiffusion ed, bool fStretch,
                            Color dark, Color bright, byte randomness, out Bitmap bmp1)
        {
            bmp1 = null;

            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            if ((randomness < 0) | (randomness > 30)) return false;

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap tmp = (Bitmap)bmp.Clone();

            GrayScale(ref tmp);

            if (fStretch) HistoStretch(ref tmp);

            double[,] fs = { {       -1,       -1, 7.0/16.0},
                             { 3.0/16.0, 5.0/16.0, 1.0/16.0} };

            double[,] st = { {-1, -1,  -1, 8.0/42.0, 4.0/42.0},
                             {2.0/42.0, 4.0/42.0, 8.0/42.0, 4.0/42.0, 2.0/42.0},
                             {1.0/42.0, 2.0/42.0, 4.0/42.0, 2.0/42.0, 1.0/42.0} };

            double[,] sr = { {-1, -1,  -1, 5.0/32.0, 3.0/32.0},
                             {2.0/32.0, 4.0/32.0, 5.0/32.0, 4.0/32.0, 2.0/32.0},
                             {-1, 2.0/32.0, 3.0/32.0, 2.0/32.0, -1} };

            double[,] jjn = { {-1, -1, -1, 7.0/48.0, 5.0/48.0},
                              {3.0/48.0, 5.0/48.0, 7.0/48.0, 5.0/48.0, 3.0/48.0},
                              {1.0/48.0, 3.0/48.0, 5.0/48.0, 3.0/48.0, 1.0/48.0} };


            bmp1 = new Bitmap(w, h, PixelFormat.Format1bppIndexed);

            byte d8;
            bool d;
            double err;
            int xx, yy;

            byte threshold = 127;

            Random rnd = new Random();
            byte randn = (byte)(randomness * 2 + 1);

            double[,] df;

            df = st;

            switch (ed)
            {
                case ErrorDiffusion.FloydSteinberg: df = fs; break;
                case ErrorDiffusion.Stucci: df = st; break;
                case ErrorDiffusion.Sierra: df = sr; break;
                case ErrorDiffusion.JaJuNi: df = jjn; break;
            }

            int row = df.GetLength(0);
            int col = df.GetLength(1);

            int xrange = (col - 1) / 2;

            BmpProc8 src = new BmpProc8(tmp);
            BmpProc1 dst = new BmpProc1(bmp1);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    if (randomness > 0)
                        threshold = (byte)(127 + rnd.Next(randn) - randomness);

                    d8 = src[x, y];
                    d = (d8 > threshold);
                    dst[x, y] = d;

                    if (d) { err = d8 - 255; } else { err = d8; }

                    for (int iy = 0; iy < row; iy++)
                        for (int ix = -xrange; ix <= xrange; ix++)
                        {
                            xx = x + ix; if ((xx < 0) | (xx > w - 1)) continue;
                            yy = y + iy; if (yy > h - 1) continue;

                            if (df[iy, ix + xrange] < 0) continue;

                            src[xx, yy] = AdjustByte(src[xx, yy] +
                                                           err * df[iy, ix + xrange]);
                        }
                }

            CallDispose(dst, src, tmp);

            ColorPalette cp = bmp1.Palette;
            cp.Entries[0] = dark;
            cp.Entries[1] = bright;
            bmp1.Palette = cp;

            return true;
        }
        public static bool Dots(Bitmap bmp, int zone,
                                  Color dark, Color bright, out Bitmap dot)
        {
            dot = null;

            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            if ((zone < 3) | (zone > 15)) return false;

            Bitmap tmp = bmp.Clone() as Bitmap;

            GrayScale(ref tmp);

            int w = bmp.Width;
            int h = bmp.Height;

            int count;
            double sum;
            double propc = zone / 28.5d;
            float cx, cy, cl, ct, cw, ch;

            dot = new Bitmap(w, h, PixelFormat.Format24bppRgb);

            Graphics g = Graphics.FromImage(dot);
            g.Clear(Color.White);
            g.SmoothingMode = SmoothingMode.AntiAlias;
            SolidBrush br = new SolidBrush(Color.Black);

            BmpProc8 src = new BmpProc8(tmp);

            for (int y = 0; y < h - 1; y += zone)
                for (int x = 0; x < w - 1; x += zone)
                {
                    count = 0;
                    sum = 0;

                    for (int iy = y; iy < y + zone; iy++)
                        for (int ix = x; ix < x + zone; ix++)
                        {
                            if ((iy > h - 1) | (ix > w - 1)) continue;

                            count++;
                            sum += 255 - src[ix, iy];
                        }

                    sum = Math.Sqrt(sum / count) * propc;

                    cx = x + (float)zone / 2f;
                    cy = y + (float)zone / 2f;

                    cl = (float)(cx - sum); ct = (float)(cy - sum);
                    cw = (float)(sum * 2); ch = (float)(sum * 2);

                    g.FillEllipse(br, cl, ct, cw, ch);
                }

            CallDispose(src, tmp);

            br.Dispose();
            g.Dispose();

            GrayScale(ref dot);
            SetTwoColorGrayPalette(dot, dark, bright);

            return true;
        }
        public static bool GrayScale(ref Bitmap bmp)
        {
            if (bmp == null)
                throw new ArgumentNullException("bmp is null.");

            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap tmp = new Bitmap(w, h, PixelFormat.Format8bppIndexed);

            if (!SetGrayPalette(tmp))
            {
                tmp.Dispose();
                return false;
            }

            int srcR;

            BmpProc24 src = new BmpProc24(bmp);
            BmpProc8 dst = new BmpProc8(tmp);

            for (int y = 0; y < h; ++y)
                for (int x = 0; x < w; ++x)
                {
                    srcR = src.IndexR(x, y);       // current

                    dst[x, y] = (byte)(src[srcR] * 0.299 +
                                       src[srcR - 1] * 0.587 + src[srcR - 2] * 0.114);

                }

            CallDispose(dst, src, bmp);

            bmp = tmp;

            return true;
        }