基于GDI和D3D的抓屏技术

最近因为工作需要,认真研究了一下屏幕截图的方法。
最主要的方法有两种,一、调用windows GDI32 API函数。二、使用DirectX9.0来实现。
另外,光注了一下Microsoft Expression Encoder 4 Screen Capture这个微软新出的功能,Expression Encoder 4 可实现屏幕录制,录制 文件格式为WMV ,为免费使用版本,Expression Encoder 4 Pro为 收费版本。
还 看了一下基于windows图形驱动技术的屏幕截图方法 ,文章链接地址:http://blog.csdn.net/jia162/article/details/2509974。实现起来可能比较困难与复杂。没找到实例参考及技术实现的算法,因此也就没有深入研究。
下面两种方法
一、GDI32 API截图,600*480大小生成Bitmap位图大概需要45ms左右,生成位图并save成bmp文件需要大概110ms左右,图片越大,耗费的时间越长,效率比较低。
二、DirectX截图,是把整个屏幕的拷贝到内存里,再进行截取,执行拷贝屏幕的方法g_pd3dDevice->GetFrontBufferData(0, g_pSurface)需要80ms-100ms,效率也比较低
若那位技术牛人有好滴方法,请推荐一下哦!!!
方法一实现:
复制代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace DataFrameFetch
{
    public class WinGdi32Api
    {
        [DllImport("GDI32.dll")]
        public static extern bool BitBlt(int hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, int hdcSrc, int nXSrc, int nYSrc, int dwRop);
        [DllImport("GDI32.dll")]
        public static extern int CreateCompatibleBitmap(int hdc, int nWidth, int nHeight);
        [DllImport("GDI32.dll")]
        public static extern int CreateCompatibleDC(int hdc);
        [DllImport("GDI32.dll")]
        public static extern bool DeleteDC(int hdc);
        [DllImport("GDI32.dll")]
        public static extern bool DeleteObject(int hObject);
        [DllImport("GDI32.dll")]
        public static extern int GetDeviceCaps(int hdc, int nIndex);
        [DllImport("GDI32.dll")]
        public static extern int SelectObject(int hdc, int hgdiobj);
        [DllImport("User32.dll")]
        public static extern int GetDesktopWindow();
        [DllImport("User32.dll")]
        public static extern int GetWindowDC(int hWnd);
        [DllImport("User32.dll")]
        public static extern int GetDC(int hWnd);
        [DllImport("User32.dll")]
        public static extern int ReleaseDC(int hWnd, int hDC);
    }
}


 

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;


namespace DataFrameFetch
{
    public class DataFetch
    {

        public DataFetch()
        { }

    

        /// <summary>
        /// 全屏截图
        /// </summary>
        /// <returns></returns>
        public Bitmap CaptureScreen()
        {
            DateTime dt_start = DateTime.Now;
            int source = WinGdi32Api.GetWindowDC(WinGdi32Api.GetDesktopWindow());
            int bitmap = WinGdi32Api.CreateCompatibleBitmap(source, WinGdi32Api.GetDeviceCaps(source, 8), WinGdi32Api.GetDeviceCaps(source, 10));

            int destination = WinGdi32Api.CreateCompatibleDC(source);
            WinGdi32Api.SelectObject(destination, bitmap);
            WinGdi32Api.BitBlt(destination, 0, 0, WinGdi32Api.GetDeviceCaps(source, 8), WinGdi32Api.GetDeviceCaps(source, 10), source, 0, 0, 0x00CC0020);
            Bitmap img = this.GetBitmap(bitmap);
            this.Cleanup(bitmap, source, destination);
            DateTime dt_end = DateTime.Now;
            TimeSpan ts = dt_end - dt_start;   
            System.Diagnostics.Debug.WriteLine(ts.Milliseconds.ToString());
            return img;
        }

        public Bitmap CaptureScreen(Control control)
        {
            DateTime dt_start = DateTime.Now;

            int source = WinGdi32Api.GetDC(control.Handle.ToInt32());
            int bitmap = WinGdi32Api.CreateCompatibleBitmap(source, control.Width,control.Height);

            int destination = WinGdi32Api.CreateCompatibleDC(source);
            WinGdi32Api.SelectObject(destination, bitmap);
            WinGdi32Api.BitBlt(destination, 0, 0, control.Width, control.Height, source, 0, 0, 0x00CC0020);
            Bitmap img = this.GetBitmap(bitmap);
            this.Cleanup(bitmap, source, destination);

            byte[] buffer = this.ConvertBitmapToRGBByteArray(img);

            string filename = "F:\img\" + dt_start.ToString("yyyyMMddHHmmss") + dt_start.Millisecond.ToString();

            FileStream fs = new FileStream(filename + ".olc", FileMode.Create);
            fs.Write(buffer, 0, buffer.Length);
            fs.Flush();
            fs.Close();

            //Bitmap bmp = this.FromRGB(buffer, img.Width, img.Height);
            //bmp.Save(filename + "_1.bmp");

            DateTime dt_end = DateTime.Now;
            TimeSpan ts = dt_end - dt_start;
            System.Diagnostics.Debug.WriteLine(ts.Milliseconds.ToString());
            return img;
        }

