2017-05-16 18 views
0

私は、フルスクリーンのDirectXアプリケーションをキャプチャするプログラムを作成しようとしています。画面上の特定のピクセルセットを探し、それが見つかったらスクリーンに画像を描画します。DirectX Partial Screen Capture

私は、画面をキャプチャするアプリケーションを設定することができたこの質問コードはIWICライブラリを使用してハードドライブに保存されます。この例ではCapture screen using DirectX

ためのコードの答えを使用してDirectXのライブラリ。私はむしろそれを保存する代わりにピクセルを操作したいと思う。

私は画面をキャプチャし、画面全体のピクセルのLPBYTを持っていると、私はそれを私が望む領域に切り抜き、次にピクセル配列を操作する方法がわかりません。単なる多次元バイト配列ですか?

私はそれを行うべきだと思う方法はIWICビットマップ(実行される)に

  1. キャプチャ画面です。
  2. ID2D1RenderTarget :: CreateBitmapFromWicBitmapを使用してIWICビットマップをID2D1ビットマップに変換する
  3. 部分画像を保存するために新しいID2D1 ::ビットマップを作成します。
  4. ID2D1 :: CopyFromBitmapを使用して、ID2D1ビットマップの領域を新しいビットマップにコピーします。
  5. ID2D1を使用して画面に戻る。

これについての助力は非常に高く評価されます。

+1

ない、これはあなたを助けるかないでしょうかどうかわから;それは関連性があると思われる。 'テクスチャへのレンダリング 'で動作するrastertekのチュートリアルのこのセクションを参照してください。http://www.rastertek.com/dx11tut22.html –

+1

最初に全体の画面を取得する必要はありません。元のコードはスクリーンの矩形部分のみを取り込むようになっている。あなたがしたくないピクセルをバッファリングする必要はありません。これらのピクセルで何をしたいのかははっきりしません。 –

+0

これは私の最初の考えであり、画面の一部をキャプチャする方が好きですが、どのように考えているのかわかりません。私はキャプチャの境界(D3DPRESENT_PARAMETERSの)を変更するのと同じくらい簡単だと思ったが、それは正しいと思われる。 –

答えて

1

original codeの変更されたバージョンで、画面の一部だけをバッファにキャプチャし、さらにstrideを返します。次に、すべてのピクセルをブラウズし、返されたバッファのサンプル使用法として色をダンプします。あなたがそれを使用したら、あなたがそれを解放しなければなりませんので、このサンプルで

は、バッファは、関数によって割り振られます。

// sample usage 
int main() 
{ 
    LONG left = 10; 
    LONG top = 10; 
    LONG width = 100; 
    LONG height = 100; 
    LPBYTE buffer; 
    UINT stride; 
    RECT rc = { left, top, left + width, top + height }; 
    Direct3D9TakeScreenshot(D3DADAPTER_DEFAULT, &buffer, &stride, &rc); 

    // In 32bppPBGRA format, each pixel is represented by 4 bytes 
    // with one byte each for blue, green, red, and the alpha channel, in that order. 
    // But don't forget this is all modulo endianness ... 
    // So, on Intel architecture, if we read a pixel from memory 
    // as a DWORD, it's reversed (ARGB). The macros below handle that. 

    // browse every pixel by line 
    for (int h = 0; h < height; h++) 
    { 
    LPDWORD pixels = (LPDWORD)(buffer + h * stride); 
    for (int w = 0; w < width; w++) 
    { 
     DWORD pixel = pixels[w]; 
     wprintf(L"#%02X#%02X#%02X#%02X\n", GetBGRAPixelAlpha(pixel), GetBGRAPixelRed(pixel), GetBGRAPixelGreen(pixel), GetBGRAPixelBlue(pixel)); 
    } 
    } 

    // get pixel at 50, 50 in the buffer, as #ARGB 
    DWORD pixel = GetBGRAPixel(buffer, stride, 50, 50); 
    wprintf(L"#%02X#%02X#%02X#%02X\n", GetBGRAPixelAlpha(pixel), GetBGRAPixelRed(pixel), GetBGRAPixelGreen(pixel), GetBGRAPixelBlue(pixel)); 

    SavePixelsToFile32bppPBGRA(width, height, stride, buffer, L"test.png", GUID_ContainerFormatPng); 
    LocalFree(buffer); 
    return 0;; 
} 

