首页  编辑  

屏幕截图完美解决方案

Tags: /超级猛料/Picture.图形图像编程/抓图/   Date Created:

[ 原创]屏幕截图完美解决方案 --- LYSoft Liu Yang

可以截取layered窗口(包括透明窗口)的代码:

procedure CaptureScreen(AFileName: string);

const

 CAPTUREBLT = $40000000;

var

 hdcScreen: HDC;

 hdcCompatible: HDC;

 bmp: TBitmap;

 hbmScreen: HBITMAP;

begin

 hdcScreen := CreateDC('DISPLAY', nil, nil, nil);

 hdcCompatible := CreateCompatibleDC(hdcScreen);

 hbmScreen := CreateCompatibleBitmap(hdcScreen,

   GetDeviceCaps(hdcScreen, HORZRES),

   GetDeviceCaps(hdcScreen, VERTRES));

 SelectObject(hdcCompatible, hbmScreen);

 bmp := TBitmap.Create;

 bmp.Handle := hbmScreen;

 BitBlt(hdcCompatible,

   0, 0,

   bmp.Width, bmp.Height,

   hdcScreen,

   0, 0,

   SRCCOPY or CAPTUREBLT);

 bmp.SaveToFile(AFileName);

 bmp.Free;

 DeleteDC(hdcScreen);

 DeleteDC(hdcCompatible);

end;

DX Primary Surface截图代码!包含DX8与DX9两个版本

...

interface

{$DEFINE D3D9}

uses

 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

 Dialogs, StdCtrls, Buttons,

{$IFDEF D3D9}

 // D3DX9, // use D3D to save surface

 Direct3D9

{$ELSE}

 // D3DX8, // use D3D to save surface

 Direct3D8

{$ENDIF};

...

procedure TForm1.BitBtn1Click(Sender: TObject);

// Capture screen through D3D.

var

 BitsPerPixel: Byte;

 {$IFDEF D3D9}

 pD3D: IDirect3D9;

 pSurface: IDirect3DSurface9;

 g_pD3DDevice: IDirect3DDevice9;

 {$ELSE}

 pD3D: IDirect3D8;

 pSurface: IDirect3DSurface8;

 g_pD3DDevice: IDirect3DDevice8;

 {$ENDIF}

 D3DPP: TD3DPresentParameters;

 ARect: TRect;

 LockedRect: TD3DLockedRect;

 BMP: TBitmap;

 i, p: Integer;

begin

 BitsPerPixel := GetDeviceCaps(Canvas.Handle, BITSPIXEL);

 FillChar(d3dpp, SizeOf(d3dpp), 0);

 D3DPP.Windowed := True;

 D3DPP.Flags := D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;

 D3DPP.SwapEffect := D3DSWAPEFFECT_DISCARD;

 D3DPP.BackBufferWidth := Screen.Width;

 D3DPP.BackBufferHeight := Screen.Height;

 D3DPP.BackBufferFormat := D3DFMT_X8R8G8B8;

 {$IFDEF D3D9}

 pD3D := Direct3DCreate9(D3D_SDK_VERSION);

 pD3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow,

   D3DCREATE_SOFTWARE_VERTEXPROCESSING, @D3DPP, g_pD3DDevice);

 g_pD3DDevice.CreateOffscreenPlainSurface(Screen.Width, Screen.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, pSurface, nil);

 g_pD3DDevice.GetFrontBufferData(0, pSurface);

 {$ELSE}

 pD3D := Direct3DCreate8(D3D_SDK_VERSION);

 pD3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, GetDesktopWindow,

   D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DPP, g_pD3DDevice);

 g_pD3DDevice.CreateImageSurface(Screen.Width, Screen.Height, D3DFMT_A8R8G8B8, pSurface);

 g_pD3DDevice.GetFrontBuffer(pSurface);

 {$ENDIF}

 // use D3D to save surface. Notes: D3DX%ab.dll is required!

//  D3DXSaveSurfaceToFile('Desktop.bmp', D3DXIFF_BMP, pSurface, nil,  nil);

 // use Bitmap to save surface

 ARect := Screen.DesktopRect;

 pSurface.LockRect(LockedRect, @ARect, D3DLOCK_NO_DIRTY_UPDATE or D3DLOCK_NOSYSLOCK or D3DLOCK_READONLY);

 BMP := TBitmap.Create;

 BMP.Width := Screen.Width;

 BMP.Height := Screen.Height;

 case BitsPerPixel of

   8:  BMP.PixelFormat := pf8bit;

   16: BMP.PixelFormat := pf16bit;

   24: BMP.PixelFormat := pf24bit;

   32: BMP.PixelFormat := pf32bit;

 end;

 p := Cardinal(LockedRect.pBits);

 for i := 0 to Screen.Height - 1 do

   begin

     CopyMemory(BMP.ScanLine[i], Ptr(p), Screen.Width * BitsPerPixel div 8);

     p := p + LockedRect.Pitch;

   end;

 BMP.SaveToFile('Desktop.bmp');

 BMP.Free;

 pSurface.UnlockRect;

end;

以上DX截图代码,不需要额外的DLL支持,有DirectX 9.0即可

采用上面的2个方案以外,还有些视频播放器的图像不能截取吧,呵呵

怎么解决呢?

它们使用的,是称为"覆盖表面"的技术,截取覆盖表面,需要Hook的手段才行

思路是:

通过Hook DDraw的DirectDrawCreate(RealOne用)同DirectDrawCreateEx(WMP用)

获得IDirectDraw(7)

再COM Hook CreateSurface,注意RealOne使用的是通过QueryInterface获得IDirectDraw2

WMP则是IDirectDraw7

Hook了CreateSurface后,就能获得OverlaySurface

所以必须在软件使用前,启动全局Hook,才有效

在需要截图的时候

Lock Overlay Surface,读取数据,马上Unlock,以免损失性能

解码读出来的数据,即可,但是由于获得的数据是显卡硬件VRAM的数据,一般是YUY2,YV12等格式,需要转换为RGB格式

例如,在我的GF6600上,RealOne(RMVB)用的是YUY2,而WMP(AVI)用的是YV12,还与当前播放的文件格式有关

提供主表面截图源码和覆盖表面截图的测试程序http://lysoft.lz169.com/projects/DXCapture.rar

现在支持YV12,NV12,YUY2,UUVY 4个格式

DXCapture.zip (493.2KB)