使用D3DXSaveSurfaceToFile保存的图像将在Paint中打开,而不是Photoshop

时间:2010-03-18 21:47:13

标签: image directx photoshop

我正在使用D3DXSaveSurfaceToFile将窗口化的Direct3D 9曲面保存为PNG,BMP和JPG文件。 D3DXSaveSurfaceToFile调用没有返回任何错误,并且所有文件在Windows Photo Viewer和Paint中都可以正常打开。但它们不会在高端图像编辑程序中打开,例如Paint Shop Pro或Photoshop。来自这些程序的错误消息基本上说该文件已损坏。如果我在Paint中打开文件,然后使用不同的文件名以相同的文件格式保存它们,那么它们将在其他程序中打开。

这让我相信D3DXSaveSurfaceToFile正在写出这些文件格式的非标准版本。有没有什么方法可以让这个函数写出可以在像Photoshop这样的程序中打开的文件而无需在Paint中重新保存文件的中间步骤?或者我应该使用另一个功能,它可以更好地将Direct3D曲面保存到图像中吗?

3 个答案:

答案 0 :(得分:2)

查看图片meta viewer中的文件。它告诉你什么?

答案 1 :(得分: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();
    }
}

答案 2 :(得分:1)

事实证明,这是我的代码中的一个错误和Paint在阅读文件时比Photoshop更宽容的组合。我的代码中的错误导致文件以错误的扩展名保存(即Image.bmp实际上是使用D3DXIFF_JPG保存的)。打开包含JPG图像但具有BMP扩展名的文件时,Photoshop刚刚失败了该文件。我猜Paint工作,因为它忽略了文件扩展名,只是解码了文件内容。

查看image meta viewer中的文件有助于我发现问题。