/// <summary> /// Saves the window contents to a stream. /// </summary> /// <param name="stream">Stream to write the window contents to.</param> public override void Save(Stream stream, PixelFormat requestedFormat) { D3D.Device device = driver.Device; DisplayMode mode = device.DisplayMode; SurfaceDescription desc = new SurfaceDescription(); desc.Width = mode.Width; desc.Height = mode.Height; desc.Format = Format.A8R8G8B8; // create a temp surface which will hold the screen image Surface surface = device.CreateOffscreenPlainSurface( mode.Width, mode.Height, Format.A8R8G8B8, Pool.SystemMemory); // get the entire front buffer. This is SLOW!! device.GetFrontBufferData(0, surface); // if not fullscreen, the front buffer contains the entire desktop image. we need to grab only the portion // that contains our render window if (!IsFullScreen) { // whatever our target control is, we need to walk up the chain and find the parent form Form form = windowHandle.FindForm(); // get the actual screen location of the form System.Drawing.Rectangle rect = form.RectangleToScreen(form.ClientRectangle); desc.Width = width; desc.Height = height; desc.Format = Format.A8R8G8B8; // create a temp surface that is sized the same as our target control Surface tmpSurface = device.CreateOffscreenPlainSurface(rect.Width, rect.Height, Format.A8R8G8B8, Pool.Default); // copy the data from the front buffer to the window sized surface device.UpdateSurface(surface, rect, tmpSurface); // dispose of the prior surface surface.Dispose(); surface = tmpSurface; } int pitch; // lock the surface to grab the data GraphicsStream graphStream = surface.LockRectangle(LockFlags.ReadOnly | LockFlags.NoSystemLock, out pitch); // create an RGB buffer byte[] buffer = new byte[width * height * 3]; int offset = 0, line = 0, count = 0; // gotta copy that data manually since it is in another format (sheesh!) unsafe { byte *data = (byte *)graphStream.InternalData; for (int y = 0; y < desc.Height; y++) { line = y * pitch; for (int x = 0; x < desc.Width; x++) { offset = x * 4; int pixel = line + offset; // Actual format is BRGA for some reason buffer[count++] = data[pixel + 2]; buffer[count++] = data[pixel + 1]; buffer[count++] = data[pixel + 0]; } } } surface.UnlockRectangle(); // dispose of the surface surface.Dispose(); // gotta flip the image real fast Image image = Image.FromDynamicImage(buffer, width, height, PixelFormat.R8G8B8); image.FlipAroundX(); // write the data to the stream provided stream.Write(image.Data, 0, image.Data.Length); }