#define GetBGRAPixelBlue(p)   (LOBYTE(p)) 
#define GetBGRAPixelGreen(p)  (HIBYTE(p)) 
#define GetBGRAPixelRed(p)   (LOBYTE(HIWORD(p))) 
#define GetBGRAPixelAlpha(p)  (HIBYTE(HIWORD(p))) 
#define GetBGRAPixel(b,s,x,y)  (((LPDWORD)(((LPBYTE)b) + y * s))[x]) 

int main() 

HRESULT Direct3D9TakeScreenshot(UINT adapter, LPBYTE *pBuffer, UINT *pStride, const RECT *pInputRc = nullptr) 
{ 
    if (!pBuffer || !pStride) return E_INVALIDARG; 

    HRESULT hr = S_OK; 
    IDirect3D9 *d3d = nullptr; 
    IDirect3DDevice9 *device = nullptr; 
    IDirect3DSurface9 *surface = nullptr; 
    D3DPRESENT_PARAMETERS parameters = { 0 }; 
    D3DDISPLAYMODE mode; 
    D3DLOCKED_RECT rc; 

    *pBuffer = NULL; 
    *pStride = 0; 

    // init D3D and get screen size 
    d3d = Direct3DCreate9(D3D_SDK_VERSION); 
    HRCHECK(d3d->GetAdapterDisplayMode(adapter, &mode)); 

    LONG width = pInputRc ? (pInputRc->right - pInputRc->left) : mode.Width; 
    LONG height = pInputRc ? (pInputRc->bottom - pInputRc->top) : mode.Height; 

    parameters.Windowed = TRUE; 
    parameters.BackBufferCount = 1; 
    parameters.BackBufferHeight = height; 
    parameters.BackBufferWidth = width; 
    parameters.SwapEffect = D3DSWAPEFFECT_DISCARD; 
    parameters.hDeviceWindow = NULL; 

    // create device & capture surface (note it needs desktop size, not our capture size) 
    HRCHECK(d3d->CreateDevice(adapter, D3DDEVTYPE_HAL, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &parameters, &device)); 
    HRCHECK(device->CreateOffscreenPlainSurface(mode.Width, mode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, nullptr)); 

    // get pitch/stride to compute the required buffer size 
    HRCHECK(surface->LockRect(&rc, pInputRc, 0)); 
    *pStride = rc.Pitch; 
    HRCHECK(surface->UnlockRect()); 

    // allocate buffer 
    *pBuffer = (LPBYTE)LocalAlloc(0, *pStride * height); 
    if (!*pBuffer) 
    { 
    hr = E_OUTOFMEMORY; 
    goto cleanup; 
    } 

    // get the data 
    HRCHECK(device->GetFrontBufferData(0, surface)); 

    // copy it into our buffer 
    HRCHECK(surface->LockRect(&rc, pInputRc, 0)); 
    CopyMemory(*pBuffer, rc.pBits, rc.Pitch * height); 
    HRCHECK(surface->UnlockRect()); 

cleanup: 
    if (FAILED(hr)) 
    { 
    if (*pBuffer) 
    { 
     LocalFree(*pBuffer); 
     *pBuffer = NULL; 
    } 
    *pStride = 0; 
    } 
    RELEASE(surface); 
    RELEASE(device); 
    RELEASE(d3d); 
    return hr; 
} 
+0

それはすごいです、ありがとう@SimonMourier。それは大丈夫ですか?私は今、特定の色のピクセルを探すことができるように、(私は推測している2次元配列として)ピクセル配列にアクセスしたいです。私はちょうどピクセル配列の開始としてピクセルLPBYTEポインタを使用し、高さと幅を与えられた後、各ピクセルのサイズとしてストライドを使用しますか?万が一これを例示するコードはありますか? –

+1

私の答えは –

+0

で更新されました。ありがとう@SimonMourier –