How to capture screen to image?
Submitted by tapalez on Sat, 01/05/2008 - 08:12.
Hi,
I'm trying to capture rendered screen to the image of greater resolution than the render screen I'm drawing to. I tried to change Display.RenderTarget to surface and than saving surface but with no success. I'm posting simplified example of my failed attempt:
DisplayWindow displayWindow1 = new DisplayWindow(mainForm.drawingPanel);
Surface captureSurface = new Surface(1440, 900);
while (mainForm.Visible)
{
if (capturing)
Display.RenderTarget = captureSurface;
else
Display.RenderTarget = displayWindow1;
Display.BeginFrame();
// Some drawing
Display.EndFrame();
if (capturing)
{
captureSurface.SaveTo("c:\\example.png", ImageFileFormat.Png);
capturing = false;
}
}
{
if (capturing)
Display.RenderTarget = captureSurface;
else
Display.RenderTarget = displayWindow1;
Display.BeginFrame();
// Some drawing
Display.EndFrame();
if (capturing)
{
captureSurface.SaveTo("c:\\example.png", ImageFileFormat.Png);
capturing = false;
}
}
Everything is working fine until I try to capture and switch RenderTarget to surface an then back to display window. Then I get blank (white) saved picture and my display window also becomes blank from then further on...
How is the capturing
How is the capturing variable being updated? I'm guessing it's through a keyboard event? Keep in mind all event handlers are called when Core.KeepAlive is called, so the positioning of the call to Core.KeepAlive can have an impact. When I first tried the above code, I put Core.KeepAlive in between the Display.EndFrame() and if(capturing) lines. In that case, the capturing variable is set there and the image is saved before anything is rendered to it. But if you put Core.KeepAlive at the very beginning of the loop, it should work.
I tried to put
I tried to put Core.KeepAlive at the beginning of the loop but it had no effect. I think problem lies in switching Display.renderTarget, because, once i switch render target to surface, rendering stops. Even when i switch render target back to displayWindow rendering doesn't start and screen remains blank. I tried switching between two displayWindows instead of displayWindow and surface and it works but than i cannot save the image. I hope that this gives you some clues...
Hmm well it should work. I
Hmm well it should work. I guess I need some more information.
What rendering driver is being used (AgateOTK, AgateMDX, AgateDrawing)? Did you try using AgateDrawing? Are you running Windows or Linux? Also, can you post a more complete code sample, just to make sure we're on the same page? Btw, you can use <code> and </code> to have the forum preserve code formatting.
I'm using windows XP SP2 and
I'm using windows XP SP2 and Visual Studio 2005. I made clean sample code to get clear picture:
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (AgateSetup setup = new AgateSetup())
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
setup.AskUser = true;
setup.Initialize(true, false, false);
if (setup.Cancel) return;
Form1 someForm = new Form1();
someForm.Size = new System.Drawing.Size(800, 600);
someForm.Show();
DisplayWindow displayWindow1 = new DisplayWindow(someForm);
Surface someSurface = new Surface(Application.StartupPath + "\\Image.png");
Surface captureSurface = new Surface(1600, 1200);
bool capturing = false;
while (someForm.Visible)
{
if (ERY.AgateLib.Keyboard.Keys.GetWinFormsKey(Keys.C))
{
capturing = true;
ERY.AgateLib.Keyboard.ReleaseKey(KeyCode.C);
}
if (capturing)
{
Display.RenderTarget = captureSurface;
someSurface.SetScale(2, 2);
}
Display.BeginFrame();
Display.Clear(ERY.AgateLib.Geometry.Color.White);
someSurface.Draw();
Display.EndFrame();
if (capturing)
{
captureSurface.SaveTo(Application.StartupPath + "\\CapturedImage.png", ImageFileFormat.Png);
Display.RenderTarget = displayWindow1;
someSurface.SetScale(1, 1);
capturing = false;
}
// KeepAlive processes events.
Core.KeepAlive();
System.Threading.Thread.Sleep(10);
}
}
}
}
}
I found out that program works OK when i use System.Drawing drivers, picture i save is double the size of rendered picture on screen and afterwards rendering continues normally. When I use Managed DirectX 1.1 picture I save is blank (white) and after that there is no picture on the form either, I guess rendering stops. When I use OpenGL drivers strange thing happens, picture that is saved is double size of rendered picture but only top left part with original picture size is rendered, other parts are blank and it looks like big picture has been cropped to original size. Afterwards rendering on form continues normally...
You can download whole sample project from:
http://rapidshare.com/files/82737314/ScreenCaptureExample.zip.html
There is an unfortunate
There is an unfortunate issue in the way that OpenGL driver writes to a surface. It's not written to use the OpenGL Framebuffer extension. So instead it just draws to the frame buffer as if it were going to render to the screen, then it copies the image data to a System.Drawing.Bitmap object. So in OpenGL at the moment you can't render to a surface that is larger than the DisplayWindow that you created. This has been on my todo list to fix for the next version of AgateLib for a while now.
I'm not sure why the DirectX driver is not working correctly. I will have a deeper look into that issue next week when I have some more time.