Jump to content
Xtreme .Net Talk

Recommended Posts

Posted (edited)

Screenshot from directX in C#. SOLVED!

 

In c++ there is a nice way of geting and saving a screenshot. Does anyone know how to do this in C#. The problem is that ther is no equivalent to the C++ D3DXSaveSurfaceToFile() in C#.

 

I have found som C++ code that gos like this:

 

HRESULT CMyD3DApplication::Screenshot( char* filename )

{

HRESULT hr;

D3DDISPLAYMODE dmCurrent;

LPDIRECT3DSURFACE9 pSurface = NULL;

 

 

if ( !m_pd3dDevice ) return E_FAIL;

 

 

 

/////////////////////////////////

// QUERY CURRENT WINDOW MODE //

/////////////////////////////////

hr = m_pd3dDevice->GetDisplayMode( 0, &dmCurrent );

 

if ( FAILED( hr ) )

{

return( hr );

}

 

 

////////////////////////////////////////

// CREATE SUFACE SAME SIZE AS WINDOW //

////////////////////////////////////////

hr = m_pd3dDevice->CreateOffscreenPlainSurface( dmCurrent.Width, dmCurrent.Height,

D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH,

&pSurface, NULL );

 

if ( FAILED( hr ) )

{

return( hr );

}

 

 

 

//////////////////////////////////////////////////////////////////

// COPY FRONTBUFFER INTO SURFACE (WE CANT TOUCH IT DIRECTLY) //

//////////////////////////////////////////////////////////////////

hr = m_pd3dDevice->GetFrontBufferData( 0, pSurface );

 

if ( FAILED( hr ) )

{

pSurface->Release();

return( hr );

}

 

 

 

//////////////////////////////

// OUTPUT SURFACE TO BMP //

//////////////////////////////

hr = D3DXSaveSurfaceToFile( filename, D3DXIFF_BMP, pSurface, NULL, NULL );

 

pSurface->Release();

 

 

 

return hr;

}

 

The C# version will look like this:

Surface renderTarget = null;

Surface destTarget = null;

 

renderTarget = device.GetRenderTarget(0);

destTarget = device.CreateOffscreenPlainSurface(ClientRectangle.Width,ClientRectangle.Height,graphicsSettings.WindowedDisplayMode.Format,Pool.SystemMemory);

device.GetRenderTargetData(renderTarget,destTarget);

 

// Now we are ready to save, but how ?????????

Edited by Reidar Lange
  • *Experts*
Posted
You can save a surface to a file by using the TextureLoader's Save method. Add a reference to Microsoft.DirectX.Direct3DX and it should be available in the Direct3D namespace.
Posted (edited)

You are hereby declared as HERO

 

You can save a surface to a file by using the TextureLoader's Save method. Add a reference to Microsoft.DirectX.Direct3DX and it should be available in the Direct3D namespace.

 

I was not able to make TextureLoader work but you put me on the track that lead me right to the solution!

 

Here is the code that takes a snapshot from the current suface and saves it to the disk (can be executed before Device.Present()):

-------------------------------------------------------------------------------------------

Surface renderTarget = device.GetRenderTarget(0);

Surface destTarget = device.CreateOffscreenPlainSurface(ClientRectangle.Width,ClientRectangle.Height,graphicsSettings.WindowedDisplayMode.Format,Pool.SystemMemory);

device.GetRenderTargetData(renderTarget,destTarget);

SurfaceLoader.Save(@"c:\temp\test.bmp",ImageFileFormat.Bmp,destTarget);

-------------------------------------------------------------------------------------------

You have saved my day!!!!!!!!!!!!!!!

Edited by Reidar Lange
Posted

OK, but thanks anyway. By the way; I have found out that the code example can be simplified:

 

Surface renderTarget = device.GetRenderTarget(0);
SurfaceLoader.Save(@"c:\temp\test.bmp",ImageFileFormat.Bmp,renderTarget);

I said earlier that the code could be executed before device.Present(). Infact it should be....

 

You do not know how many hours I have spent in search for this solution.

Just look at the beauty.

 

It realy is quite different than the c++ sniplet I started out with.

  • 1 year later...
Posted

Render to memory

 

Thanks for this tip, that was very useful for writing to file. Is there a similar trick to writing directly to memory, say to a Bitmap? Thanks

  • 3 years later...
Posted

This method uses alot of unmanaged code, but will probably be very fast:

http://www.developerfusion.com/code/4630/capture-a-screen-shot/

 

