2010-03-18 1 views
2

Я использую D3DXSaveSurfaceToFile для сохранения оконных поверхностей Direct3D 9 в PNG, BMP и JPG-файлах. Ошибок, вызванных вызовом D3DXSaveSurfaceToFile, нет, и все файлы открываются нормально в Windows Photo Viewer и Paint. Но они не будут открываться в программе редактирования более высокого уровня, например Paint Shop Pro или Photoshop. Сообщения об ошибках из этих программ в основном говорят, что файл поврежден. Если я открою файлы в Paint и затем сохраню их в том же формате файла с другим именем файла, то они откроются в других программах.Изображения, сохраненные с помощью D3DXSaveSurfaceToFile, будут открываться в Paint, а не Photoshop

Это заставляет меня думать, что D3DXSaveSurfaceToFile записывает нестандартные версии этих форматов файлов. Есть ли способ получить эту функцию для записи файлов, которые можно открыть в программах, таких как Photoshop, без промежуточного этапа сохранения файлов в Paint? Или есть еще одна функция, которую я должен использовать, что лучше справляется с сохранением поверхностей Direct3D для изображения?

ответ

1

Оказалось, что это была комбинация из-за ошибки в своем коде и Paint быть более либерален, чем Photoshop, когда дело доходит до чтения файлов. Ошибка в моем коде привела к тому, что файлы были сохранены с неправильным расширением (т. Е. Image.bmp был фактически сохранен с использованием D3DXIFF_JPG). При открытии файла, содержащего изображение в формате JPG, но имеющего расширение BMP, Photoshop просто провалил файл. Я предполагаю, что Paint работала, поскольку она игнорировала расширение файла и просто расшифровывала содержимое файла.

Просмотрев файл в image meta viewer, он помог мне увидеть проблему.

2

Посмотрите файл на картинке meta viewer. Что это говорит вам?

+0

Оказывается, файлы были сохранены некорректно. Спасибо, что указал на эту утилиту. – bsruth

+1

Если его решение сработало ... не забудьте принять его как решение. – Lee

+0

Я поддержал, так как он помог найти ответ, но не был точным ответом на вопрос. – bsruth

2

К сожалению, D3DXSaveSurfaceToFile() не самый стабильный (он также чрезвычайно медленный). Лично я делаю что-то вроде кода ниже. Он работает даже на Anti-aliased дисплеях, делая экранный рендер, чтобы сделать снимок экрана, а затем попал в буфер. Он также поддерживает только самые распространенные форматы пикселей. Извините за любые ошибки в нем, вытащил его из приложения, над которым я работал.

Затем вы можете в своем коде и, возможно, в другом потоке, преобразовать упомянутое «растровое изображение» во все, что вам нравится, используя различные коды.

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(); 
    } 
}