C # accelerate access to Bitmap,
When operating Bitmap images, you sometimes need to use the GetPixel and SetPixel methods to obtain or set the pixel color,
If you directly perform operations on these two methods, the speed is very slow. Here we can extract the data and then copy it back to speed up access.
In fact, there are two ways to access Bitmap: memory method and pointer method.
1. Memory Method
A LockBitmap class is defined here. By copying Bitmap data, you can directly operate on the memory. After the operation is completed, the data is copied to Bitmap.
public class LockBitmap { Bitmap source = null; IntPtr Iptr = IntPtr.Zero; BitmapData bitmapData = null; public byte[] Pixels { get; set; } public int Depth { get; private set; } public int Width { get; private set; } public int Height { get; private set; } public LockBitmap(Bitmap source) { this.source = source; } /// <summary> /// Lock bitmap data /// </summary> public void LockBits() { try { // Get width and height of bitmap Width = source.Width; Height = source.Height; // get total locked pixels count int PixelCount = Width * Height; // Create rectangle to lock Rectangle rect = new Rectangle(0, 0, Width, Height); // get source bitmap pixel format size Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat); // Check if bpp (Bits Per Pixel) is 8, 24, or 32 if (Depth != 8 && Depth != 24 && Depth != 32) { throw new ArgumentException("Only 8, 24 and 32 bpp images are supported."); } // Lock bitmap and return bitmap data bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat); // create byte array to copy pixel values int step = Depth / 8; Pixels = new byte[PixelCount * step]; Iptr = bitmapData.Scan0; // Copy data from pointer to array Marshal.Copy(Iptr, Pixels, 0, Pixels.Length); } catch (Exception ex) { throw ex; } } /// <summary> /// Unlock bitmap data /// </summary> public void UnlockBits() { try { // Copy data from byte array to pointer Marshal.Copy(Pixels, 0, Iptr, Pixels.Length); // Unlock bitmap data source.UnlockBits(bitmapData); } catch (Exception ex) { throw ex; } } /// <summary> /// Get the color of the specified pixel /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public Color GetPixel(int x, int y) { Color clr = Color.Empty; // Get color components count int cCount = Depth / 8; // Get start index of the specified pixel int i = ((y * Width) + x) * cCount; if (i > Pixels.Length - cCount) throw new IndexOutOfRangeException(); if (Depth == 32) // For 32 bpp get Red, Green, Blue and Alpha { byte b = Pixels[i]; byte g = Pixels[i + 1]; byte r = Pixels[i + 2]; byte a = Pixels[i + 3]; // a clr = Color.FromArgb(a, r, g, b); } if (Depth == 24) // For 24 bpp get Red, Green and Blue { byte b = Pixels[i]; byte g = Pixels[i + 1]; byte r = Pixels[i + 2]; clr = Color.FromArgb(r, g, b); } if (Depth == 8) // For 8 bpp get color value (Red, Green and Blue values are the same) { byte c = Pixels[i]; clr = Color.FromArgb(c, c, c); } return clr; } /// <summary> /// Set the color of the specified pixel /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="color"></param> public void SetPixel(int x, int y, Color color) { // Get color components count int cCount = Depth / 8; // Get start index of the specified pixel int i = ((y * Width) + x) * cCount; if (Depth == 32) // For 32 bpp set Red, Green, Blue and Alpha { Pixels[i] = color.B; Pixels[i + 1] = color.G; Pixels[i + 2] = color.R; Pixels[i + 3] = color.A; } if (Depth == 24) // For 24 bpp set Red, Green and Blue { Pixels[i] = color.B; Pixels[i + 1] = color.G; Pixels[i + 2] = color.R; } if (Depth == 8) // For 8 bpp set color value (Red, Green and Blue values are the same) { Pixels[i] = color.B; } } }
Usage: first lock Bitmap, then operate the color object through Pixels, and finally release the lock to update the data to Bitmap.
String file = @ "C: \ test.jpg"; Bitmap bmp = new Bitmap (Image. fromFile (file); LockBitmap lockbmp = new LockBitmap (bmp); // lock Bitmap and access the color lockbmp through Pixel. lockBits (); // obtain the Color color Color = lockbmp. getPixel (10, 10); // unlock Bitmap lockbmp from memory. unlockBits ();
2. pointer Method
In this way, the access speed is faster than the memory method, and the memory is operated directly through the pointer without copying. However, it is not safe to operate the memory directly through the pointer in C, therefore, you need to add the unsafe keyword to the code and check the Insecure code in the generate option to compile and pass
It is defined as the PointerBitmap class.
Public class PointBitmap {Bitmap source = null; IntPtr Iptr = IntPtr. zero; BitmapData bitmapData = null; public int Depth {get; private set;} public int Width {get; private set;} public int Height {get; private set ;} public PointBitmap (Bitmap source) {this. source = source;} public void LockBits () {try {// Get width and height of bitmap Width = source. width; Height = source. height; // get Total locked pixels count int PixelCount = Width * Height; // Create rectangle to lock Rectangle rect = new Rectangle (0, 0, Width, Height ); // get source bitmap pixel format size Depth = System. drawing. bitmap. getPixelFormatSize (source. pixelFormat); // Check if bpp (Bits Per Pixel) is 8, 24, or 32 if (Depth! = 8 & Depth! = 24 & Depth! = 32) {throw new ArgumentException ("Only 8, 24 and 32 bpp images are supported. ");} // Lock bitmap and return bitmap data bitmapData = source. lockBits (rect, ImageLockMode. readWrite, source. pixelFormat); // obtain the first address unsafe {Iptr = bitmapData. scan0; // two-dimensional image loop} catch (Exception ex) {throw ex ;}} public void UnlockBits () {try {source. unlockBits (bitmapData);} catch (Exception ex) {throw ex;} public Color GetPixel (int x, int y) {unsafe {byte * ptr = (byte *) Iptr; ptr = ptr + bitmapData. stride * y; ptr + = Depth * x/8; Color c = Color. empty; if (Depth = 32) {int a = ptr [3]; int r = ptr [2]; int g = ptr [1]; int B = ptr [0]; c = Color. fromArgb (a, r, g, B);} else if (Depth = 24) {int r = ptr [2]; int g = ptr [1]; int B = ptr [0]; c = Color. fromArgb (r, g, B);} else if (Depth = 8) {int r = ptr [0]; c = Color. fromArgb (r, r, r);} return c ;}} public void SetPixel (int x, int y, Color c) {unsafe {byte * ptr = (byte *) iptr; ptr = ptr + bitmapData. stride * y; ptr + = Depth * x/8; if (Depth = 32) {ptr [3] = c. a; ptr [2] = c. r; ptr [1] = c. g; ptr [0] = c. b;} else if (Depth = 24) {ptr [2] = c. r; ptr [1] = c. g; ptr [0] = c. b;} else if (Depth = 8) {ptr [2] = c. r; ptr [1] = c. g; ptr [0] = c. B ;}}}}
The usage is not listed here. It is similar to the LockBitmap above.
Provided by "figure douluo"