• 基于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 ;
     }
    复制代码
  • 相关阅读:
    Curso de FP Interpretacion Lenguaje de Signos a distancia.
    T1载波与E1载波
    快速以太网中传输介质100BASETX
    MySQLdb
    NRZ编码、NRZI编码、曼彻斯特编码和差分曼彻斯特编码
    静态VLAN和动态VLAN
    Windows用脚本快速修改IP地址(Netsh)
    some skills in Windows
    shell 条件测试
    [转]不要做浮躁的嵌入式工程师
  • 原文地址:https://www.cnblogs.com/cnhk19/p/12017987.html
Copyright © 2020-2023  润新知