一、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