在对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类似