2

D3DXSaveSurfaceToFileを使用して、ウィンドウ化されたDirect3D 9サーフェスをPNG、BMP、およびJPGファイルに保存しています。D3DXSaveSurfaceToFile呼び出しからエラーが返されることはなく、すべてのファイルがWindowsフォトビューアーとペイントで正常に開きます。ただし、PaintShopProやPhotoshopなどのハイエンドの画像編集プログラムでは開きません。これらのプログラムからのエラーメッセージは、基本的にファイルが破損していることを示しています。ペイントでファイルを開いてから、同じファイル形式で別のファイル名で保存すると、他のプログラムでも正常に開きます。

これにより、D3DXSaveSurfaceToFileがこれらのファイル形式の非標準バージョンを書き出していると思います。ペイントでファイルを再保存する中間ステップなしで、Photoshopなどのプログラムで開くことができるファイルをこの関数で書き出す方法はありますか?または、Direct3Dサーフェスを画像に保存するためのより良い仕事をするために使用する必要がある別の関数はありますか?

4

3 に答える 3

2

画像メタビューアでファイルを見てください。それはあなたに何を伝えますか?

于 2010-03-18T21:50:06.693 に答える
2

残念ながら、D3DXSaveSurfaceToFile()は最も安定していません(非常に遅いです)。個人的には以下のコードのようなことをします。アンチエイリアス表示でも、オフスクリーンレンダリングを実行してスクリーンショットを取得し、それをバッファに入れることで機能します。また、最も一般的なピクセル形式のみをサポートします。エラーが発生した場合は申し訳ありませんが、以前作業していたアプリから取り出しました。

次に、コード内で、おそらく別のスレッドで、さまざまな異なるコードを使用して、上記の「ビットマップ」を好きなものに変換できます。

void HandleScreenshot(IDirect3DDevice9* device)
{
    DWORD tcHandleScreenshot = GetTickCount();
    LPDIRECT3DSURFACE9 pd3dsBack = NULL;
    LPDIRECT3DSURFACE9 pd3dsTemp = NULL;

    // Grab the back buffer into a surface
    if ( SUCCEEDED ( device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pd3dsBack) ))
    {
        D3DSURFACE_DESC desc;
        pd3dsBack->GetDesc(&desc);

        LPDIRECT3DSURFACE9 pd3dsCopy = NULL;
        if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
        {
            if (SUCCEEDED(device->CreateRenderTarget(desc.Width, desc.Height, desc.Format, D3DMULTISAMPLE_NONE, 0, FALSE, &pd3dsCopy, NULL)))
            {
                if (SUCCEEDED(device->StretchRect(pd3dsBack, NULL, pd3dsCopy, NULL, D3DTEXF_NONE)))
                {
                    pd3dsBack->Release();
                    pd3dsBack = pd3dsCopy;
                }
                else
                {
                    pd3dsCopy->Release();
                }
            }
        }

        if (SUCCEEDED(device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &pd3dsTemp, NULL)))
        {
            DWORD tmpTimeGRTD = GetTickCount();
            if (SUCCEEDED(device->GetRenderTargetData(pd3dsBack, pd3dsTemp)))
            {
                D3DLOCKED_RECT lockedSrcRect;
                if (SUCCEEDED(pd3dsTemp->LockRect(&lockedSrcRect, NULL, D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK | D3DLOCK_NO_DIRTY_UPDATE)))
                {

                    int nSize = desc.Width * desc.Height * 3;
                    BYTE* pixels = new BYTE[nSize +1];
                    int iSrcPitch = lockedSrcRect.Pitch;
                    BYTE* pSrcRow = (BYTE*)lockedSrcRect.pBits;

                    LPBYTE lpDest = pixels;
                    LPDWORD lpSrc;

                    switch (desc.Format)
                    {
                    case D3DFMT_A8R8G8B8:
                    case D3DFMT_X8R8G8B8:
                        for (int y = desc.Height - 1; y >= 0; y--)
                        {
                            lpSrc = reinterpret_cast<LPDWORD>(lockedSrcRect.pBits) + y * desc.Width;
                            for (unsigned int x = 0; x < desc.Width; x++)
                            {
                                *reinterpret_cast<LPDWORD>(lpDest) = *lpSrc;
                                lpSrc++;        // increment source pointer by 1 DWORD
                                lpDest += 3;    // increment destination pointer by 3 bytes
                            }
                        }
                        break;
                    default:
                        ZeroMemory(pixels, nSize);
                    }

                    pd3dsTemp->UnlockRect();

                    BITMAPINFOHEADER header;
                    header.biWidth = desc.Width; 
                    header.biHeight = desc.Height; 
                    header.biSizeImage = nSize; 
                    header.biSize = sizeof(BITMAPINFOHEADER); 
                    header.biPlanes = 1;
                    header.biBitCount =  3 * 8; // RGB 
                    header.biCompression = 0; 
                    header.biXPelsPerMeter = 0; 
                    header.biYPelsPerMeter = 0; 
                    header.biClrUsed = 0; 
                    header.biClrImportant = 0; 

                    BITMAPFILEHEADER bfh = {0};
                    bfh.bfType = 0x4d42;
                    bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
                    bfh.bfSize = bfh.bfOffBits + nSize;

                    unsigned int rough_size = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER) + nSize;
                    unsigned char* p = new unsigned char[rough_size]

                    memcpy(p, &bfh, sizeof(BITMAPFILEHEADER));
                    p += sizeof(BITMAPFILEHEADER);
                    memcpy(p, &header, sizeof(BITMAPINFOHEADER));
                    p += sizeof(BITMAPINFOHEADER);
                    memcpy(p, pixels, nSize);

                    delete [] pixels;

                    /**********************************************/
                    // p now has a full BMP file, write it out here
                }
            }
            pd3dsTemp->Release();
        }
        pd3dsBack->Release();
    }
}
于 2010-03-18T21:57:46.467 に答える
1

それは私のコードのバグと、ファイルの読み取りに関してPhotoshopよりも寛容なPaintの組み合わせであることがわかりました。私のコードのバグにより、ファイルが間違った拡張子で保存されていました(つまり、Image.bmpは実際にはD3DXIFF_JPGを使用して保存されていました)。JPG画像を含むが、BMP拡張子を持つファイルを開くと、Photoshopはファイルに失敗しました。Paintはファイル拡張子を無視し、ファイルの内容をデコードしただけなので、機能したと思います。

画像メタビューアでファイルを見ると、問題を確認するのに役立ちました。

于 2010-03-18T23:21:56.920 に答える