在对Bitmap图片操作的时候,有时需要用到获取或设置像素颜色方法:GetPixel 和 SetPixel,
如果直接对这两个方法进行操作的话速度很慢,这里我们可以通过把数据提取出来操作,然后操作完在复制回去可以加快访问速度
其实对Bitmap的访问还有两种方式,一种是内存法,一种是指针法
1、内存法
这里定义一个类LockBitmap,通过把Bitmap数据拷贝出来,在内存上直接操作,操作完成后在拷贝到Bitmap中
1 public class LockBitmap 2 { 3 Bitmap source = null; 4 IntPtr Iptr = IntPtr.Zero; 5 BitmapData bitmapData = null; 6
7 public byte[] Pixels { get; set; } 8 public int Depth { get; private set; } 9 public int Width { get; private set; } 10 public int Height { get; private set; } 11
12 public LockBitmap(Bitmap source) 13 { 14 this.source = source; 15 } 16
17 /// <summary>
18 /// Lock bitmap data 19 /// </summary>
20 public void LockBits() 21 { 22 try
23 { 24 // Get width and height of bitmap
25 Width = source.Width; 26 Height = source.Height; 27
28 // get total locked pixels count
29 int PixelCount = Width * Height; 30
31 // Create rectangle to lock
32 Rectangle rect = new Rectangle(0, 0, Width, Height); 33
34 // get source bitmap pixel format size
35 Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat); 36
37 // Check if bpp (Bits Per Pixel) is 8, 24, or 32
38 if (Depth != 8 && Depth != 24 && Depth != 32) 39 { 40 throw new ArgumentException("Only 8, 24 and 32 bpp images are supported."); 41 } 42
43 // Lock bitmap and return bitmap data
44 bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite, 45 source.PixelFormat); 46
47 // create byte array to copy pixel values
48 int step = Depth / 8; 49 Pixels = new byte[PixelCount * step]; 50 Iptr = bitmapData.Scan0; 51
52 // Copy data from pointer to array
53 Marshal.Copy(Iptr, Pixels, 0, Pixels.Length); 54 } 55 catch (Exception ex) 56 { 57 throw ex; 58 } 59 } 60
61 /// <summary>
62 /// Unlock bitmap data 63 /// </summary>
64 public void UnlockBits() 65 { 66 try
67 { 68 // Copy data from byte array to pointer
69 Marshal.Copy(Pixels, 0, Iptr, Pixels.Length); 70
71 // Unlock bitmap data
72 source.UnlockBits(bitmapData); 73 } 74 catch (Exception ex) 75 { 76 throw ex; 77 } 78 } 79
80 /// <summary>
81 /// Get the color of the specified pixel 82 /// </summary>
83 /// <param name="x"></param>
84 /// <param name="y"></param>
85 /// <returns></returns>
86 public Color GetPixel(int x, int y) 87 { 88 Color clr = Color.Empty; 89
90 // Get color components count
91 int cCount = Depth / 8; 92
93 // Get start index of the specified pixel
94 int i = ((y * Width) + x) * cCount; 95
96 if (i > Pixels.Length - cCount) 97 throw new IndexOutOfRangeException(); 98
99 if (Depth == 32) // For 32 bpp get Red, Green, Blue and Alpha
100 { 101 byte b = Pixels[i]; 102 byte g = Pixels[i + 1]; 103 byte r = Pixels[i + 2]; 104 byte a = Pixels[i + 3]; // a
105 clr = Color.FromArgb(a, r, g, b); 106 } 107 if (Depth == 24) // For 24 bpp get Red, Green and Blue
108 { 109 byte b = Pixels[i]; 110 byte g = Pixels[i + 1]; 111 byte r = Pixels[i + 2]; 112 clr = Color.FromArgb(r, g, b); 113 } 114 if (Depth == 8) 115 // For 8 bpp get color value (Red, Green and Blue values are the same)
116 { 117 byte c = Pixels[i]; 118 clr = Color.FromArgb(c, c, c); 119 } 120 return clr; 121 } 122
123 /// <summary>
124 /// Set the color of the specified pixel 125 /// </summary>
126 /// <param name="x"></param>
127 /// <param name="y"></param>
128 /// <param name="color"></param>
129 public void SetPixel(int x, int y, Color color) 130 { 131 // Get color components count
132 int cCount = Depth / 8; 133
134 // Get start index of the specified pixel
135 int i = ((y * Width) + x) * cCount; 136
137 if (Depth == 32) // For 32 bpp set Red, Green, Blue and Alpha
138 { 139 Pixels[i] = color.B; 140 Pixels[i + 1] = color.G; 141 Pixels[i + 2] = color.R; 142 Pixels[i + 3] = color.A; 143 } 144 if (Depth == 24) // For 24 bpp set Red, Green and Blue
145 { 146 Pixels[i] = color.B; 147 Pixels[i + 1] = color.G; 148 Pixels[i + 2] = color.R; 149 } 150 if (Depth == 8) 151 // For 8 bpp set color value (Red, Green and Blue values are the same)
152 { 153 Pixels[i] = color.B; 154 } 155 } 156 }
使用:先锁定Bitmap,然后通过Pixels操作颜色对象,最后释放锁,把数据更新到Bitmap中
1 string file = @"C:\test.jpg"; 2 Bitmap bmp = new Bitmap(Image.FromFile(file)); 3
4 LockBitmap lockbmp = new LockBitmap(bmp); 5 //锁定Bitmap,通过Pixel访问颜色
6 lockbmp.LockBits(); 7
8 //获取颜色
9 Color color = lockbmp.GetPixel(10, 10); 10
11 //从内存解锁Bitmap
12 lockbmp.UnlockBits();
2、指针法
这种方法访问速度比内存法更快,直接通过指针对内存进行操作,不需要进行拷贝,但是在C#中直接通过指针操作内存是不安全的,所以需要在代码中加入unsafe关键字,在生成选项中把允许不安全代码勾上,才能编译通过
这里定义成PointerBitmap类
1 public class PointBitmap 2 { 3 Bitmap source = null; 4 IntPtr Iptr = IntPtr.Zero; 5 BitmapData bitmapData = null; 6
7 public int Depth { get; private set; } 8 public int Width { get; private set; } 9 public int Height { get; private set; } 10
11 public PointBitmap(Bitmap source) 12 { 13 this.source = source; 14 } 15
16 public void LockBits() 17 { 18 try
19 { 20 // Get width and height of bitmap
21 Width = source.Width; 22 Height = source.Height; 23
24 // get total locked pixels count
25 int PixelCount = Width * Height; 26
27 // Create rectangle to lock
28 Rectangle rect = new Rectangle(0, 0, Width, Height); 29
30 // get source bitmap pixel format size
31 Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat); 32
33 // Check if bpp (Bits Per Pixel) is 8, 24, or 32
34 if (Depth != 8 && Depth != 24 && Depth != 32) 35 { 36 throw new ArgumentException("Only 8, 24 and 32 bpp images are supported."); 37 } 38
39 // Lock bitmap and return bitmap data
40 bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite, 41 source.PixelFormat); 42
43 //得到首地址
44 unsafe
45 { 46 Iptr = bitmapData.Scan0; 47 //二维图像循环
48
49 } 50 } 51 catch (Exception ex) 52 { 53 throw ex; 54 } 55 } 56
57 public void UnlockBits() 58 { 59 try
60 { 61 source.UnlockBits(bitmapData); 62 } 63 catch (Exception ex) 64 { 65 throw ex; 66 } 67 } 68
69 public Color GetPixel(int x, int y) 70 { 71 unsafe
72 { 73 byte* ptr = (byte*)Iptr; 74 ptr = ptr + bitmapData.Stride * y; 75 ptr += Depth * x / 8; 76 Color c = Color.Empty; 77 if (Depth == 32) 78 { 79 int a = ptr[3]; 80 int r = ptr[2]; 81 int g = ptr[1]; 82 int b = ptr[0]; 83 c = Color.FromArgb(a, r, g, b); 84 } 85 else if (Depth == 24) 86 { 87 int r = ptr[2]; 88 int g = ptr[1]; 89 int b = ptr[0]; 90 c = Color.FromArgb(r, g, b); 91 } 92 else if (Depth == 8) 93 { 94 int r = ptr[0]; 95 c = Color.FromArgb(r, r, r); 96 } 97 return c; 98 } 99 } 100
101 public void SetPixel(int x, int y, Color c) 102 { 103 unsafe
104 { 105 byte* ptr = (byte*)Iptr; 106 ptr = ptr + bitmapData.Stride * y; 107 ptr += Depth * x / 8; 108 if (Depth == 32) 109 { 110 ptr[3] = c.A; 111 ptr[2] = c.R; 112 ptr[1] = c.G; 113 ptr[0] = c.B; 114 } 115 else if (Depth == 24) 116 { 117 ptr[2] = c.R; 118 ptr[1] = c.G; 119 ptr[0] = c.B; 120 } 121 else if (Depth == 8) 122 { 123 ptr[2] = c.R; 124 ptr[1] = c.G; 125 ptr[0] = c.B; 126 } 127 } 128 } 129 }
使用方法这里就不列出来了,跟上面的LockBitmap类似