摘自:
作者:Vano Maisuradze
当你在C#中操作bitmaps时,你可以使用 GetPixel(x ,y) 和 SetPixel(x, y, color) 去获取/设置特定像素的值。但是它们十分的慢。
这里有另一种更快的方法去操作bitmaps。
LockBitmap
使用LockBitmap类,我们可以锁定/解锁bitmaps的数据
(PS:这里定义一个类LockBitmap,锁定时把bitmap所有像素的数据拷贝在一个数组上,操作时就是在数组上直接操作,避免了对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 ///
18 /// Lock bitmap data
19 ///
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 }//代码效果参考:http://www.ezhiqi.com/zx/art_5014.html
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 ///
62 /// Unlock bitmap data
63 ///
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 ///
81 /// Get the color of the specified pixel
82 ///
83 ///
84 ///
85 ///
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 ///
124 /// Set the color of the specified pixel
125 ///
126 ///
127 ///
128 ///
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 }
测试方法
我们可以使用Benchmark类去测试LockBitmap的性能。
1 public class Benchmark
2 {
3 private static DateTime startDate = DateTime.MinValue;
4 private static DateTime endDate = DateTime.MinValue;
5
6 public static TimeSpan Span { get { return endDate.Subtract(startDate); } }
7
8 public static void Start() { startDate = DateTime.Now; }
9
10 public static void End() { endDate = DateTime.Now; }
11
12 public static double GetSeconds()
13 {
14 if (endDate == DateTime.MinValue) return 0.0;
15 else return Span.TotalSeconds;
16 }
17 }
使用方法
现在,我们可以使用LockBitmap类非常快地去操作bitmap。
1 public void ChangeColor()
2 {
3 Bitmap bmp = (Bitmap)Image.FromFile(d:\source.png);
4 Benchmark.Start();