在绘图过程中,可能存在局部绘制,需要把一个图片区域块 copy 到另一图形内部。
针对常用的几种操作方式对比。
本次比较对象为 BitBlt 与 LockBits 方式
BitBlt 实现:
private void SnapShot(Bitmap des, Bitmap bitmapsrc) { IntPtr dc; IntPtr dc1; IntPtr dcbitmap; Graphics g; //绘制目标区域 Graphics g1 = System.Drawing.Graphics.FromImage(des); dc1 = g1.GetHdc(); //源图与设备关联 g = System.Drawing.Graphics.FromImage(bitmapsrc); dc = CreateCompatibleDC(g.GetHdc()); IntPtr pOrig = SelectObject(dc, dcbitmap = bitmapsrc.GetHbitmap()); for (int i = 0; i < redraw; i++) BitBlt(dc1, 0, 0, bitmapsrc.Width, bitmapsrc.Height, dc, 0, 0, TernaryRasterOperations.SRCCOPY); DeleteDC(dc); DeleteObject(dcbitmap); g1.ReleaseHdc(dc1); g1.Dispose(); }
调用代码:
private void button4_Click(object sender, EventArgs e) { Bitmap bitmapCopy = new Bitmap(bitmap.Width, bitmap.Height); System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); stopWatch.Start(); SnapShot(bitmapCopy, bitmap); stopWatch.Stop(); Console.WriteLine("bitblt 时间刻度:{0} {1}ms", stopWatch.ElapsedTicks, stopWatch.ElapsedMilliseconds); bitmapCopy.Save(@"C:\Users\zhoupeng\Pictures\testbitblt.jpg", System.Drawing.Imaging.ImageFormat.Jpeg); }
LockBits 方式实现:
private void CopyImage(Bitmap des, Bitmap bitmapsrc) { Rectangle rect = new Rectangle(0, 0, des.Width, des.Height); System.Drawing.Imaging.BitmapData bmpData = des.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmapsrc.PixelFormat); System.Drawing.Imaging.BitmapData bmpDataSrc = bitmapsrc.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmapsrc.PixelFormat); unsafe { for (int j = 0; j < redraw; j++) { byte* ptrdes = (byte*)bmpData.Scan0; byte* ptrsrc = (byte*)bmpDataSrc.Scan0; int width = bmpDataSrc.Stride; for (int i = 0; i < rect.Height; i++) { for (int l = 0; l < width; l++) { ptrdes[l] = ptrsrc[l]; } ptrdes += width; ptrsrc += width; } } } bitmapsrc.UnlockBits(bmpDataSrc); des.UnlockBits(bmpData); }
LockBits 方式 调用:
private void button5_Click(object sender, EventArgs e) { Bitmap bitmapCopy = new Bitmap(bitmap.Width, bitmap.Height); System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); stopWatch.Start(); CopyImage(bitmapCopy, bitmap); stopWatch.Stop(); Console.WriteLine("bit copy 时间刻度:{0} {1}ms", stopWatch.ElapsedTicks, stopWatch.ElapsedMilliseconds); bitmapCopy.Save(@"C:\Users\zhoupeng\Pictures\testbitcopy.jpg", System.Drawing.Imaging.ImageFormat.Bmp); }
由于两种方式 初使化方式不一样,本例尝试乎略这些步骤,这里使用 redraw 变量差异化工作量,分别测试两种性能.
redraw = 1 结果:
bitblt 时间刻度:818184 81ms
bit copy 时间刻度:401926 40ms
redraw = 2 结果:
bitblt 时间刻度:652939 65ms
bit copy 时间刻度:588758 58ms
redraw = 3 结果:
bitblt 时间刻度:689693 68ms
bit copy 时间刻度:804597 80ms
redraw = 5 结果:
bitblt 时间刻度:858016 85ms
bit copy 时间刻度:1196078 119ms
redraw = 15 结果:
bitblt 时间刻度:1062028 106ms
bit copy 时间刻度:3279949 327ms
redraw = 100 结果:
bitblt 时间刻度:1707719 170ms
bit copy 时间刻度:19362181 1936ms