This code will get the image into a BitmatpSource (for use with WPF .Net 3.0/5)

               Bitmap bmpScreenshot;
               Graphics gfxScreenshot;
               // Hide the form so that it does not appear in the screenshot
               this.Hide();
               System.Threading.Thread.Sleep(1);
               // Set the bitmap object to the size of the screen
               bmpScreenshot = new Bitmap((int)System.Windows.SystemParameters.PrimaryScreenWidth, (int)System.Windows.SystemParameters.PrimaryScreenHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
               // Create a graphics object from the bitmap
               gfxScreenshot = Graphics.FromImage(bmpScreenshot);
               // Take the screenshot from the upper left corner to the right bottom corner
               gfxScreenshot.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size((int)System.Windows.SystemParameters.PrimaryScreenWidth,(int)System.Windows.SystemParameters.PrimaryScreenHeight), CopyPixelOperation.SourceCopy);
               // Save the screenshot to the specified path that the user has chosen
               BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmpScreenshot.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());

               imx.Source = bitmapSource;
               //bmpScreenshot.Save(saveScreenshot.FileName, ImageFormat.Png);
               // Show the form again
               this.Show();

 

Otherwise, this code will probably work if you just want a Bitmap object:

 

Bitmap bmpScreenshot;
               Graphics gfxScreenshot;
               // Hide the form so that it does not appear in the screenshot
               this.Hide();
               System.Threading.Thread.Sleep(1);
               // Set the bitmap object to the size of the screen
               bmpScreenshot = new Bitmap((int)System.Windows.SystemParameters.PrimaryScreenWidth, (int)System.Windows.SystemParameters.PrimaryScreenHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
               // Create a graphics object from the bitmap
               gfxScreenshot = Graphics.FromImage(bmpScreenshot);
               // Take the screenshot from the upper left corner to the right bottom corner
               gfxScreenshot.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size((int)System.Windows.SystemParameters.PrimaryScreenWidth,(int)System.Windows.SystemParameters.PrimaryScreenHeight), CopyPixelOperation.SourceCopy);
this.Show();

~Nate�

___________________________________________

Please use the [vb]/[cs] tags on posted code.

Please post solutions you find somewhere else.

Follow me on Twitter here.

  • 4 months later...
Posted
This method uses alot of unmanaged code, but will probably be very fast:

http://www.developerfusion.com/code/4630/capture-a-screen-shot/

 

This code will get the image into a BitmatpSource (for use with WPF .Net 3.0/5)

               Bitmap bmpScreenshot;
               Graphics gfxScreenshot;
               // Hide the form so that it does not appear in the screenshot
               this.Hide();
               System.Threading.Thread.Sleep(1);
               // Set the bitmap object to the size of the screen
               bmpScreenshot = new Bitmap((int)System.Windows.SystemParameters.PrimaryScreenWidth, (int)System.Windows.SystemParameters.PrimaryScreenHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
               // Create a graphics object from the bitmap
               gfxScreenshot = Graphics.FromImage(bmpScreenshot);
               // Take the screenshot from the upper left corner to the right bottom corner
               gfxScreenshot.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size((int)System.Windows.SystemParameters.PrimaryScreenWidth,(int)System.Windows.SystemParameters.PrimaryScreenHeight), CopyPixelOperation.SourceCopy);
               // Save the screenshot to the specified path that the user has chosen
               BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmpScreenshot.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());

               imx.Source = bitmapSource;
               //bmpScreenshot.Save(saveScreenshot.FileName, ImageFormat.Png);
               // Show the form again
               this.Show();

 

Otherwise, this code will probably work if you just want a Bitmap object:

 

Bitmap bmpScreenshot;
               Graphics gfxScreenshot;
               // Hide the form so that it does not appear in the screenshot
               this.Hide();
               System.Threading.Thread.Sleep(1);
               // Set the bitmap object to the size of the screen
               bmpScreenshot = new Bitmap((int)System.Windows.SystemParameters.PrimaryScreenWidth, (int)System.Windows.SystemParameters.PrimaryScreenHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
               // Create a graphics object from the bitmap
               gfxScreenshot = Graphics.FromImage(bmpScreenshot);
               // Take the screenshot from the upper left corner to the right bottom corner
               gfxScreenshot.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size((int)System.Windows.SystemParameters.PrimaryScreenWidth,(int)System.Windows.SystemParameters.PrimaryScreenHeight), CopyPixelOperation.SourceCopy);
this.Show();

 

this works on everything except vista32, with a dx10 card. What gives with that??? I just get a black screen!

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...