private void LoadImage(WriteableBitmap bitmap) { if (bitmap.PixelWidth != 0 && bitmap.PixelHeight != 0) { this.loadedBitmap = bitmap; SketchGenTaskData task_data = new SketchGenTaskData(); task_data.radius = this.gaussianRadius; task_data.width = bitmap.PixelWidth; task_data.height = bitmap.PixelHeight; task_data.pixels = bitmap.Pixels; this.sketchGeneratorWorker.RunWorkerAsync(task_data); this.GenerationProgressIndicator.IsVisible = true; } }
private void StartSketchGenerator() { if (this.scaledBitmap != null) { try { SketchGenTaskData task_data = new SketchGenTaskData(); task_data.radius = this.gaussianRadius; task_data.width = this.scaledBitmap.PixelWidth; task_data.height = this.scaledBitmap.PixelHeight; task_data.pixels = this.scaledBitmap.Pixels; this.sketchGeneratorWorker.RunWorkerAsync(task_data); this.GenerationProgressIndicator.IsVisible = true; } catch (Exception) { // Ignore } } }
private void sketchGeneratorWorker_DoWork(object sender, DoWorkEventArgs e) { int radius = (e.Argument as SketchGenTaskData).radius; int width = (e.Argument as SketchGenTaskData).width; int height = (e.Argument as SketchGenTaskData).height; int[] pixels = (e.Argument as SketchGenTaskData).pixels; // Make Gaussian blur of original image int[] sketch_pixels = pixels.Clone() as int[]; int[] tab = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius - 1]; int r1 = 0; int r2 = height - 1; int c1 = 0; int c2 = width - 1; int[] rgba = new int[4]; for (int col = c1; col <= c2; col++) { int s = r1 * width + col; for (int i = 0; i < 4; i++) { rgba[i] = ((sketch_pixels[s] >> (i * 8)) & 0xFF) << 4; } s += width; for (int j = r1; j < r2; j++, s += width) { int p = 0; for (int i = 0; i < 4; i++) { p = p | ((((rgba[i] += ((((sketch_pixels[s] >> (i * 8)) & 0xFF) << 4) - rgba[i]) * alpha / 16) >> 4) & 0xFF) << (i * 8)); } sketch_pixels[s] = p; } } for (int row = r1; row <= r2; row++) { int s = row * width + c1; for (int i = 0; i < 4; i++) { rgba[i] = ((sketch_pixels[s] >> (i * 8)) & 0xFF) << 4; } s++; for (int j = c1; j < c2; j++, s++) { int p = 0; for (int i = 0; i < 4; i++) { p = p | ((((rgba[i] += ((((sketch_pixels[s] >> (i * 8)) & 0xFF) << 4) - rgba[i]) * alpha / 16) >> 4) & 0xFF) << (i * 8)); } sketch_pixels[s] = p; } } for (int col = c1; col <= c2; col++) { int s = r2 * width + col; for (int i = 0; i < 4; i++) { rgba[i] = ((sketch_pixels[s] >> (i * 8)) & 0xFF) << 4; } s -= width; for (int j = r1; j < r2; j++, s -= width) { int p = 0; for (int i = 0; i < 4; i++) { p = p | ((((rgba[i] += ((((sketch_pixels[s] >> (i * 8)) & 0xFF) << 4) - rgba[i]) * alpha / 16) >> 4) & 0xFF) << (i * 8)); } sketch_pixels[s] = p; } } for (int row = r1; row <= r2; row++) { int s = row * width + c2; for (int i = 0; i < 4; i++) { rgba[i] = ((sketch_pixels[s] >> (i * 8)) & 0xFF) << 4; } s--; for (int j = c1; j < c2; j++, s--) { int p = 0; for (int i = 0; i < 4; i++) { p = p | ((((rgba[i] += ((((sketch_pixels[s] >> (i * 8)) & 0xFF) << 4) - rgba[i]) * alpha / 16) >> 4) & 0xFF) << (i * 8)); } sketch_pixels[s] = p; } } // Make grayscale image from original image, inverted grayscale image from blurred image // Then apply Color Dodge mixing for sketch int[] grayscale_pixels = pixels.Clone() as int[]; for (int i = 0; i < sketch_pixels.Length; i++) { byte[] b_color = BitConverter.GetBytes(sketch_pixels[i]); byte[] g_color = BitConverter.GetBytes(grayscale_pixels[i]); byte top_gray = (byte)(255 - (byte)((b_color[0] * 11 + b_color[1] * 16 + b_color[2] * 5) / 32)); byte btm_gray = (byte)((g_color[0] * 11 + g_color[1] * 16 + g_color[2] * 5) / 32); byte res_gray = (byte)(top_gray >= 255 ? 255 : Math.Min(btm_gray * 255 / (255 - top_gray), 255)); sketch_pixels[i] = (b_color[3] << 24) | (res_gray << 16) | (res_gray << 8) | res_gray; } SketchGenTaskData task_data = new SketchGenTaskData(); task_data.radius = radius; task_data.width = width; task_data.height = height; task_data.pixels = sketch_pixels; e.Result = task_data; }