Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. IDirectDrawSurface saving as a bitmap

IDirectDrawSurface saving as a bitmap

Scheduled Pinned Locked Moved C / C++ / MFC
adobegraphics
4 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    Todd Jeffreys
    wrote on last edited by
    #1

    I have an IDirectDrawSurface and I would like to save it as a bitmap. Im only interested in 24/32 formats. I have written some code, and it exports the file correctly. It locks the surface to get the bits, and then dumps it to a file. When I view the file with MS paint, it looks fine. However, when I open in Adobe Photoshop, the colors are off (I think the blue and red are switched). It seems odd to work in MSpaint but then not in photoshop. If anybody has experience doing this, please take a look at my code. Thanks

    STDMETHODIMP CCaptureWindow::SaveScreenshot(LPTSTR pFile)
    {
    if (!g_pCapture || !g_pBaseFilter)
    return E_UNEXPECTED;

    CComPtr ddemv;
    HRESULT hr;
    if (FAILED(g_pCapture->FindInterface(&PIN_CATEGORY_PREVIEW,
    &MEDIATYPE_Interleaved, g_pBaseFilter,
    IID_IDDrawExclModeVideo, (void**)&ddemv)))
    {
    if (FAILED(hr = g_pCapture->FindInterface(&PIN_CATEGORY_PREVIEW,
    &MEDIATYPE_Video, g_pBaseFilter,
    IID_IDDrawExclModeVideo, (void**)&ddemv)))
    {
    return hr;
    }
    }
    // ok take the screenshot now
    CComPtr pSurface;
    CComPtr pSurface7;
    BOOL bExternal;
    if (FAILED(hr=ddemv->GetDDrawSurface(&pSurface,&bExternal)))
    return hr;

    if (FAILED(hr=pSurface->QueryInterface(IID_IDirectDrawSurface7,(void**)&pSurface7)))
    return hr;

    DDSURFACEDESC2 desc;
    desc.dwSize = sizeof(desc);
    if (FAILED(hr=pSurface7->Lock(NULL,&desc,DDLOCK_WAIT | DDLOCK_READONLY,0)))
    return hr;

    // now make sure we can save it to a file
    if ((desc.ddpfPixelFormat.dwRGBBitCount < 24) || !(desc.ddpfPixelFormat.dwFlags & DDPF_RGB) || (desc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXEDTO8))
    {
    pSurface7->Unlock(NULL);
    return E_UNEXPECTED;
    }

    // now create the file
    HANDLE hFile = CreateFile(pFile,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
    if (hFile == INVALID_HANDLE_VALUE)
    {
    pSurface7->Unlock(NULL);
    return GetLastError();
    }

    CFile file(hFile);
    BITMAPFILEHEADER bfh;
    BITMAPINFO bmi;
    DWORD sizeImage;

    // fill in common areas
    bfh.bfType = MAKEWORD('B','M');
    bfh.bfReserved1 = 0;
    bfh.bfReserved2 = 0;
    bfh.bfOffBits = sizeof(bmi.bmiHeader);
    bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biCompression = BI_RGB;
    bmi.bmiHeader.biXPelsPerMeter = 0;
    bmi.bmiHeader.biYPelsPerMeter = 0;
    bmi.bmiHeader.biClrUsed = 0;
    bmi.bmiHeader.biClrImportant = 0;
    bmi.bmiHeader.biWidth = desc.dwWidth;
    bmi.

    S 1 Reply Last reply
    0
    • T Todd Jeffreys

      I have an IDirectDrawSurface and I would like to save it as a bitmap. Im only interested in 24/32 formats. I have written some code, and it exports the file correctly. It locks the surface to get the bits, and then dumps it to a file. When I view the file with MS paint, it looks fine. However, when I open in Adobe Photoshop, the colors are off (I think the blue and red are switched). It seems odd to work in MSpaint but then not in photoshop. If anybody has experience doing this, please take a look at my code. Thanks

      STDMETHODIMP CCaptureWindow::SaveScreenshot(LPTSTR pFile)
      {
      if (!g_pCapture || !g_pBaseFilter)
      return E_UNEXPECTED;

      CComPtr ddemv;
      HRESULT hr;
      if (FAILED(g_pCapture->FindInterface(&PIN_CATEGORY_PREVIEW,
      &MEDIATYPE_Interleaved, g_pBaseFilter,
      IID_IDDrawExclModeVideo, (void**)&ddemv)))
      {
      if (FAILED(hr = g_pCapture->FindInterface(&PIN_CATEGORY_PREVIEW,
      &MEDIATYPE_Video, g_pBaseFilter,
      IID_IDDrawExclModeVideo, (void**)&ddemv)))
      {
      return hr;
      }
      }
      // ok take the screenshot now
      CComPtr pSurface;
      CComPtr pSurface7;
      BOOL bExternal;
      if (FAILED(hr=ddemv->GetDDrawSurface(&pSurface,&bExternal)))
      return hr;

      if (FAILED(hr=pSurface->QueryInterface(IID_IDirectDrawSurface7,(void**)&pSurface7)))
      return hr;

      DDSURFACEDESC2 desc;
      desc.dwSize = sizeof(desc);
      if (FAILED(hr=pSurface7->Lock(NULL,&desc,DDLOCK_WAIT | DDLOCK_READONLY,0)))
      return hr;

      // now make sure we can save it to a file
      if ((desc.ddpfPixelFormat.dwRGBBitCount < 24) || !(desc.ddpfPixelFormat.dwFlags & DDPF_RGB) || (desc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXEDTO8))
      {
      pSurface7->Unlock(NULL);
      return E_UNEXPECTED;
      }

      // now create the file
      HANDLE hFile = CreateFile(pFile,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
      if (hFile == INVALID_HANDLE_VALUE)
      {
      pSurface7->Unlock(NULL);
      return GetLastError();
      }

      CFile file(hFile);
      BITMAPFILEHEADER bfh;
      BITMAPINFO bmi;
      DWORD sizeImage;

      // fill in common areas
      bfh.bfType = MAKEWORD('B','M');
      bfh.bfReserved1 = 0;
      bfh.bfReserved2 = 0;
      bfh.bfOffBits = sizeof(bmi.bmiHeader);
      bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
      bmi.bmiHeader.biPlanes = 1;
      bmi.bmiHeader.biCompression = BI_RGB;
      bmi.bmiHeader.biXPelsPerMeter = 0;
      bmi.bmiHeader.biYPelsPerMeter = 0;
      bmi.bmiHeader.biClrUsed = 0;
      bmi.bmiHeader.biClrImportant = 0;
      bmi.bmiHeader.biWidth = desc.dwWidth;
      bmi.

      S Offline
      S Offline
      Stephane Rodriguez
      wrote on last edited by
      #2

      First of all, looks like 75% of your code here is useless, you don't need to copy the source surface byte by byte. DirectDraw exposes a DC. Once you've got it, you simply do a StretchBlit to a destination DC.

      // m_pDDSOffscreen3 is a DirectDraw surface

      HDC MemDC, SurfDC;
      HBITMAP	hBmp,hDib;
      DDSURFACEDESC ddsd;
      LPBYTE	destbuffer=NULL;
      BITMAP	bmp;
      PBITMAPINFO	pbmi;
      WORD		cClrBits;
      LPVOID lpBits=NULL;
      
      if (m\_pDDSOffscreen3==NULL) return;
      
      // Get the size of the surface...
      ddsd.dwSize  = sizeof(ddsd);
      ddsd.dwFlags = DDSD\_HEIGHT | DDSD\_WIDTH;
      m\_pDDSOffscreen3->GetSurfaceDesc(&ddsd);
      
      // Create the Memorybitmap now...
      HRESULT hr = m\_pDDSOffscreen3->GetDC(&SurfDC);
      if (SUCCEEDED(hr))
      {
      	// Create the Memorybitmap now...
      	MemDC = ::CreateCompatibleDC( NULL );
      	hBmp = ::CreateCompatibleBitmap( SurfDC, ddsd.dwWidth, ddsd.dwHeight );
      	::SelectObject( MemDC, hBmp );
      	::BitBlt( MemDC, 0, 0, ddsd.dwWidth, ddsd.dwHeight, SurfDC, 0, 0, SRCCOPY );
      
      	// Bitmapstruct init...
      	::GetObject( hBmp, sizeof(BITMAP), (LPSTR)&bmp ); cClrBits = (WORD) 24;
      	pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));
      
      	/\* Initialize the fields in the BITMAPINFO structure. \*/ 
      	pbmi->bmiHeader.biSize         = sizeof(BITMAPINFOHEADER); 
      	pbmi->bmiHeader.biWidth        = bmp.bmWidth; 
      	pbmi->bmiHeader.biHeight       = bmp.bmHeight; 
      	pbmi->bmiHeader.biPlanes       = bmp.bmPlanes; 
      	pbmi->bmiHeader.biBitCount     = 24; 
      	if( cClrBits < 24 ) pbmi->bmiHeader.biClrUsed = 2^cClrBits; 
      	pbmi->bmiHeader.biCompression  = BI\_RGB; 
      	pbmi->bmiHeader.biSizeImage    = (pbmi->bmiHeader.biWidth + 7) /8 \* 
      									pbmi->bmiHeader.biHeight \* 24; 
      	pbmi->bmiHeader.biClrImportant = 0; 
      
      	hDib = ::CreateDIBSection(NULL,pbmi,DIB\_RGB\_COLORS,&lpBits,NULL,0);
      	if (hDib==NULL) TRACE("CreateDIBSection failed\\n");
      
      	// Get the bits from the DC to save it to disk...
      	GetDIBits( SurfDC, hBmp, 0, (WORD) bmp.bmHeight, lpBits, pbmi, 0 );
      	if( lpBits == NULL ) TRACE( "No memory for screenshot!\\n" );
      
      	if (bAddTail)
      	{
      		CString name=\_T("");
      		if (GetDocument()->addShot(name,nStart,nEnd) &&
      			pThumb->AddItem(CBitmap::FromHandle(hDib), name))
      		{
      			GetDocument()->addShotInfo(nStart,nEnd,
      				pThumb->GetImageListIndex(),pThumb->GetItemIndex());
      		}
      	}
      	else
      	{
      		// remplace
      		replaceShot(CBitmap::FromHandle(hDib));
      	}
      
      	m\_pDDSOffscreen3->ReleaseDC(SurfDC );
      	::SelectObject(MemDC,NULL);
      	::DeleteDC(MemDC);
      	::DeleteObject(hBmp);
      	:
      
      T 1 Reply Last reply
      0
      • S Stephane Rodriguez

        First of all, looks like 75% of your code here is useless, you don't need to copy the source surface byte by byte. DirectDraw exposes a DC. Once you've got it, you simply do a StretchBlit to a destination DC.

        // m_pDDSOffscreen3 is a DirectDraw surface

        HDC MemDC, SurfDC;
        HBITMAP	hBmp,hDib;
        DDSURFACEDESC ddsd;
        LPBYTE	destbuffer=NULL;
        BITMAP	bmp;
        PBITMAPINFO	pbmi;
        WORD		cClrBits;
        LPVOID lpBits=NULL;
        
        if (m\_pDDSOffscreen3==NULL) return;
        
        // Get the size of the surface...
        ddsd.dwSize  = sizeof(ddsd);
        ddsd.dwFlags = DDSD\_HEIGHT | DDSD\_WIDTH;
        m\_pDDSOffscreen3->GetSurfaceDesc(&ddsd);
        
        // Create the Memorybitmap now...
        HRESULT hr = m\_pDDSOffscreen3->GetDC(&SurfDC);
        if (SUCCEEDED(hr))
        {
        	// Create the Memorybitmap now...
        	MemDC = ::CreateCompatibleDC( NULL );
        	hBmp = ::CreateCompatibleBitmap( SurfDC, ddsd.dwWidth, ddsd.dwHeight );
        	::SelectObject( MemDC, hBmp );
        	::BitBlt( MemDC, 0, 0, ddsd.dwWidth, ddsd.dwHeight, SurfDC, 0, 0, SRCCOPY );
        
        	// Bitmapstruct init...
        	::GetObject( hBmp, sizeof(BITMAP), (LPSTR)&bmp ); cClrBits = (WORD) 24;
        	pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));
        
        	/\* Initialize the fields in the BITMAPINFO structure. \*/ 
        	pbmi->bmiHeader.biSize         = sizeof(BITMAPINFOHEADER); 
        	pbmi->bmiHeader.biWidth        = bmp.bmWidth; 
        	pbmi->bmiHeader.biHeight       = bmp.bmHeight; 
        	pbmi->bmiHeader.biPlanes       = bmp.bmPlanes; 
        	pbmi->bmiHeader.biBitCount     = 24; 
        	if( cClrBits < 24 ) pbmi->bmiHeader.biClrUsed = 2^cClrBits; 
        	pbmi->bmiHeader.biCompression  = BI\_RGB; 
        	pbmi->bmiHeader.biSizeImage    = (pbmi->bmiHeader.biWidth + 7) /8 \* 
        									pbmi->bmiHeader.biHeight \* 24; 
        	pbmi->bmiHeader.biClrImportant = 0; 
        
        	hDib = ::CreateDIBSection(NULL,pbmi,DIB\_RGB\_COLORS,&lpBits,NULL,0);
        	if (hDib==NULL) TRACE("CreateDIBSection failed\\n");
        
        	// Get the bits from the DC to save it to disk...
        	GetDIBits( SurfDC, hBmp, 0, (WORD) bmp.bmHeight, lpBits, pbmi, 0 );
        	if( lpBits == NULL ) TRACE( "No memory for screenshot!\\n" );
        
        	if (bAddTail)
        	{
        		CString name=\_T("");
        		if (GetDocument()->addShot(name,nStart,nEnd) &&
        			pThumb->AddItem(CBitmap::FromHandle(hDib), name))
        		{
        			GetDocument()->addShotInfo(nStart,nEnd,
        				pThumb->GetImageListIndex(),pThumb->GetItemIndex());
        		}
        	}
        	else
        	{
        		// remplace
        		replaceShot(CBitmap::FromHandle(hDib));
        	}
        
        	m\_pDDSOffscreen3->ReleaseDC(SurfDC );
        	::SelectObject(MemDC,NULL);
        	::DeleteDC(MemDC);
        	::DeleteObject(hBmp);
        	:
        
        T Offline
        T Offline
        Todd Jeffreys
        wrote on last edited by
        #3

        Thanks for the tip, but I think your solution seems slightly wasteful. You suggest creating a DIB from a DDB which requires allocating a new DDB + memory for the DIB bits. Isn't Lock'ing the surface the same thing as getting the DIB bits (and hence you can avoid the DDB HBITMAP stuff)?

        M 1 Reply Last reply
        0
        • T Todd Jeffreys

          Thanks for the tip, but I think your solution seems slightly wasteful. You suggest creating a DIB from a DDB which requires allocating a new DDB + memory for the DIB bits. Isn't Lock'ing the surface the same thing as getting the DIB bits (and hence you can avoid the DDB HBITMAP stuff)?

          M Offline
          M Offline
          Mike Nordell
          wrote on last edited by
          #4

          Todd Jeffreys wrote: You suggest creating a DIB from a DDB Yes? That is AFAIK what the very definition of a .BMP-file says it contains.

          1 Reply Last reply
          0
          Reply
          • Reply as topic
          Log in to reply
          • Oldest to Newest
          • Newest to Oldest
          • Most Votes


          • Login

          • Don't have an account? Register

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • World
          • Users
          • Groups