一、GDI+双缓冲绘图
BufferedGraphicsContext GraphicsContext = BufferedGraphicsManager.Current;BufferedGraphics myBuffer = GraphicsContext.Allocate(e.Graphics, e.ClipRectangle);Graphics g = myBuffer.Graphics;Bitmap bitmap = bitmaps[index];g.DrawImage(bitmap, 0, 0, pictureBox1.Width, pictureBox1.Height);myBuffer.Render(e.Graphics);g.Dispose();myBuffer.Dispose();
二、 GDI API双缓冲绘图
BufferedGraphicsContext GraphicsContext = BufferedGraphicsManager.Current;BufferedGraphics myBuffer = GraphicsContext.Allocate(e.Graphics, e.ClipRectangle);Graphics g = myBuffer.Graphics;var info = hBitmaps[index];// 调整绘制位置和大小以适应pictureBox1的尺寸int destWidth = pictureBox1.Width;int destHeight = pictureBox1.Height;int srcWidth = info.Widht;int srcHeight = info.Heigth;float scaleX = (float)destWidth / srcWidth;float scaleY = (float)destHeight / srcHeight;float scale = Math.Min(scaleX, scaleY);int width = (int)(srcWidth * scale);int height = (int)(srcHeight * scale);int x = (destWidth - width) >> 1;int y = (destHeight - height) >> 1;// 使用GDI API绘制图像IntPtr hdc = myBuffer.Graphics.GetHdc();IntPtr hBitmap = info.hBitmap;IntPtr hMemDC = GDI32.CreateCompatibleDC(hdc);IntPtr hOldBitmap = GDI32.SelectObject(hMemDC, hBitmap);GDI32.SetStretchBltMode(hdc, GDI32.STRETCH_DELETESCANS);GDI32.StretchBlt(hdc, x, y, width, height, hMemDC, 0, 0, srcWidth, srcHeight, GDI32.SRCCOPY);GDI32.DeleteDC(hOldBitmap);GDI32.DeleteDC(hMemDC);myBuffer.Graphics.ReleaseHdc(hdc);myBuffer.Render(e.Graphics);g.Dispose();myBuffer.Dispose();
public class BitmapInfo{public IntPtr hBitmap { get; set; }public int Widht { get; set; }public int Heigth { get; set; }}
public class GDI32{public const int SRCCOPY = 0x00CC0020;public const int STRETCH_ANDSCANS = 1;// 使用位与运算来处理像素的拉伸。public const int STRETCH_ORSCANS = 2;// 使用位或运算来处理像素的拉伸。public const int STRETCH_DELETESCANS = 3;// 使用位异或运算来处理像素的拉伸。public const int STRETCH_HALFTONE = 4;// 使用半色调算法来处理像素的拉伸,以获得更平滑的结果。/// <summary>/// 创建与当前窗口兼容的HDC2(内存设备上下文)/// </summary>/// <param name="hdc"></param>/// <returns></returns>[DllImport("gdi32.dll")]public static extern IntPtr CreateCompatibleDC(IntPtr hdc);[DllImport("gdi32.dll")]public static extern bool DeleteDC(IntPtr hdc);[DllImport("gdi32.dll")]public static extern bool DeleteObject(IntPtr hObject);/// <summary>/// 每个设备场景都可能有选入其中的图形对象/// </summary>/// <param name="hdc"></param>/// <param name="hObject"></param>/// <returns></returns>[DllImport("gdi32.dll")]public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hObject);/// <summary>/// 将一幅位图从一个设备场景复制到另一个。源和目标DC相互间必须兼容。/// </summary>/// <param name="hdcDest"></param>/// <param name="nXDest"></param>/// <param name="nYDest"></param>/// <param name="nWidth"></param>/// <param name="nHeight"></param>/// <param name="hdcSrc"></param>/// <param name="nXSrc"></param>/// <param name="nYSrc"></param>/// <param name="dwRop"></param>/// <returns></returns>[DllImport("gdi32.dll", SetLastError = true)]public static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight,IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);/// <summary>/// 将一幅位图从一个设备场景复制到另一个/// </summary>/// <param name="hdcDest"></param>/// <param name="nXDest"></param>/// <param name="nYDest"></param>/// <param name="nWidthDest"></param>/// <param name="nHeightDest"></param>/// <param name="hdcSrc"></param>/// <param name="nXSrc"></param>/// <param name="nYSrc"></param>/// <param name="nWidthSrc"></param>/// <param name="nHeightSrc"></param>/// <param name="dwRop"></param>/// <returns></returns>[DllImport("gdi32.dll")]public static extern bool StretchBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidthDest, int nHeightDest, IntPtr hdcSrc, int nXSrc, int nYSrc, int nWidthSrc, int nHeightSrc, int dwRop);[DllImport("gdi32.dll")]public static extern int SetStretchBltMode(IntPtr hdc, int iStretchMode);}
三、测试
private void pictureBox1_Paint(object sender, PaintEventArgs e){if (bitmaps.Count == 0) return;Stopwatch sw = Stopwatch.StartNew();//Test111(e);Test222(e);sw.Stop();Trace.WriteLine(sw.ElapsedMilliseconds);if (++index >= bitmaps.Count)index = 0;}
其中hBitmap=Bitmap.GetHbitmap()
当gdi api 图像拉伸模式为STRETCH_DELETESCANS时,绘制4.8MB的图像需要2ms,GDI+绘制图像需要14~20ms