/// <summary> /// Applies this filter in a given circular area of the given FastBitmapArray. /// </summary> /// <param name="array"></param> /// <param name="point"></param> /// <param name="diameter"></param> /// <param name="mask"></param> protected void PaintCircle(FastBitmapArray array, Point point, int diameter, bool[][] mask) { int centerX = (int)point.X; int centerY = (int)point.Y; double radius = diameter / 2; int x = centerX - (int)radius; int y = centerY - (int)radius; int xEnd = x + diameter; int yEnd = y + diameter; bool inBounds = false; array.SetBatchArea(x, y, xEnd - 1, yEnd - 1); for (int i = x; i < xEnd; i++) { for (int j = y; j < yEnd; j++) { inBounds = i >= 0 && i < array.Width && j >= 0 && j < array.Height && (i - centerX) * (i - centerX) + (j - centerY) * (j - centerY) <= radius * radius; if (inBounds && mask[i][j]) { FilterWithCorrection(array, i, j); mask[i][j] = false; } } } }
/// <summary> /// Applies this filter in a given rectangular area of the given FastBitmapArray. /// </summary> /// <param name="array"></param> /// <param name="point"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="mask"></param> protected void PaintRect(FastBitmapArray array, Point point, int width, int height, bool[][] mask) { int x = (int)point.X; int y = (int)point.Y; int xEnd = x + width; int yEnd = y + height; bool inBounds = false; array.SetBatchArea(x, y, xEnd - 1, yEnd - 1); for (int i = x; i < xEnd; i++) { for (int j = y; j < yEnd; j++) { inBounds = i >= 0 && i < array.Width && j >= 0 && j < array.Height; if (inBounds && mask[i][j]) { FilterWithCorrection(array, i, j); mask[i][j] = false; } } } }
public FastBitmapArray Process(FastBitmapArray array, ErrorDiffusionKernelName kernelName, int levelsCount) { if (levelsCount < 2) { throw new ArgumentException("at least 2 levels are needed"); } var processed = new FastBitmapArray(array.Width, array.Height); int levelsCountLess = levelsCount - 1; double[] levels = new double[levelsCount]; // upper bounds for all levels (except for the last level, cos this one is always 1.0) double[] levelsBounds = new double[levelsCountLess]; for (int i = 0; i < levelsCount; ++i) { levels[i] = ((double)i) / levelsCountLess; if (i > 0) { levelsBounds[i - 1] = (levels[i - 1] + levels[i]) / 2; } } var matrix = Matrices[kernelName]; var matrixSum = MatricesSums[kernelName]; var matrixWidth = matrix[0].Length; var matrixHeight = matrix.Length; var currentPixelX = (matrixWidth - 1) / 2; for (int y = 0; y < array.Height; ++y) { for (int x = 0; x < array.Width; ++x) { // get color value double red = array.GetRed(x, y); double green = array.GetGreen(x, y); double blue = array.GetBlue(x, y); // add error accumulated from previous pixels red += processed.GetRed(x, y); green += processed.GetGreen(x, y); blue += processed.GetBlue(x, y); // approximate double redApprox = levels[levelsCountLess]; for (int i = 0; i < levelsCountLess; ++i) { if (red < levelsBounds[i]) { redApprox = levels[i]; break; } } double greenApprox = levels[levelsCountLess]; for (int i = 0; i < levelsCountLess; ++i) { if (green < levelsBounds[i]) { greenApprox = levels[i]; break; } } double blueApprox = levels[levelsCountLess]; for (int i = 0; i < levelsCountLess; ++i) { if (blue < levelsBounds[i]) { blueApprox = levels[i]; break; } } // calculate error double redError = red - redApprox; double greenError = green - greenApprox; double blueError = blue - blueApprox; // set current pixel value processed.SetRedBatch(x, y, redApprox); processed.SetGreenBatch(x, y, greenApprox); processed.SetBlueBatch(x, y, blueApprox); // diffuse the arror accross other pixels for (int xx = 0; xx < matrixWidth; ++xx) { for (int yy = 0; yy < matrixHeight; ++yy) { if (yy == 0 && xx <= currentPixelX) { continue; } int xxx = x + xx - currentPixelX; int yyy = y + yy; if (xxx < 0 || xxx >= array.Width || yyy >= array.Height) { continue; } double level = ((double)matrix[yy][xx]) / matrixSum; processed.SetRedBatch(xxx, yyy, processed.GetRed(xxx, yyy) + redError * level); processed.SetGreenBatch(xxx, yyy, processed.GetGreen(xxx, yyy) + greenError * level); processed.SetBlueBatch(xxx, yyy, processed.GetBlue(xxx, yyy) + blueError * level); } } } } processed.SetBatchArea(); return(processed); }
/// <summary> /// Processes the input array. /// </summary> /// <param name="array"></param> /// <param name="matrixSize"></param> /// <returns></returns> public FastBitmapArray Process(FastBitmapArray array, int matrixSize, int levelsCount) { #region old approach //var processed = new FastBitmapArray(array.Width * matrixSize, array.Height * matrixSize); //int procXmin = 0; //int procXmax = 0; //int procYmin = 0; //int procYmax = 0; //var matrix = Matrices[matrixSize]; //var matrixCoef = matrixSize * matrixSize + 1; //for (int x = 0; x < array.Width; ++x) //{ // procXmin = x * matrixSize; // procXmax = procXmin + matrixSize; // for (int y = 0; y < array.Height; ++y) // { // double red = array.GetRed(x, y); // double green = array.GetGreen(x, y); // double blue = array.GetBlue(x, y); // procYmin = y * matrixSize; // procYmax = procYmin + matrixSize; // for (int xx = procXmin, xxx = 0; xx < procXmax; ++xx, ++xxx) // for (int yy = procYmin, yyy = 0; yy < procYmax; ++yy, ++yyy) // { // double matrixValue = ((double)matrix[xxx][yyy]) / matrixCoef; // processed.SetRed(xx, yy, red > matrixValue ? 1 : 0); // processed.SetGreen(xx, yy, green > matrixValue ? 1 : 0); // processed.SetBlue(xx, yy, blue > matrixValue ? 1 : 0); // } // } //} #endregion // new approach: var processed = new FastBitmapArray(array.Width, array.Height); int levelsCountLess = levelsCount - 1; var matrix = Matrices[matrixSize]; var matrixCoef = matrixSize * matrixSize + 1; double matrixLevel = 1.0 / levelsCountLess; double[] levels = new double[levelsCount]; // upper bounds for all levels (except for the last level, cos this one is always 1.0) double[] levelsBounds = new double[levelsCountLess]; for (int i = 0; i < levelsCount; ++i) { levels[i] = ((double)i) / levelsCountLess; if (i > 0) { levelsBounds[i - 1] = (levels[i - 1] + levels[i]) / 2; } if (i > 0 && i < levelsCount - 1) { levels[i] += 0.5 / (levelsCountLess * (matrixCoef - 1) + 1); } } int matrixX = 0; int matrixY = 0; for (int x = 0; x < array.Width; ++x) { for (int y = 0; y < array.Height; ++y) { double matrixValue = matrixLevel * ((double)matrix[matrixY][matrixX]) / matrixCoef; double red = array.GetRed(x, y); double green = array.GetGreen(x, y); double blue = array.GetBlue(x, y); // approximation double redApprox = processOnePixel(red, levels, levelsBounds, levelsCountLess, matrixValue); double greenApprox = processOnePixel(green, levels, levelsBounds, levelsCountLess, matrixValue); double blueApprox = processOnePixel(blue, levels, levelsBounds, levelsCountLess, matrixValue); processed.SetRedBatch(x, y, redApprox); processed.SetGreenBatch(x, y, greenApprox); processed.SetBlueBatch(x, y, blueApprox); ++matrixY; if (matrixY == matrixSize) { matrixY = 0; } } ++matrixX; if (matrixX == matrixSize) { matrixX = 0; } } processed.SetBatchArea(); return(processed); }
private void OptionGeneratePalette_Click(object sender, RoutedEventArgs e) { bitmapArray = new FastBitmapArray((int)DrawingScrollView.ViewportWidth, (int)DrawingScrollView.ViewportHeight); bitmapArrayWithoutLines = null; bitmapArray.SetBatchArea(0, 0, bitmapArray.Width - 1, bitmapArray.Height - 1); double xJump = 1.0 / bitmapArray.Width; int ySegment = bitmapArray.Height / (1 + 3 + 3 + 3 + 3); //double xJump = 1.0 / bitmapArray.Width; for (int x = 0; x < bitmapArray.Width; ++x) { int y = 0; int yMax = ySegment; for (; y < yMax; ++y) { bitmapArray.SetRedBatch(x, y, x * xJump); bitmapArray.SetGreenBatch(x, y, x * xJump); bitmapArray.SetBlueBatch(x, y, x * xJump); } yMax += ySegment; for (; y < yMax; ++y) { bitmapArray.SetRedBatch(x, y, x * xJump); } yMax += ySegment; for (; y < yMax; ++y) { bitmapArray.SetGreenBatch(x, y, x * xJump); } yMax += ySegment; for (; y < yMax; ++y) { bitmapArray.SetBlueBatch(x, y, x * xJump); } yMax += ySegment; for (; y < yMax; ++y) { bitmapArray.SetRedBatch(x, y, x * xJump); bitmapArray.SetGreenBatch(x, y, x * xJump); //bitmapArray.SetBlueBatch(x, y, x * xJump); } yMax += ySegment; for (; y < yMax; ++y) { //bitmapArray.SetRedBatch(x, y, x * xJump); bitmapArray.SetGreenBatch(x, y, x * xJump); bitmapArray.SetBlueBatch(x, y, x * xJump); } yMax += ySegment; for (; y < yMax; ++y) { bitmapArray.SetRedBatch(x, y, x * xJump); //bitmapArray.SetGreenBatch(x, y, x * xJump); bitmapArray.SetBlueBatch(x, y, x * xJump); } yMax += ySegment; for (; y < yMax; ++y) { bitmapArray.SetRedBatch(x, y, x * xJump); bitmapArray.SetGreenBatch(x, y, 1); bitmapArray.SetBlueBatch(x, y, 1); } yMax += ySegment; for (; y < yMax; ++y) { bitmapArray.SetRedBatch(x, y, 1); bitmapArray.SetGreenBatch(x, y, x * xJump); bitmapArray.SetBlueBatch(x, y, 1); } yMax += ySegment; for (; y < yMax; ++y) { bitmapArray.SetRedBatch(x, y, 1); bitmapArray.SetGreenBatch(x, y, 1); bitmapArray.SetBlueBatch(x, y, x * xJump); } yMax += ySegment; for (; y < yMax; ++y) { bitmapArray.SetRedBatch(x, y, x * xJump); bitmapArray.SetGreenBatch(x, y, x * xJump); bitmapArray.SetBlueBatch(x, y, 1); } yMax += ySegment; for (; y < yMax; ++y) { bitmapArray.SetRedBatch(x, y, 1); bitmapArray.SetGreenBatch(x, y, x * xJump); bitmapArray.SetBlueBatch(x, y, x * xJump); } yMax += ySegment; for (; y < yMax; ++y) { bitmapArray.SetRedBatch(x, y, x * xJump); bitmapArray.SetGreenBatch(x, y, 1); bitmapArray.SetBlueBatch(x, y, x * xJump); } } DrawingImage.Source = bitmapArray.GetBitmap(Mask.Disabled); DrawingImage.Width = bitmapArray.Width; DrawingImage.Height = bitmapArray.Height; ReinitializeMask(); if (latestFileName != null) { latestFileName = null; OptionReload.IsEnabled = false; } }