static SignedColor CalculateError(SignedColor delta, int x, int y, DitherPattern pattern) { if (y == 0) { x--; } else { x -= pattern.KernelMinX; } int mul = pattern.Kernel[y][x]; if (mul == 0) { return(new SignedColor()); } else { int div = pattern.Divisor; SignedColor c = new SignedColor(); c.R = (delta.R * mul) / div; c.G = (delta.G * mul) / div; c.B = (delta.B * mul) / div; c.A = (delta.A * mul) / div; return(c); } }
public Color Dither(int x, int y, Color c, DitherPattern pattern) { // Get the existing error at this pixel SignedColor e = GetError(x, y); // Get the quantized color Color q = QuantizeColor(c, e); // Calculate the difference SignedColor delta = Diff(c, q); // Kernel may be zero size (so we should ignore it) if (pattern.KernelHeight > 0) { // First row handled differently for (int i = 1; i <= pattern.KernelMaxX; ++i) { AddError(x + i, y, CalculateError(delta, i, 0, pattern)); } // Process subsequent rows for (int j = 1; j < pattern.KernelHeight; ++j) { for (int i = pattern.KernelMinX; i <= pattern.KernelMaxX; ++i) { AddError(x + i, y + j, CalculateError(delta, i, j, pattern)); } } } _totalError += delta.RGBError; return(q); }
static float DitherOneImage(Bitmap srcData, Bitmap dstData, DitherPattern pattern, Color transparentColorKey) { Ditherer ditherer = new Ditherer(srcData.Width, srcData.Height); for (int x = 0; x < srcData.Width; x++) { for (int y = 0; y < srcData.Height; y++) { Color c = srcData.GetPixel(x, y); if (c == transparentColorKey || c.A == 0) { dstData.SetPixel(x, y, Color.FromArgb(0)); } else { dstData.SetPixel(x, y, ditherer.Dither(x, y, c, pattern)); } } } return(ditherer.RootMeanSquaredError); }
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(); ImageUtils.GrayScale(ref tmp); if (fStretch) ImageUtils.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] = ImageUtils.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; }