public static RasterColor FindClosestColor( RasterColor color, RasterColor[] palette, ColorDifferencingMethod colorDifferencingMethod) { double minDistance = double.MaxValue; var bestIndex = 0; switch (colorDifferencingMethod) { case ColorDifferencingMethod.EuclideanDistance: for (var i = 0; i < palette.Length; i++) { double distance = color.CalculateEuclideanDistance(palette[i]); if (!(distance < minDistance)) { continue; } minDistance = distance; bestIndex = i; } break; case ColorDifferencingMethod.RelativeLuminance601: for (var i = 0; i < palette.Length; i++) { double distance = color.CalculateRelativeLuminance601(palette[i]); if (!(distance < minDistance)) { continue; } minDistance = distance; bestIndex = i; } break; case ColorDifferencingMethod.RelativeLuminance709: for (var i = 0; i < palette.Length; i++) { double distance = color.CalculateRelativeLuminance709(palette[i]); if (!(distance < minDistance)) { continue; } minDistance = distance; bestIndex = i; } break; default: throw new ArgumentOutOfRangeException(nameof(colorDifferencingMethod), colorDifferencingMethod, null); } return(palette[bestIndex]); }
public static RasterImage NoDithering(RasterImage image, RasterColor[] ditheringPalette, ColorDifferencingMethod colorMatching) { int width = image.Width, height = image.Height; int rOffset, bOffset, gOffset; if (image.Order == RasterByteOrder.Bgr) { rOffset = 2; gOffset = 1; bOffset = 0; } else { rOffset = 0; gOffset = 1; bOffset = 2; } byte[] buffer = AllocateImageBytes(image); // Translates the x,y coordinates to a buffer index int CalculateIndex(int x, int y) { return(y * width * (image.BitsPerPixel == 24 ? 3 : 4) + x * (image.BitsPerPixel == 24 ? 3 : 4)); } for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { int index = CalculateIndex(x, y); byte b = buffer[index + bOffset]; byte r = buffer[index + rOffset]; byte g = buffer[index + gOffset]; RasterColor bestColor = FindClosestColor(new RasterColor(r, g, b), ditheringPalette, colorMatching); buffer[index + bOffset] = bestColor.B; buffer[index + rOffset] = bestColor.R; buffer[index + gOffset] = bestColor.G; } } SetImageBytes(image, buffer); return(image); }
public static RasterImage ErrorDiffusionDithering(ErrorDiffusionMatrix matrix, RasterImage image, RasterColor[] ditheringPalette, ColorDifferencingMethod colorMatching) { int width = image.Width, height = image.Height; int rOffset, bOffset, gOffset; if (image.Order == RasterByteOrder.Bgr) { rOffset = 2; gOffset = 1; bOffset = 0; } else { rOffset = 0; gOffset = 1; bOffset = 2; } byte[] buffer = AllocateImageBytes(image); int CalculateIndex(int x, int y) { return(y * width * (image.BitsPerPixel == 24 ? 3 : 4) + x * (image.BitsPerPixel == 24 ? 3 : 4)); } int CalculateError(int error, int numerator, int denominator) { if (error == 0) { return(0); } // fixes problem where for example -5/8==0, but -5>>3 == -1. return((int)Math.Floor((double)error * numerator / denominator)); } void ApplyError(int bx, int by, int[] error, int numerator, int denominator) { int currentIndex = CalculateIndex(bx, by); buffer[currentIndex + bOffset] = AddClamp(buffer[currentIndex + bOffset], CalculateError(error[bOffset], numerator, denominator)); buffer[currentIndex + gOffset] = AddClamp(buffer[currentIndex + gOffset], CalculateError(error[gOffset], numerator, denominator)); buffer[currentIndex + rOffset] = AddClamp(buffer[currentIndex + rOffset], CalculateError(error[rOffset], numerator, denominator)); } for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { int index = CalculateIndex(x, y); byte b = buffer[index + bOffset], r = buffer[index + rOffset], g = buffer[index + gOffset]; var currentPixel = new RasterColor(r, g, b); RasterColor bestColor = FindClosestColor(currentPixel, ditheringPalette, colorMatching); var error = new int[image.BitsPerPixel == 24 ? 3 : 4]; error[rOffset] = r - bestColor.R; error[gOffset] = g - bestColor.G; error[bOffset] = b - bestColor.B; buffer[index + bOffset] = bestColor.B; buffer[index + rOffset] = bestColor.R; buffer[index + gOffset] = bestColor.G; if (matrix?.Cells == null) { continue; } foreach (ErrorDiffusionMatrix.Cell cell in matrix.Cells) { int targetX = x + cell.XOffset, targetY = y + cell.YOffset; if (targetX < 0 || targetX >= image.Width) { continue; } if (targetY < 0 || targetY >= image.Height) { continue; } ApplyError(targetX, targetY, error, cell.Numerator, matrix.Denominator); } } } SetImageBytes(image, buffer); return(image); }