        private void Cleanup(int bitmap, int source, int destination)
        {
            WinGdi32Api.ReleaseDC(WinGdi32Api.GetDesktopWindow(), source);
            WinGdi32Api.DeleteDC(destination);
            WinGdi32Api.DeleteObject(bitmap);
        }

        private Bitmap GetBitmap(int hbitmap)
        {
            Bitmap bmp = new Bitmap(Image.FromHbitmap(new IntPtr(hbitmap)), Image.FromHbitmap(new IntPtr(hbitmap)).Width, Image.FromHbitmap(new IntPtr(hbitmap)).Height);
            return bmp;
        }       

        /// <summary>
        /// 将位图转换成数组
        /// </summary>
        /// <param name="bmp"></param>
        /// <returns></returns>
        private byte[] ConvertBitmapToRGBByteArray(Bitmap bmp)
        {
            Rectangle rect = new Rectangle(new Point(0,0),bmp.Size);
            BitmapData bmpdata = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int len = bmp.Width * bmp.Height * 3;
            byte[] buffer = new byte[len];
            int index = 0;
            unsafe
            {
                byte* color = (byte*)bmpdata.Scan0;
                for (int y = 0; y < bmp.Height; y++)
                {
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        buffer[index++] = *color;
                        buffer[index++] = *(color + 1);
                        buffer[index++] = *(color + 2);
                        color += 3;
                    }
                    //color += bmpdata.Stride - bmpdata.Width * 3;
                }
            }
            bmp.UnlockBits(bmpdata);
            return buffer;
        }

 

        /// <summary>
        /// 图像象素数组转成位图
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public Bitmap ConvertRGBByteArrayToBitmap(byte[] buffer, int width, int height)
        {
            // 申请目标位图的变量,并将其内存区域锁定 
            Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);//创建新图像 
            Rectangle rect = new Rectangle(0, 0, width, height);
            BitmapData bmpData = bmp.LockBits(rect,ImageLockMode.WriteOnly,PixelFormat.Format24bppRgb);
            //// 用Marshal的Copy方法,将刚才得到的内存字节数组复制到BitmapData中 
            Marshal.Copy(buffer, 0, bmpData.Scan0, buffer.Length);
            bmp.UnlockBits(bmpData);  // 解锁内存区域 
  
            return bmp;
        }
    }
}
复制代码

方法二以VC++实现

复制代码
BOOL ScreenShot(HWND hWnd, TCHAR* fileName)
 {
    HRESULT hr;

    
    IDirect3D9*   gpD3D=NULL;
    IDirect3DDevice9* gpd3dDevice=NULL;
    IDirect3DSurface9* gpSurface=NULL;

 D3DDISPLAYMODE ddm;
 D3DPRESENT_PARAMETERS d3dpp;

 if((gpD3D=Direct3DCreate9(D3D_SDK_VERSION))==NULL)
 {
  ErrorMessage("Unable to Create Direct3D ");
  return E_FAIL;
 }

 if(FAILED(gpD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&ddm)))
 {
  ErrorMessage("Unable to Get Adapter Display Mode");
  return E_FAIL;
 } 

 ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));

 d3dpp.Windowed=WINDOW_MODE;
 d3dpp.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
 d3dpp.BackBufferFormat=ddm.Format;
 d3dpp.BackBufferHeight=nDisplayHeight=gScreenRect.bottom =ddm.Height;
 d3dpp.BackBufferWidth=nDisplayWidth=gScreenRect.right =ddm.Width;
 d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
 d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
 d3dpp.hDeviceWindow=hWnd;
 d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT;
 d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;

 if(FAILED(gpD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING ,&d3dpp,&gpd3dDevice)))
 {
  ErrorMessage("Unable to Create Device");
  return E_FAIL;
 }

 if(FAILED(gpd3dDevice->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &gpSurface, NULL)))
 {
  ErrorMessage("Unable to Create Surface");
  return E_FAIL;
 }
  if (FAILED(hr = gpd3dDevice->GetFrontBufferData(0, gpSurface))) 
    {
        gpSurface->Release() ;
        return hr ;
    }
 hr = D3DXSaveSurfaceToFile(fileName, D3DXIFF_BMP, gpSurface, NULL, NULL); 
    gpSurface->Release() ; 

   return hr ;
 }
复制代码
原文地址:https://www.cnblogs.com/cnhk19/p/12017987.html