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 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 TwoValued2(Bitmap bmp24, Color BKcolor, out Bitmap bmp1)
        {
            bmp1 = null;

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

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

            byte r = BKcolor.R;
            byte g = BKcolor.G;
            byte b = BKcolor.B;

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

            int ir;

            BmpProc24 src = new BmpProc24(bmp24);
            BmpProc1 dst = new BmpProc1(bmp1);

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

                    dst[x, y] = ((src[ir] == r) && (src[ir - 1] == g) && (src[ir - 2] == b));

                }

            CallDispose(dst, src);

            return true;
        }
        public static bool TwoValued1(Bitmap bmp24, int threshold, out Bitmap bmp1)
        {
            bmp1 = null;

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

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

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

            int srcR;

            BmpProc24 src = new BmpProc24(bmp24);
            BmpProc1 dst = new BmpProc1(bmp1);

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

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

                }

            CallDispose(dst, src);

            return true;
        }