Winform GDI+双缓冲绘图与GDI API双缓冲绘图

发布于:2024-06-06 ⋅ 阅读:(148) ⋅ 点赞:(0)

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


网站公告

今日签到

点亮在社区的每一天
去签到