Advertisement

a good DX screen capture function...

Started by August 20, 2001 09:22 PM
2 comments, last by Codejoy 23 years, 5 months ago
Anyone have a cool function in directX to capture a screen and write it out to say a .bmp file? I tried to use prtscn and it screwed up my pallets, I only ask because I dont want to reinvent the wheel if someone has one already... Thanks -Shane p.s.if you do post or mail me it, thanks.
I am looking for Dx screen capture function a long time. if you have, can you give me ?
Advertisement
Ok guys, have fun:

Here are two ways to accomplish what you need. The first is by writing your ddsurface to a bitmap file. You call SaveBMP and pass it the surface to save, your primary buffer if you are in 8 bit mode so the palette can be accessed, and the filename. It then calls SaveBMPToFile, which does exactly what it says on the tin. Note, I did not write these two functions, but received it here in much the same manner you are. I''ve tested them for 32 and 24 bit mode, not 16 or 8, so they may not work.

  /************************************************************************ Function: SaveBMP NOTE: The FrontBuffer parameter is needed only for 8-bit surfaces so that the system        palette can be accessed, for  15-,16-,24-bit surfaces it can be NULL************************************************************************/BOOLCDirectXEngine::SaveBMP (LPDIRECTDRAWSURFACE SaveSurface, LPDIRECTDRAWSURFACE FrontBuffer,const char * szFilename){ HANDLE file_out; char buf[128];  // Create the outputfile...  file_out = CreateFile(szFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  if(file_out == INVALID_HANDLE_VALUE)  {	  sprintf(buf, "Surface - Could not open output file for Bitmap: %s!", szFilename);	  g_ErrorLog.ProcessError(0, buf, FALSE);	  g_Console.Message(buf);   return FALSE;  }  if (SaveBMPToFile(SaveSurface,FrontBuffer, file_out)) {	  sprintf(buf, "%s successfully written.", szFilename);	  g_ErrorLog.Log(buf);	  g_Console.Message(buf);  } else {	  sprintf(buf, "%s not written.", szFilename);	  g_ErrorLog.Log(buf);	  g_Console.Message(buf);  }  CloseHandle(file_out); return TRUE;}/************************************************************************Function: SaveBMPToFileddsdription: Saves a BMP************************************************************************/BOOLCDirectXEngine::SaveBMPToFile (LPDIRECTDRAWSURFACE SaveSurface,LPDIRECTDRAWSURFACE FrontBuffer, HANDLE file_out){ HRESULT           rval; DWORD             numwrite; BITMAPFILEHEADER  fh; BITMAPINFOHEADER  bi; DWORD             outpixel; int               outbyte, loop, loop2, BufferIndex; BYTE              *WriteBuffer;  DDSURFACEDESC     ddsd; int              Width, Height, Pitch;  //First we need a ddsdription of the surface  ZeroMemory(&ddsd, sizeof(ddsd));  ddsd.dwSize = sizeof(ddsd);  rval = SaveSurface -> GetSurfaceDesc (&ddsd);  if (rval != DD_OK)  {          g_ErrorLog.ProcessError(0, "Couldn''t get surface ddsd for bitmap save", FALSE);          return FALSE;   }  //Setup output buffer stuff, since Windows has paging and we''re in flat mode, I just made  //it as big as the bitmap   BufferIndex = 0;  Width = ddsd.dwWidth;  Height = ddsd.dwHeight;  Pitch = ddsd.lPitch;  WriteBuffer = new BYTE [Width* Height * 3];  //width*height*24-bit  //Write the file header  ((char *)&(fh . bfType))[0] = ''B'';  ((char *)&(fh . bfType))[1] = ''M'';  fh . bfSize = (long)(sizeof (BITMAPINFOHEADER)+sizeof (BITMAPFILEHEADER)+Width*Height*3); //Size in BYTES  fh . bfReserved1 = 0;  fh . bfReserved2 = 0;  fh . bfOffBits = sizeof (BITMAPINFOHEADER)+sizeof (BITMAPFILEHEADER);  bi . biSize = sizeof (BITMAPINFOHEADER);  bi . biWidth =Width;  bi . biHeight =Height;  bi . biPlanes = 1;  bi . biBitCount = 24;  bi . biCompression = BI_RGB;  bi . biSizeImage = 0;  bi . biXPelsPerMeter = 10000;  bi . biYPelsPerMeter = 10000;  bi . biClrUsed = 0;  bi . biClrImportant = 0;  WriteFile (file_out, (char *) &fh,sizeof (BITMAPFILEHEADER),&numwrite,NULL);  WriteFile (file_out, (char *) &bi,sizeof (BITMAPINFOHEADER),&numwrite,NULL);  if (ddsd.ddpfPixelFormat.dwRGBBitCount==32)    //16 bit surfaces  {                          //lock the surface and start filling the output                          //buffer                                ZeroMemory(&ddsd, sizeof(ddsd));								ddsd.dwSize = sizeof(ddsd);                                rval = SaveSurface -> Lock(NULL,&ddsd, DDLOCK_WAIT,NULL);                                if (rval != DD_OK)                                {                                        g_ErrorLog.ProcessError(0, "Couldn''t lock source", FALSE);                                        delete [] WriteBuffer;                                        return FALSE;                                }                                BYTE *Bitmap_in = (BYTE*)ddsd.lpSurface;                                         for (loop =Height-1;loop>=0;loop--)    //Loop bottom up                                         for (loop2=0;loop2<Width;loop2++)                                          {                                           outpixel = *((DWORD *)(Bitmap_in+loop2*4 + loop * Pitch)); //Load a word                                           //Load up the Blue component and output it                                                                                      outbyte = (((outpixel)&0x000000ff));//blue                                           WriteBuffer [BufferIndex++] = outbyte;                                           //Load up the green component and output it                                            outbyte = (((outpixel>>8)&0x000000ff));                                                 WriteBuffer [BufferIndex++] = outbyte;                                           //Load up the red component and output it                                            outbyte = (((outpixel>>16)&0x000000ff));                                           WriteBuffer [BufferIndex++] = outbyte;                                          }                                 //At this point the buffer should be full, so just write it out                                        WriteFile (file_out, WriteBuffer,BufferIndex,&numwrite,NULL);                                //Now unlock the surface and we''re done                                        SaveSurface -> Unlock(NULL); } if (ddsd.ddpfPixelFormat.dwRGBBitCount==24)    //24 bit surfaces {                  //So easy just lock the surface and output                          //lock the surface and start filling the output                          //buffer                                ZeroMemory(&ddsd, sizeof(ddsd));								ddsd.dwSize = sizeof(ddsd);                                rval = SaveSurface -> Lock(NULL,&ddsd, DDLOCK_WAIT,NULL);                                if (rval != DD_OK)                                {                                        g_ErrorLog.ProcessError(0, "Couldn''t lock source", FALSE);                                        delete [] WriteBuffer;                                        return FALSE;                                }                                BYTE *Bitmap_in = (BYTE*)ddsd.lpSurface;                                 for (loop =Height-1;loop>=0;loop--)    //Loop bottom up                                 for (loop2=0;loop2<Width;loop2++)                                  {                                   //Load up the Blue component and output it                                   									 /*                                   WriteBuffer [BufferIndex++] = *(Bitmap_in+loop2*3+2 + loop * Pitch); //Bug fix 6-5                                   //Load up the green component and output it                                    WriteBuffer [BufferIndex++] = *(Bitmap_in+loop2*3+ 1 + loop * Pitch); //Bug fix 6-5                                   //Load up the red component and output it                                    WriteBuffer [BufferIndex++] = *(Bitmap_in+loop2*3 + loop * Pitch);								   */                                   WriteBuffer [BufferIndex++] = *(Bitmap_in+loop2*3 + loop * Pitch); //Bug fix 6-5                                   //Load up the green component and output it                                    WriteBuffer [BufferIndex++] = *(Bitmap_in+loop2*3+ 1 + loop * Pitch); //Bug fix 6-5                                   //Load up the red component and output it                                    WriteBuffer [BufferIndex++] = *(Bitmap_in+loop2*3+ 2 + loop * Pitch);                                  }                                                                     //At this point the buffer should be full, so just write it out                                        WriteFile (file_out, WriteBuffer,BufferIndex,&numwrite,NULL);                                //Now unlock the surface and we''re done                                        SaveSurface -> Unlock(NULL); } else if (ddsd.ddpfPixelFormat.dwRGBBitCount==16)       //16 bit surfaces {                          //lock the surface and start filling the output                          //buffer                                ZeroMemory(&ddsd, sizeof(ddsd));								ddsd.dwSize = sizeof(ddsd);                                rval = SaveSurface -> Lock(NULL,&ddsd, DDLOCK_WAIT,NULL);                                if (rval != DD_OK)                                {                                        g_ErrorLog.ProcessError(0, "Couldn''t lock source", FALSE);                                        delete [] WriteBuffer;                                        return FALSE;                                }                                BYTE *Bitmap_in = (BYTE*)ddsd.lpSurface;                          /*                          According to DirectX docs, dwRGBBitCount is 2,4,8,16,24,32, BUT what about 15-bit surfaces                          (5,5,5) I don''t really know if its needed but here we check the green bitmask to see                          if 5 or 6 bits are used for green.                                                    If the green bitmask equals 565 mode, do 16-bit mode, otherwise do 15-bit mode                          NOTE: We are reversing the component order (ie. BGR instead of RGB)                                and we are outputting it bottom up because BMP files are backwards and upside down.                          */                                if (ddsd .ddpfPixelFormat . dwGBitMask ==  0x07E0)                                  {                                         for (loop =Height-1;loop>=0;loop--)    //Loop bottom up                                         for (loop2=0;loop2<Width;loop2++)                                          {                                           outpixel = *((WORD *)(Bitmap_in+loop2*2 + loop * Pitch)); //Load a word                                           //Load up the Blue component and output it                                                                                      outbyte = (8*((outpixel)&0x001f));//blue                                           WriteBuffer [BufferIndex++] = outbyte;                                           //Load up the green component and output it                                            outbyte = (4*((outpixel>>5)&0x003f));                                                 WriteBuffer [BufferIndex++] = outbyte;                                           //Load up the red component and output it                                            outbyte = (8*((outpixel>>11)&0x001f));                                           WriteBuffer [BufferIndex++] = outbyte;                                          }                                                                       }                                 else //Assume 555 mode. 15-bit mode                                   {                                         for (loop =Height-1;loop>=0;loop--)    //Loop bottom up                                         for (loop2=0;loop2<Width;loop2++)                                          {                                           outpixel = *((WORD *)(Bitmap_in+loop2*2 + loop * Pitch)); //Load a word                                           //Load up the Blue component and output it                                                                                      outbyte = (8*((outpixel)&0x001f));//blue                                           WriteBuffer [BufferIndex++] = outbyte;                                           //Load up the green component and output it                                            outbyte = (8*((outpixel>>5)&0x001f));                                                 WriteBuffer [BufferIndex++] = outbyte;                                           //Load up the red component and output it                                            outbyte = (8*((outpixel>>10)&0x001f));  //BUG FIX here                                           WriteBuffer [BufferIndex++] = outbyte;                                          }                                 }                                 //At this point the buffer should be full, so just write it out                                        WriteFile (file_out, WriteBuffer,BufferIndex,&numwrite,NULL);                                //Now unlock the surface and we''re done                                        SaveSurface -> Unlock(NULL); } else  if (ddsd.ddpfPixelFormat.dwRGBBitCount==8) //8 bit surfaces {        //Get the system palette so we can index each pixel to its corresponding color, this        //is what the frontbuffer parameter is needed for                        if (FrontBuffer == NULL)                        {                                g_ErrorLog.ProcessError(0, "No Front Buffer for 8-bit BMP save", FALSE);                                delete [] WriteBuffer;                                 return FALSE;                        }                        LPDIRECTDRAWPALETTE Pal;                        char bytepal [256*4];                        rval = FrontBuffer -> GetPalette(&Pal);                        if (rval != DD_OK)                        {                                g_ErrorLog.ProcessError(0, "Surface - Couldn''t get palette for 8-bit Bitmap Save", FALSE);                                delete [] WriteBuffer;                                return FALSE;                        }                        Pal -> GetEntries (0,0,256,(tagPALETTEENTRY *)&(bytepal[0]));                        Pal -> Release();          //lock the surface and start filling the output          //buffer                        ZeroMemory(&ddsd, sizeof(ddsd));						ddsd.dwSize = sizeof(ddsd);                        rval = SaveSurface -> Lock(NULL,&ddsd, DDLOCK_WAIT,NULL);                        if (rval != DD_OK)                        {                                g_ErrorLog.ProcessError(0, "Couldn''t lock source", FALSE);                                delete [] WriteBuffer;                                return FALSE;                        }                        BYTE *Bitmap_in = (BYTE*)ddsd.lpSurface;         //Ok, now that we''ve got the palette and the 24-bit entries, we just look up the color and output it         //NOTE: At the same time we are reversing the component order (ie. BGR instead of RGB)         //      and we are outputting it bottom up.                          for (loop =Height-1;loop>=0;loop--)    //Loop bottom up                         for (loop2=0;loop2<Width;loop2++)                          {                           outpixel = *(Bitmap_in+loop2 + loop * Pitch); //Load a byte from the surface                           //Load up the Blue component and output it                           outbyte = bytepal[outpixel*4+2];//blue                           WriteBuffer [BufferIndex++] = outbyte;                           //Load up the Green component and output it                           outbyte = bytepal[outpixel*4+1];//green                                WriteBuffer [BufferIndex++] = outbyte;                           //Load up the Red component and output it                           outbyte = bytepal[outpixel*4];//red                                WriteBuffer [BufferIndex++] = outbyte;                          }                                 //At this point the buffer should be full, so just write it out                                        WriteFile (file_out, WriteBuffer,BufferIndex,&numwrite,NULL);                                //Now unlock the surface and we''re done                                        SaveSurface -> Unlock(NULL);  }  delete [] WriteBuffer; return TRUE;}  




In that case try using the following function, which I did write.
This function copies any surface to the clipboard, as a bitmap, which you can then paste into any paint-like program. Note this hasn''t been tested for 8 bit mode either, so you might get wierd effects when pasting if you run your windows os at 256 colours (it may conform the bitmap to the nearest colour on the windows palette). Anyway, here''s the code:

  intCDirectXEngine::CopySurfaceToClipboard(LPDIRECTDRAWSURFACE lpdds) {	HBITMAP bitmap;		if (!lpdds) {		g_ErrorLog.ProcessError(0, "Null surface passed to CDirectXEngine::CopySurfaceToClipboard.", 0);		return (0);	}	ZeroMemory(&ddsd, sizeof(ddsd));	ddsd.dwSize = sizeof(ddsd);	lpdds->GetSurfaceDesc(&ddsd);	int width = ddsd.dwWidth;	int height = ddsd.dwHeight;	char buf[128];	sprintf(buf, "Height: %d, Width: %d", height, width);	g_Console.Message(buf);	HDC hsurfacedc, hbitmapdc;		lpdds->GetDC(&hsurfacedc);	if (!hsurfacedc) {		g_ErrorLog.ProcessError(NULL, "CDirectXEngine::CopySurfaceToClipboard: Error using lpdds->GetDC", 0);		return (0);	}	hbitmapdc = CreateCompatibleDC(hsurfacedc);	if (!hbitmapdc) {		lpdds->ReleaseDC(hsurfacedc);		g_ErrorLog.ProcessError(NULL, "CDirectXEngine::CopySurfaceToClipboard: Error using lpdds->GetDC", 0);		return (0);	}	bitmap = (HBITMAP)CreateCompatibleBitmap(hsurfacedc, width, height);	if (!bitmap) {		DeleteDC(hbitmapdc);		lpdds->ReleaseDC(hsurfacedc);		g_ErrorLog.ProcessError(NULL, "CDirectXEngine::CopySurfaceToClipboard: CreateCompatibleBitmap gave NULL bitmap.", 0);		return (0);	}	SelectObject(hbitmapdc, bitmap);		if (!BitBlt(hbitmapdc, 0, 0, width, height, hsurfacedc, 0, 0, SRCCOPY)) {		DeleteDC(hbitmapdc);		lpdds->ReleaseDC(hsurfacedc);		DeleteObject(bitmap);		g_ErrorLog.ProcessError(NULL, "CDirectXEngine::CopySurfaceToClipboard: Could not BitBlt surface to bitmap.", 0);		return (0);	}	if (OpenClipboard(main_window_handle)) {		g_ErrorLog.Log("CDirectXEngine::CopySurfaceToClipboard: Opened the clipboard...");		if (EmptyClipboard()) {			g_ErrorLog.Log("CDirectXEngine::CopySurfaceToClipboard: Emptied the clipboard...");			if (SetClipboardData(CF_BITMAP, bitmap))				g_ErrorLog.Log("CDirectXEngine::CopySurfaceToClipboard: SetClipboardData returned handle...");		}		CloseClipboard();	}	DeleteDC(hbitmapdc);	lpdds->ReleaseDC(hsurfacedc);	//DeleteObject(bitmap);	return (1);}  


Good luck with your work

ps. please check out my recent post to see if you know of the game/developer I am looking for: it''s here. Thanks.

r.




"The mere thought hadn''t even begun to speculate about the slightest possibility of traversing the eternal wasteland that is my mind..."
An easier and less complicated way is found here. There is no reason to loop thru all the bytes and write em out for each color depth. GDI can do it for you.

Using the GDI to Take DirectDraw Screenshots

-Mod

----------------------
Modian

This topic is closed to new replies.

Advertisement