public static SimpleColor Grayscale(SimpleColor clr) { // Calculates weighted average from the color components var c = (clr.R * 11 + clr.G * 59 + clr.B * 30) / 100; return(new SimpleColor(c, c, c)); }
// -------------------------------------------------------------------------- // Section 14.2.5 Parallelizing the application // Listing 14.17 Applying color filter in parallel public static SimpleColor[,] RunFilterParallel (this SimpleColor[,] arr, Func <SimpleColor, SimpleColor> f) { int hgt = arr.GetLength(0), wid = arr.GetLength(1); var res = new SimpleColor[hgt, wid]; // Parallelize the outer loop Parallel.For(0, hgt, y => { // Leave inner loop sequential for (int x = 0; x < wid; x++) { res[y, x] = f(arr[y, x]); } }); return(res); }
// Listing 14.11 Sequential method for applying filters (C#) public static SimpleColor[,] RunFilter (this SimpleColor[,] arr, Func <SimpleColor, SimpleColor> f) { int hgt = arr.GetLength(0), wid = arr.GetLength(1); // Create a new array as the result var res = new SimpleColor[hgt, wid]; // Calculate new color for every pixel for (int y = 0; y < hgt; y++) { for (int x = 0; x < wid; x++) { res[y, x] = f(arr[y, x]); } } return(res); }
// Convert bitmap to an array public static SimpleColor[,] ToArray2D(this Bitmap bmp) { var rect = new Rectangle(0, 0, bmp.Width, bmp.Height); var bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); var ptr0 = bmpData.Scan0; var stride = bmpData.Stride; var res = new SimpleColor[bmp.Width, bmp.Height]; int width = bmp.Width; int height = bmp.Height; for (int y = 0; y < width; y++) { for(int x = 0; x < height; x++) { var offset = y*4 + stride*x; var clr = Color.FromArgb(System.Runtime.InteropServices.Marshal.ReadInt32(ptr0,offset)); res[y,x] = new SimpleColor(clr.R, clr.G, clr.B); } } bmp.UnlockBits(bmpData); return res; }
// Convert bitmap to an array public static SimpleColor[,] ToArray2D(this Bitmap bmp) { var rect = new Rectangle(0, 0, bmp.Width, bmp.Height); var bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); var ptr0 = bmpData.Scan0; var stride = bmpData.Stride; var res = new SimpleColor[bmp.Width, bmp.Height]; int width = bmp.Width; int height = bmp.Height; for (int y = 0; y < width; y++) { for (int x = 0; x < height; x++) { var offset = y * 4 + stride * x; var clr = Color.FromArgb(System.Runtime.InteropServices.Marshal.ReadInt32(ptr0, offset)); res[y, x] = new SimpleColor(clr.R, clr.G, clr.B); } } bmp.UnlockBits(bmpData); return(res); }
// Get pixel color after applying effect to the specified input public static SimpleColor[,] Blur(SimpleColor[,] arr, bool parallel) { int hgt = arr.GetLength(0), wid = arr.GetLength(1); var res = new SimpleColor[hgt, wid]; // The outer for loop can be parallelized, depending on the argument RunForLoop(parallel, 0, hgt, y => { // Leave inner loop sequential for (int x = 0; x < wid; x++) { // Sum colors close to the specified location var sum = SimpleColor.Zero; for (int dy = -2; dy <= 2; dy++) { for (int dx = -2; dx <= 2; dx++) { sum += CheckedRead(arr, y + dy, x + dx, hgt, wid); } } res[y, x] = sum / 25; } }); return(res); }
// Get pixel color after applying effect to the specified input public static SimpleColor[,] Blur(SimpleColor[,] arr, bool parallel) { int hgt = arr.GetLength(0), wid = arr.GetLength(1); var res = new SimpleColor[hgt, wid]; // The outer for loop can be parallelized, depending on the argument RunForLoop(parallel, 0, hgt, y => { // Leave inner loop sequential for (int x = 0; x < wid; x++) { // Sum colors close to the specified location var sum = SimpleColor.Zero; for (int dy = -2; dy <= 2; dy++) for (int dx = -2; dx <= 2; dx++) sum += CheckedRead(arr, y + dy, x + dx, hgt, wid); res[y, x] = sum / 25; } }); return res; }
// -------------------------------------------------------------------------- // Section 14.2.5 Parallelizing the application // Listing 14.17 Applying color filter in parallel public static SimpleColor[,] RunFilterParallel(this SimpleColor[,] arr, Func<SimpleColor, SimpleColor> f) { int hgt = arr.GetLength(0), wid = arr.GetLength(1); var res = new SimpleColor[hgt, wid]; // Parallelize the outer loop Parallel.For(0, hgt, y => { // Leave inner loop sequential for(int x = 0; x < wid; x++) res[y, x] = f(arr[y, x]); }); return res; }
// Listing 14.11 Sequential method for applying filters (C#) public static SimpleColor[,] RunFilter(this SimpleColor[,] arr, Func<SimpleColor, SimpleColor> f) { int hgt = arr.GetLength(0), wid = arr.GetLength(1); // Create a new array as the result var res = new SimpleColor[hgt, wid]; // Calculate new color for every pixel for (int y = 0; y < hgt; y++) for(int x = 0; x < wid; x++) res[y, x] = f(arr[y, x]); return res; }
public static SimpleColor Lighten(SimpleColor clr) { // Lighten the color an make sure it is valid return (clr * 2).ClipColor(); }
public static SimpleColor Grayscale(SimpleColor clr) { // Calculates weighted average from the color components var c = (clr.R*11 + clr.G*59 + clr.B*30) / 100; return new SimpleColor(c, c, c); }
// -------------------------------------------------------------------------- // BONUS: Sample graphical effect // Implements 'Blur' effect, which cannot be created using color filters // Read color at the specified location, but check bounds of the bitmap private static SimpleColor CheckedRead(SimpleColor[,] arr, int y, int x, int hgt, int wid) { return arr[Math.Max(0, Math.Min(hgt - 1, y)), Math.Max(0, Math.Min(wid - 1, x))]; }
// Sequential version of the blur effect public static SimpleColor[,] SequentialBlur(SimpleColor[,] arr) { return Blur(arr, false); }
// Parallelized version of the blur effect public static SimpleColor[,] ParallelBlur(SimpleColor[,] arr) { return Blur(arr, true); }
public static SimpleColor Lighten(SimpleColor clr) { // Lighten the color an make sure it is valid return((clr * 2).ClipColor()); }