richTextBox.DrawToBitmap Does Not Draw Containing Text? - c#

If I have a richTextBox and run DrawToBitmap on it, it doesn't draw any of the text inside of the richTextBox.
Bitmap b = new Bitmap(rtb.Width, rtb.Height);
inputControl.DrawToBitmap(b, new Rectangle(0, 0, b.Width, b.Height));
Is there any way to fix this?

I know this is relatively old, but a working solution that I found at http://www.windows-tech.info/3/8ffaf21eed5de2d4.php:
public static Bitmap RtbToBitmap(RichTextBox rtb)
{
rtb.Update(); // Ensure RTB fully painted
Bitmap bmp = new Bitmap(rtb.Width, rtb.Height);
using (Graphics gr = Graphics.FromImage(bmp))
{
gr.CopyFromScreen(rtb.PointToScreen(Point.Empty), Point.Empty, rtb.Size);
}
return bmp;
}

This thread came up second in Google. Seems to have exactly what you want. Because I imagine you're using this inside your function from this question Accepting Form Elements As Method Arguments?, it's probably best to do something like this.
if(inputControl is RichTextBox)
{
//do specifc magic here
}
else
{
//general case
}
You can check for a Control containing RichTextBox recursively
bool ContainsOrIsRichTextBox(Control inputControl)
{
if(inputControl is RichTextBox) return true;
foreach(Control control in inputControl.Controls)
{
if(ContainsOrIsRichTextBox(control)) return true;
}
return false;
}
I haven't compiled this, and there's a way of doing it without risking a StackOverflowException, but this should get you started.

From the MSDN Library article for RichTextBox.DrawToBitmap():
This method is not relevant for this class.
A crummy way to say that the native Windows richedit control doesn't support WM_PRINT. Taking a screen shot is an option, Novikov gave you a link to my answer.

For what it's worth, the later version of the RichTextBox control supports the DrawToBitmap method properly; it also improves performance and has more features.
internal class RichTextBox5: RichTextBox
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern IntPtr LoadLibrary(string lpFileName);
protected override CreateParams CreateParams
{
get
{
CreateParams cparams = base.CreateParams;
if (LoadLibrary("msftedit.dll") != IntPtr.Zero)
{
cparams.ClassName = "RICHEDIT50W";
}
return cparams;
}
}
}

I found a related answer here: how to print Rich text box contents on any device contenxt with proper formatting?
I changed this to render my off screen RichTextBox to a bitmap. This way I could create a bitmap off screen and then send it to OpenGL.
// Convert the unit used by the .NET framework (1/100 inch)
// and the unit used by Win32 API calls (twips 1/1440 inch)
private const double anInch = 14.4;
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential)]
private struct CHARRANGE
{
public int cpMin; // First character of range (0 for start of doc)
public int cpMax; // Last character of range (-1 for end of doc)
}
[StructLayout(LayoutKind.Sequential)]
private struct FORMATRANGE
{
public IntPtr hdc; // Actual DC to draw on
public IntPtr hdcTarget; // Target DC for determining text formatting
public RECT rc; // Region of the DC to draw to (in twips)
public RECT rcPage; // Region of the whole DC (page size) (in twips)
public CHARRANGE chrg; // Range of text to draw (see earlier declaration)
}
private const int WM_USER = 0x0400;
private const int EM_FORMATRANGE = WM_USER + 57;
[DllImport("USER32.dll")] private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
/// <summary>
/// Render the specified RichTextBox onto the specified bitmap
/// </summary>
/// <param name="textBox">RichTextBox to render</param>
/// <param name="bitmap">Bitmap to render the RichTextBox onto</param>
public void RenderToBitmap(RichTextBox textBox, Bitmap bitmap)
{
// Set area to render to be entire bitmap
RECT rect;
rect.Left = 0;
rect.Top = 0;
rect.Right = (int)(bitmap.Width * anInch);
rect.Bottom = (int)(bitmap.Height * anInch);
Graphics g = Graphics.FromImage(bitmap);
IntPtr hdc = g.GetHdc();
FORMATRANGE fmtRange;
fmtRange.chrg.cpMin = textBox.GetCharIndexFromPosition(new Point(0,0));
fmtRange.chrg.cpMax = textBox.GetCharIndexFromPosition(new Point(bitmap.Width,bitmap.Height));
fmtRange.hdc = hdc; // Use the same DC for measuring and rendering
fmtRange.hdcTarget = hdc;
fmtRange.rc = rect;
fmtRange.rcPage = rect;
IntPtr lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
Marshal.StructureToPtr(fmtRange, lparam, false);
// Render the control to the bitmap
SendMessage(textBox.Handle, EM_FORMATRANGE, new IntPtr(1), lparam);
// Clean up
Marshal.FreeCoTaskMem(lparam);
g.ReleaseHdc(hdc);
}

I tested the methods above, and whenever I load the saved Bitmap into an ImageViewer(Like Paint), it would have the SaveFileDialog-UI faded into the background of the text. Luckily, I found an easy fix:
SaveFileDialog bfsd = new SaveFileDialog();
var rtb = richTextBox1;
bfsd.Filter = "Bitmap (*.bmp)|*.bmp|All Files (*.*)|*.*";
bfsd.Title = "Save your text as a Bitmap File";
rtb.Update(); // Ensure RTB fully painted
Bitmap bmp = new Bitmap(rtb.Width, rtb.Height);
using (Graphics gr = Graphics.FromImage(bmp))
{
gr.CopyFromScreen(rtb.PointToScreen(Point.Empty), Point.Empty, rtb.Size);
}
if (bfsd.ShowDialog()==DialogResult.OK)
{
Draw:
try
{
bmp.Save(bfsd.FileName);
bmp.Dispose();
}
catch (Exception)
{
DialogResult dr = MessageBox.Show("An error ocurred while attempting to save your Image...", "Error! Error!", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error);
if (dr == DialogResult.Retry)
{
goto Draw;
}
else if (dr == DialogResult.Cancel)
{
return;
}
}
That way, it paints the picture before you even press Save(Don't worry, it won't actually save the image until you press Save)
Pressing Cancel doesn't effect the process, because when you press the Button or MenuStripItem to save it, it will update & re-paint it :)
I implemented a try-catch method, so that it will catch an error if one occurs, rather than the app just (Not Responding)
The catch method is a Retry Button
It will catch the error, and give you the choice to either Cancel the whole Operation, or Retry
I used a goto to be able to just rewind, and make another attempt to save the file, rather than having the SaveFileDialog appear again.
I hope this helps you :)

Related

How can I convert the content of a WPF-window into an image? [duplicate]

I am making a screen capturing application and everything is going fine. All I need to do is capture the active window and take a screenshot of this active window. Does anyone know how I can do this?
Rectangle bounds = Screen.GetBounds(Point.Empty);
using(Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using(Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
}
bitmap.Save("test.jpg", ImageFormat.Jpeg);
}
for capturing current window use
Rectangle bounds = this.Bounds;
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(new Point(bounds.Left,bounds.Top), Point.Empty, bounds.Size);
}
bitmap.Save("C://test.jpg", ImageFormat.Jpeg);
}
ScreenCapture sc = new ScreenCapture();
// capture entire screen, and save it to a file
Image img = sc.CaptureScreen();
// display image in a Picture control named imageDisplay
this.imageDisplay.Image = img;
// capture this window, and save it
sc.CaptureWindowToFile(this.Handle,"C:\\temp2.gif",ImageFormat.Gif);
http://www.developerfusion.com/code/4630/capture-a-screen-shot/
I suggest next solution for capturing any current active window (not only our C# application) or entire screen with cursor position determination relative to left-top corner of window or screen respectively:
public enum enmScreenCaptureMode
{
Screen,
Window
}
class ScreenCapturer
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
public Bitmap Capture(enmScreenCaptureMode screenCaptureMode = enmScreenCaptureMode.Window)
{
Rectangle bounds;
if (screenCaptureMode == enmScreenCaptureMode.Screen)
{
bounds = Screen.GetBounds(Point.Empty);
CursorPosition = Cursor.Position;
}
else
{
var foregroundWindowsHandle = GetForegroundWindow();
var rect = new Rect();
GetWindowRect(foregroundWindowsHandle, ref rect);
bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
CursorPosition = new Point(Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);
}
var result = new Bitmap(bounds.Width, bounds.Height);
using (var g = Graphics.FromImage(result))
{
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
return result;
}
public Point CursorPosition
{
get;
protected set;
}
}
Here is a snippet to capture either the desktop or the active window.
It has no reference to Windows Forms.
public class ScreenCapture
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow();
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
public static Image CaptureDesktop()
{
return CaptureWindow(GetDesktopWindow());
}
public static Bitmap CaptureActiveWindow()
{
return CaptureWindow(GetForegroundWindow());
}
public static Bitmap CaptureWindow(IntPtr handle)
{
var rect = new Rect();
GetWindowRect(handle, ref rect);
var bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
var result = new Bitmap(bounds.Width, bounds.Height);
using (var graphics = Graphics.FromImage(result))
{
graphics.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
return result;
}
}
How to capture the whole screen:
var image = ScreenCapture.CaptureDesktop();
image.Save(#"C:\temp\snippetsource.jpg", ImageFormat.Jpeg);
How to capture the active window:
var image = ScreenCapture.CaptureActiveWindow();
image.Save(#"C:\temp\snippetsource.jpg", ImageFormat.Jpeg);
Originally found here: http://www.snippetsource.net/Snippet/158/capture-screenshot-in-c
KvanTTT's code worked great. I extended it a bit to allow a little more flexibility on save format, as well as the ability to save by hWnd, .NET Control/Form. You can get a bitmap or save to file, with a few options.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace MosaiqPerformanceMonitor {
public enum CaptureMode {
Screen, Window
}
public static class ScreenCapturer {
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
[StructLayout(LayoutKind.Sequential)]
private struct Rect {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow();
/// <summary> Capture Active Window, Desktop, Window or Control by hWnd or .NET Contro/Form and save it to a specified file. </summary>
/// <param name="filename">Filename.
/// <para>* If extension is omitted, it's calculated from the type of file</para>
/// <para>* If path is omitted, defaults to %TEMP%</para>
/// <para>* Use %NOW% to put a timestamp in the filename</para></param>
/// <param name="mode">Optional. The default value is CaptureMode.Window.</param>
/// <param name="format">Optional file save mode. Default is PNG</param>
public static void CaptureAndSave(string filename, CaptureMode mode = CaptureMode.Window, ImageFormat format = null) {
ImageSave(filename, format, Capture(mode));
}
/// <summary> Capture a specific window (or control) and save it to a specified file. </summary>
/// <param name="filename">Filename.
/// <para>* If extension is omitted, it's calculated from the type of file</para>
/// <para>* If path is omitted, defaults to %TEMP%</para>
/// <para>* Use %NOW% to put a timestamp in the filename</para></param>
/// <param name="handle">hWnd (handle) of the window to capture</param>
/// <param name="format">Optional file save mode. Default is PNG</param>
public static void CaptureAndSave(string filename, IntPtr handle, ImageFormat format = null) {
ImageSave(filename, format, Capture(handle));
}
/// <summary> Capture a specific window (or control) and save it to a specified file. </summary>
/// <param name="filename">Filename.
/// <para>* If extension is omitted, it's calculated from the type of file</para>
/// <para>* If path is omitted, defaults to %TEMP%</para>
/// <para>* Use %NOW% to put a timestamp in the filename</para></param>
/// <param name="c">Object to capture</param>
/// <param name="format">Optional file save mode. Default is PNG</param>
public static void CaptureAndSave(string filename, Control c, ImageFormat format = null) {
ImageSave(filename, format, Capture(c));
}
/// <summary> Capture the active window (default) or the desktop and return it as a bitmap </summary>
/// <param name="mode">Optional. The default value is CaptureMode.Window.</param>
public static Bitmap Capture(CaptureMode mode = CaptureMode.Window) {
return Capture(mode == CaptureMode.Screen ? GetDesktopWindow() : GetForegroundWindow());
}
/// <summary> Capture a .NET Control, Form, UserControl, etc. </summary>
/// <param name="c">Object to capture</param>
/// <returns> Bitmap of control's area </returns>
public static Bitmap Capture(Control c) {
return Capture(c.Handle);
}
/// <summary> Capture a specific window and return it as a bitmap </summary>
/// <param name="handle">hWnd (handle) of the window to capture</param>
public static Bitmap Capture(IntPtr handle) {
Rectangle bounds;
var rect = new Rect();
GetWindowRect(handle, ref rect);
bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
CursorPosition = new Point(Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);
var result = new Bitmap(bounds.Width, bounds.Height);
using (var g = Graphics.FromImage(result))
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
return result;
}
/// <summary> Position of the cursor relative to the start of the capture </summary>
public static Point CursorPosition;
/// <summary> Save an image to a specific file </summary>
/// <param name="filename">Filename.
/// <para>* If extension is omitted, it's calculated from the type of file</para>
/// <para>* If path is omitted, defaults to %TEMP%</para>
/// <para>* Use %NOW% to put a timestamp in the filename</para></param>
/// <param name="format">Optional file save mode. Default is PNG</param>
/// <param name="image">Image to save. Usually a BitMap, but can be any
/// Image.</param>
static void ImageSave(string filename, ImageFormat format, Image image) {
format = format ?? ImageFormat.Png;
if (!filename.Contains("."))
filename = filename.Trim() + "." + format.ToString().ToLower();
if (!filename.Contains(#"\"))
filename = Path.Combine(Environment.GetEnvironmentVariable("TEMP") ?? #"C:\Temp", filename);
filename = filename.Replace("%NOW%", DateTime.Now.ToString("yyyy-MM-dd#hh.mm.ss"));
image.Save(filename, format);
}
}
}
I assume you use Graphics.CopyFromScreen to get the screenshot.
You can use P/Invoke to GetForegroundWindow (and then get its position and size) to determine which region you need to copy from.
You can use the code from this question: How can I save a screenshot directly to a file in Windows?
Just change WIN32_API.GetDesktopWindow() to the Handle property of the window you want to capture.
If you want to use managed code: This will capture any window via the ProcessId.
I used the following to make the window active.
Microsoft.VisualBasic.Interaction.AppActivate(ProcessId);
Threading.Thread.Sleep(20);
I used the print screen to capture a window.
SendKeys.SendWait("%{PRTSC}");
Threading.Thread.Sleep(40);
IDataObject objData = Clipboard.GetDataObject();
Use the following code :
// Shot size = screen size
Size shotSize = Screen.PrimaryScreen.Bounds.Size;
// the upper left point in the screen to start shot
// 0,0 to get the shot from upper left point
Point upperScreenPoint = new Point(0, 0);
// the upper left point in the image to put the shot
Point upperDestinationPoint = new Point(0, 0);
// create image to get the shot in it
Bitmap shot = new Bitmap(shotSize.Width, shotSize.Height);
// new Graphics instance
Graphics graphics = Graphics.FromImage(shot);
// get the shot by Graphics class
graphics.CopyFromScreen(upperScreenPoint, upperDestinationPoint, shotSize);
// return the image
pictureBox1.Image = shot;
Works if the Desktop scaling is set.
public class ScreenCapture
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow();
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
public static Image CaptureDesktop()
{
return CaptureWindow(GetDesktopWindow());
}
public static Bitmap CaptureActiveWindow()
{
return CaptureWindow(GetForegroundWindow());
}
public static Bitmap CaptureWindow(IntPtr handle)
{
var rect = new Rect();
GetWindowRect(handle, ref rect);
GetScale getScale = new GetScale();
var bounds = new Rectangle(rect.Left, rect.Top, (int)((rect.Right - rect.Left)* getScale.getScalingFactor()), (int)((rect.Bottom - rect.Top )* getScale.getScalingFactor()));
var result = new Bitmap(bounds.Width, bounds.Height);
using (var graphics = Graphics.FromImage(result))
{
graphics.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
return result;
}
}
A little tweak to method static void ImageSave() will grant you the option where to save it. Credit goes to Microsoft (http://msdn.microsoft.com/en-us/library/sfezx97z.aspx)
static void ImageSave(string filename, ImageFormat format, Image image, SaveFileDialog saveFileDialog1)
{
saveFileDialog1.Filter = "JPeg Image|*.jpg|Bitmap Image|*.bmp|Gif Image|*.gif";
saveFileDialog1.Title = "Enregistrer un image";
saveFileDialog1.ShowDialog();
// If the file name is not an empty string open it for saving.
if (saveFileDialog1.FileName != "")
{
// Saves the Image via a FileStream created by the OpenFile method.
System.IO.FileStream fs =
(System.IO.FileStream)saveFileDialog1.OpenFile();
// Saves the Image in the appropriate ImageFormat based upon the
// File type selected in the dialog box.
// NOTE that the FilterIndex property is one-based.
switch (saveFileDialog1.FilterIndex)
{
case 1:
image.Save(fs,
System.Drawing.Imaging.ImageFormat.Jpeg);
break;
case 2:
image.Save(fs,
System.Drawing.Imaging.ImageFormat.Bmp);
break;
case 3:
image.Save(fs,
System.Drawing.Imaging.ImageFormat.Gif);
break;
}
fs.Close();
}
}
Your button_click event should be coded something like this...
private void btnScreenShot_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
ScreenCapturer.CaptureAndSave(filename, mode, format, saveFileDialog1);
}//
Based on ArsenMkrt's reply, but this one allows you to capture a control in your form (I'm writing a tool for example that has a WebBrowser control in it and want to capture just its display). Note the use of PointToScreen method:
//Project: WebCapture
//Filename: ScreenshotUtils.cs
//Author: George Birbilis (http://zoomicon.com)
//Version: 20130820
using System.Drawing;
using System.Windows.Forms;
namespace WebCapture
{
public static class ScreenshotUtils
{
public static Rectangle Offseted(this Rectangle r, Point p)
{
r.Offset(p);
return r;
}
public static Bitmap GetScreenshot(this Control c)
{
return GetScreenshot(new Rectangle(c.PointToScreen(Point.Empty), c.Size));
}
public static Bitmap GetScreenshot(Rectangle bounds)
{
Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
using (Graphics g = Graphics.FromImage(bitmap))
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
return bitmap;
}
public const string DEFAULT_IMAGESAVEFILEDIALOG_TITLE = "Save image";
public const string DEFAULT_IMAGESAVEFILEDIALOG_FILTER = "PNG Image (*.png)|*.png|JPEG Image (*.jpg)|*.jpg|Bitmap Image (*.bmp)|*.bmp|GIF Image (*.gif)|*.gif";
public const string CUSTOMPLACES_COMPUTER = "0AC0837C-BBF8-452A-850D-79D08E667CA7";
public const string CUSTOMPLACES_DESKTOP = "B4BFCC3A-DB2C-424C-B029-7FE99A87C641";
public const string CUSTOMPLACES_DOCUMENTS = "FDD39AD0-238F-46AF-ADB4-6C85480369C7";
public const string CUSTOMPLACES_PICTURES = "33E28130-4E1E-4676-835A-98395C3BC3BB";
public const string CUSTOMPLACES_PUBLICPICTURES = "B6EBFB86-6907-413C-9AF7-4FC2ABF07CC5";
public const string CUSTOMPLACES_RECENT = "AE50C081-EBD2-438A-8655-8A092E34987A";
public static SaveFileDialog GetImageSaveFileDialog(
string title = DEFAULT_IMAGESAVEFILEDIALOG_TITLE,
string filter = DEFAULT_IMAGESAVEFILEDIALOG_FILTER)
{
SaveFileDialog dialog = new SaveFileDialog();
dialog.Title = title;
dialog.Filter = filter;
/* //this seems to throw error on Windows Server 2008 R2, must be for Windows Vista only
dialog.CustomPlaces.Add(CUSTOMPLACES_COMPUTER);
dialog.CustomPlaces.Add(CUSTOMPLACES_DESKTOP);
dialog.CustomPlaces.Add(CUSTOMPLACES_DOCUMENTS);
dialog.CustomPlaces.Add(CUSTOMPLACES_PICTURES);
dialog.CustomPlaces.Add(CUSTOMPLACES_PUBLICPICTURES);
dialog.CustomPlaces.Add(CUSTOMPLACES_RECENT);
*/
return dialog;
}
public static void ShowSaveFileDialog(this Image image, IWin32Window owner = null)
{
using (SaveFileDialog dlg = GetImageSaveFileDialog())
if (dlg.ShowDialog(owner) == DialogResult.OK)
image.Save(dlg.FileName);
}
}
}
Having the Bitmap object you can just call Save on it
private void btnCapture_Click(object sender, EventArgs e)
{
webBrowser.GetScreenshot().Save("C://test.jpg", ImageFormat.Jpeg);
}
The above assumes the GC will grab the bitmap, but maybe it's better to assign the result of someControl.getScreenshot() to a Bitmap variable, then dispose that variable manually when finished with each image, especially if you're doing this grabbing often (say you have a list of webpages you want to load and save screenshots of them):
private void btnCapture_Click(object sender, EventArgs e)
{
Bitmap bitmap = webBrowser.GetScreenshot();
bitmap.ShowSaveFileDialog();
bitmap.Dispose(); //release bitmap resources
}
Even better, could employ a using clause, which has the added benefit of releasing the bitmap resources even in case of an exception occuring inside the using (child) block:
private void btnCapture_Click(object sender, EventArgs e)
{
using(Bitmap bitmap = webBrowser.GetScreenshot())
bitmap.ShowSaveFileDialog();
//exit from using block will release bitmap resources even if exception occured
}
Update:
Now WebCapture tool is ClickOnce-deployed (http://gallery.clipflair.net/WebCapture) from the web (also has nice autoupdate support thanks to ClickOnce) and you can find its source code at https://github.com/Zoomicon/ClipFlair/tree/master/Server/Tools/WebCapture
public static void ScreenCapFull_Clip(string strDestinationFolder, string strDestinationFile, bool bWriteToFile, bool bWriteToClipboard, out string strError)
{
strError = String.Empty;
if (strDestinationFile.Trim() == String.Empty) // Sort of hokey
bWriteToFile = false; // strDestinationFile = "c:\\temp\\clip.jpg";
int screenLeft = SystemInformation.VirtualScreen.Left;
int screenTop = SystemInformation.VirtualScreen.Top;
int screenWidth = SystemInformation.VirtualScreen.Width;
int screenHeight = SystemInformation.VirtualScreen.Height;
// Create a bitmap of the appropriate size to receive the full-screen screenshot.
using (Bitmap bitmap = new Bitmap(screenWidth, screenHeight))
{
// Draw the screenshot into our bitmap.
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(screenLeft, screenTop, 0, 0, bitmap.Size);
}
//Save the screenshot as a Jpg image
var uniqueFileName = strDestinationFile; // "C:\\temp\\a.Jpg";
try
{
if(bWriteToFile == true)
bitmap.Save(uniqueFileName, ImageFormat.Jpeg);
}
catch (Exception ex)
{
strError = "Error: Could not write to file: " + uniqueFileName + "-" + ex.Message + "...";
}
if (bWriteToClipboard == false)
return;
try
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
PictureBox pb = new PictureBox();
pb.Image = bitmap; //???
//Put the image in a memorystream. VpaResult.VpaImage is a picturebox.
//VpaResult.VpaImage.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
pb.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
DataObject m_data = new DataObject();
m_data.SetData("PNG", true, ms);
Clipboard.SetDataObject(m_data, true);
}
catch (Exception ex)
{
strError += "Error: Could not write to Clipboard: " + ex.Message + "...";
strError = ex.Message;
}
}
} // End public static void ScreenCapFull_Clip

Get the windows current display as images - C# [duplicate]

I am making a screen capturing application and everything is going fine. All I need to do is capture the active window and take a screenshot of this active window. Does anyone know how I can do this?
Rectangle bounds = Screen.GetBounds(Point.Empty);
using(Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using(Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
}
bitmap.Save("test.jpg", ImageFormat.Jpeg);
}
for capturing current window use
Rectangle bounds = this.Bounds;
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(new Point(bounds.Left,bounds.Top), Point.Empty, bounds.Size);
}
bitmap.Save("C://test.jpg", ImageFormat.Jpeg);
}
ScreenCapture sc = new ScreenCapture();
// capture entire screen, and save it to a file
Image img = sc.CaptureScreen();
// display image in a Picture control named imageDisplay
this.imageDisplay.Image = img;
// capture this window, and save it
sc.CaptureWindowToFile(this.Handle,"C:\\temp2.gif",ImageFormat.Gif);
http://www.developerfusion.com/code/4630/capture-a-screen-shot/
I suggest next solution for capturing any current active window (not only our C# application) or entire screen with cursor position determination relative to left-top corner of window or screen respectively:
public enum enmScreenCaptureMode
{
Screen,
Window
}
class ScreenCapturer
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
public Bitmap Capture(enmScreenCaptureMode screenCaptureMode = enmScreenCaptureMode.Window)
{
Rectangle bounds;
if (screenCaptureMode == enmScreenCaptureMode.Screen)
{
bounds = Screen.GetBounds(Point.Empty);
CursorPosition = Cursor.Position;
}
else
{
var foregroundWindowsHandle = GetForegroundWindow();
var rect = new Rect();
GetWindowRect(foregroundWindowsHandle, ref rect);
bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
CursorPosition = new Point(Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);
}
var result = new Bitmap(bounds.Width, bounds.Height);
using (var g = Graphics.FromImage(result))
{
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
return result;
}
public Point CursorPosition
{
get;
protected set;
}
}
Here is a snippet to capture either the desktop or the active window.
It has no reference to Windows Forms.
public class ScreenCapture
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow();
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
public static Image CaptureDesktop()
{
return CaptureWindow(GetDesktopWindow());
}
public static Bitmap CaptureActiveWindow()
{
return CaptureWindow(GetForegroundWindow());
}
public static Bitmap CaptureWindow(IntPtr handle)
{
var rect = new Rect();
GetWindowRect(handle, ref rect);
var bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
var result = new Bitmap(bounds.Width, bounds.Height);
using (var graphics = Graphics.FromImage(result))
{
graphics.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
return result;
}
}
How to capture the whole screen:
var image = ScreenCapture.CaptureDesktop();
image.Save(#"C:\temp\snippetsource.jpg", ImageFormat.Jpeg);
How to capture the active window:
var image = ScreenCapture.CaptureActiveWindow();
image.Save(#"C:\temp\snippetsource.jpg", ImageFormat.Jpeg);
Originally found here: http://www.snippetsource.net/Snippet/158/capture-screenshot-in-c
KvanTTT's code worked great. I extended it a bit to allow a little more flexibility on save format, as well as the ability to save by hWnd, .NET Control/Form. You can get a bitmap or save to file, with a few options.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace MosaiqPerformanceMonitor {
public enum CaptureMode {
Screen, Window
}
public static class ScreenCapturer {
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
[StructLayout(LayoutKind.Sequential)]
private struct Rect {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow();
/// <summary> Capture Active Window, Desktop, Window or Control by hWnd or .NET Contro/Form and save it to a specified file. </summary>
/// <param name="filename">Filename.
/// <para>* If extension is omitted, it's calculated from the type of file</para>
/// <para>* If path is omitted, defaults to %TEMP%</para>
/// <para>* Use %NOW% to put a timestamp in the filename</para></param>
/// <param name="mode">Optional. The default value is CaptureMode.Window.</param>
/// <param name="format">Optional file save mode. Default is PNG</param>
public static void CaptureAndSave(string filename, CaptureMode mode = CaptureMode.Window, ImageFormat format = null) {
ImageSave(filename, format, Capture(mode));
}
/// <summary> Capture a specific window (or control) and save it to a specified file. </summary>
/// <param name="filename">Filename.
/// <para>* If extension is omitted, it's calculated from the type of file</para>
/// <para>* If path is omitted, defaults to %TEMP%</para>
/// <para>* Use %NOW% to put a timestamp in the filename</para></param>
/// <param name="handle">hWnd (handle) of the window to capture</param>
/// <param name="format">Optional file save mode. Default is PNG</param>
public static void CaptureAndSave(string filename, IntPtr handle, ImageFormat format = null) {
ImageSave(filename, format, Capture(handle));
}
/// <summary> Capture a specific window (or control) and save it to a specified file. </summary>
/// <param name="filename">Filename.
/// <para>* If extension is omitted, it's calculated from the type of file</para>
/// <para>* If path is omitted, defaults to %TEMP%</para>
/// <para>* Use %NOW% to put a timestamp in the filename</para></param>
/// <param name="c">Object to capture</param>
/// <param name="format">Optional file save mode. Default is PNG</param>
public static void CaptureAndSave(string filename, Control c, ImageFormat format = null) {
ImageSave(filename, format, Capture(c));
}
/// <summary> Capture the active window (default) or the desktop and return it as a bitmap </summary>
/// <param name="mode">Optional. The default value is CaptureMode.Window.</param>
public static Bitmap Capture(CaptureMode mode = CaptureMode.Window) {
return Capture(mode == CaptureMode.Screen ? GetDesktopWindow() : GetForegroundWindow());
}
/// <summary> Capture a .NET Control, Form, UserControl, etc. </summary>
/// <param name="c">Object to capture</param>
/// <returns> Bitmap of control's area </returns>
public static Bitmap Capture(Control c) {
return Capture(c.Handle);
}
/// <summary> Capture a specific window and return it as a bitmap </summary>
/// <param name="handle">hWnd (handle) of the window to capture</param>
public static Bitmap Capture(IntPtr handle) {
Rectangle bounds;
var rect = new Rect();
GetWindowRect(handle, ref rect);
bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
CursorPosition = new Point(Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);
var result = new Bitmap(bounds.Width, bounds.Height);
using (var g = Graphics.FromImage(result))
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
return result;
}
/// <summary> Position of the cursor relative to the start of the capture </summary>
public static Point CursorPosition;
/// <summary> Save an image to a specific file </summary>
/// <param name="filename">Filename.
/// <para>* If extension is omitted, it's calculated from the type of file</para>
/// <para>* If path is omitted, defaults to %TEMP%</para>
/// <para>* Use %NOW% to put a timestamp in the filename</para></param>
/// <param name="format">Optional file save mode. Default is PNG</param>
/// <param name="image">Image to save. Usually a BitMap, but can be any
/// Image.</param>
static void ImageSave(string filename, ImageFormat format, Image image) {
format = format ?? ImageFormat.Png;
if (!filename.Contains("."))
filename = filename.Trim() + "." + format.ToString().ToLower();
if (!filename.Contains(#"\"))
filename = Path.Combine(Environment.GetEnvironmentVariable("TEMP") ?? #"C:\Temp", filename);
filename = filename.Replace("%NOW%", DateTime.Now.ToString("yyyy-MM-dd#hh.mm.ss"));
image.Save(filename, format);
}
}
}
I assume you use Graphics.CopyFromScreen to get the screenshot.
You can use P/Invoke to GetForegroundWindow (and then get its position and size) to determine which region you need to copy from.
You can use the code from this question: How can I save a screenshot directly to a file in Windows?
Just change WIN32_API.GetDesktopWindow() to the Handle property of the window you want to capture.
If you want to use managed code: This will capture any window via the ProcessId.
I used the following to make the window active.
Microsoft.VisualBasic.Interaction.AppActivate(ProcessId);
Threading.Thread.Sleep(20);
I used the print screen to capture a window.
SendKeys.SendWait("%{PRTSC}");
Threading.Thread.Sleep(40);
IDataObject objData = Clipboard.GetDataObject();
Use the following code :
// Shot size = screen size
Size shotSize = Screen.PrimaryScreen.Bounds.Size;
// the upper left point in the screen to start shot
// 0,0 to get the shot from upper left point
Point upperScreenPoint = new Point(0, 0);
// the upper left point in the image to put the shot
Point upperDestinationPoint = new Point(0, 0);
// create image to get the shot in it
Bitmap shot = new Bitmap(shotSize.Width, shotSize.Height);
// new Graphics instance
Graphics graphics = Graphics.FromImage(shot);
// get the shot by Graphics class
graphics.CopyFromScreen(upperScreenPoint, upperDestinationPoint, shotSize);
// return the image
pictureBox1.Image = shot;
Works if the Desktop scaling is set.
public class ScreenCapture
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow();
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
public static Image CaptureDesktop()
{
return CaptureWindow(GetDesktopWindow());
}
public static Bitmap CaptureActiveWindow()
{
return CaptureWindow(GetForegroundWindow());
}
public static Bitmap CaptureWindow(IntPtr handle)
{
var rect = new Rect();
GetWindowRect(handle, ref rect);
GetScale getScale = new GetScale();
var bounds = new Rectangle(rect.Left, rect.Top, (int)((rect.Right - rect.Left)* getScale.getScalingFactor()), (int)((rect.Bottom - rect.Top )* getScale.getScalingFactor()));
var result = new Bitmap(bounds.Width, bounds.Height);
using (var graphics = Graphics.FromImage(result))
{
graphics.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
return result;
}
}
A little tweak to method static void ImageSave() will grant you the option where to save it. Credit goes to Microsoft (http://msdn.microsoft.com/en-us/library/sfezx97z.aspx)
static void ImageSave(string filename, ImageFormat format, Image image, SaveFileDialog saveFileDialog1)
{
saveFileDialog1.Filter = "JPeg Image|*.jpg|Bitmap Image|*.bmp|Gif Image|*.gif";
saveFileDialog1.Title = "Enregistrer un image";
saveFileDialog1.ShowDialog();
// If the file name is not an empty string open it for saving.
if (saveFileDialog1.FileName != "")
{
// Saves the Image via a FileStream created by the OpenFile method.
System.IO.FileStream fs =
(System.IO.FileStream)saveFileDialog1.OpenFile();
// Saves the Image in the appropriate ImageFormat based upon the
// File type selected in the dialog box.
// NOTE that the FilterIndex property is one-based.
switch (saveFileDialog1.FilterIndex)
{
case 1:
image.Save(fs,
System.Drawing.Imaging.ImageFormat.Jpeg);
break;
case 2:
image.Save(fs,
System.Drawing.Imaging.ImageFormat.Bmp);
break;
case 3:
image.Save(fs,
System.Drawing.Imaging.ImageFormat.Gif);
break;
}
fs.Close();
}
}
Your button_click event should be coded something like this...
private void btnScreenShot_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
ScreenCapturer.CaptureAndSave(filename, mode, format, saveFileDialog1);
}//
Based on ArsenMkrt's reply, but this one allows you to capture a control in your form (I'm writing a tool for example that has a WebBrowser control in it and want to capture just its display). Note the use of PointToScreen method:
//Project: WebCapture
//Filename: ScreenshotUtils.cs
//Author: George Birbilis (http://zoomicon.com)
//Version: 20130820
using System.Drawing;
using System.Windows.Forms;
namespace WebCapture
{
public static class ScreenshotUtils
{
public static Rectangle Offseted(this Rectangle r, Point p)
{
r.Offset(p);
return r;
}
public static Bitmap GetScreenshot(this Control c)
{
return GetScreenshot(new Rectangle(c.PointToScreen(Point.Empty), c.Size));
}
public static Bitmap GetScreenshot(Rectangle bounds)
{
Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
using (Graphics g = Graphics.FromImage(bitmap))
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
return bitmap;
}
public const string DEFAULT_IMAGESAVEFILEDIALOG_TITLE = "Save image";
public const string DEFAULT_IMAGESAVEFILEDIALOG_FILTER = "PNG Image (*.png)|*.png|JPEG Image (*.jpg)|*.jpg|Bitmap Image (*.bmp)|*.bmp|GIF Image (*.gif)|*.gif";
public const string CUSTOMPLACES_COMPUTER = "0AC0837C-BBF8-452A-850D-79D08E667CA7";
public const string CUSTOMPLACES_DESKTOP = "B4BFCC3A-DB2C-424C-B029-7FE99A87C641";
public const string CUSTOMPLACES_DOCUMENTS = "FDD39AD0-238F-46AF-ADB4-6C85480369C7";
public const string CUSTOMPLACES_PICTURES = "33E28130-4E1E-4676-835A-98395C3BC3BB";
public const string CUSTOMPLACES_PUBLICPICTURES = "B6EBFB86-6907-413C-9AF7-4FC2ABF07CC5";
public const string CUSTOMPLACES_RECENT = "AE50C081-EBD2-438A-8655-8A092E34987A";
public static SaveFileDialog GetImageSaveFileDialog(
string title = DEFAULT_IMAGESAVEFILEDIALOG_TITLE,
string filter = DEFAULT_IMAGESAVEFILEDIALOG_FILTER)
{
SaveFileDialog dialog = new SaveFileDialog();
dialog.Title = title;
dialog.Filter = filter;
/* //this seems to throw error on Windows Server 2008 R2, must be for Windows Vista only
dialog.CustomPlaces.Add(CUSTOMPLACES_COMPUTER);
dialog.CustomPlaces.Add(CUSTOMPLACES_DESKTOP);
dialog.CustomPlaces.Add(CUSTOMPLACES_DOCUMENTS);
dialog.CustomPlaces.Add(CUSTOMPLACES_PICTURES);
dialog.CustomPlaces.Add(CUSTOMPLACES_PUBLICPICTURES);
dialog.CustomPlaces.Add(CUSTOMPLACES_RECENT);
*/
return dialog;
}
public static void ShowSaveFileDialog(this Image image, IWin32Window owner = null)
{
using (SaveFileDialog dlg = GetImageSaveFileDialog())
if (dlg.ShowDialog(owner) == DialogResult.OK)
image.Save(dlg.FileName);
}
}
}
Having the Bitmap object you can just call Save on it
private void btnCapture_Click(object sender, EventArgs e)
{
webBrowser.GetScreenshot().Save("C://test.jpg", ImageFormat.Jpeg);
}
The above assumes the GC will grab the bitmap, but maybe it's better to assign the result of someControl.getScreenshot() to a Bitmap variable, then dispose that variable manually when finished with each image, especially if you're doing this grabbing often (say you have a list of webpages you want to load and save screenshots of them):
private void btnCapture_Click(object sender, EventArgs e)
{
Bitmap bitmap = webBrowser.GetScreenshot();
bitmap.ShowSaveFileDialog();
bitmap.Dispose(); //release bitmap resources
}
Even better, could employ a using clause, which has the added benefit of releasing the bitmap resources even in case of an exception occuring inside the using (child) block:
private void btnCapture_Click(object sender, EventArgs e)
{
using(Bitmap bitmap = webBrowser.GetScreenshot())
bitmap.ShowSaveFileDialog();
//exit from using block will release bitmap resources even if exception occured
}
Update:
Now WebCapture tool is ClickOnce-deployed (http://gallery.clipflair.net/WebCapture) from the web (also has nice autoupdate support thanks to ClickOnce) and you can find its source code at https://github.com/Zoomicon/ClipFlair/tree/master/Server/Tools/WebCapture
public static void ScreenCapFull_Clip(string strDestinationFolder, string strDestinationFile, bool bWriteToFile, bool bWriteToClipboard, out string strError)
{
strError = String.Empty;
if (strDestinationFile.Trim() == String.Empty) // Sort of hokey
bWriteToFile = false; // strDestinationFile = "c:\\temp\\clip.jpg";
int screenLeft = SystemInformation.VirtualScreen.Left;
int screenTop = SystemInformation.VirtualScreen.Top;
int screenWidth = SystemInformation.VirtualScreen.Width;
int screenHeight = SystemInformation.VirtualScreen.Height;
// Create a bitmap of the appropriate size to receive the full-screen screenshot.
using (Bitmap bitmap = new Bitmap(screenWidth, screenHeight))
{
// Draw the screenshot into our bitmap.
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(screenLeft, screenTop, 0, 0, bitmap.Size);
}
//Save the screenshot as a Jpg image
var uniqueFileName = strDestinationFile; // "C:\\temp\\a.Jpg";
try
{
if(bWriteToFile == true)
bitmap.Save(uniqueFileName, ImageFormat.Jpeg);
}
catch (Exception ex)
{
strError = "Error: Could not write to file: " + uniqueFileName + "-" + ex.Message + "...";
}
if (bWriteToClipboard == false)
return;
try
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
PictureBox pb = new PictureBox();
pb.Image = bitmap; //???
//Put the image in a memorystream. VpaResult.VpaImage is a picturebox.
//VpaResult.VpaImage.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
pb.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
DataObject m_data = new DataObject();
m_data.SetData("PNG", true, ms);
Clipboard.SetDataObject(m_data, true);
}
catch (Exception ex)
{
strError += "Error: Could not write to Clipboard: " + ex.Message + "...";
strError = ex.Message;
}
}
} // End public static void ScreenCapFull_Clip

Best way to take screenshot of a web page

What is the best way to take screenshot of a web page?
At the moment I just start an selenium instance of firefox and using winapi bring it to the front and make a screenshot.
I ask similar question already.
There is two points:
Slowness.
If any window occurently gets higher than our web browser's window, this window will imprint in our screenshot.
Is there any method to take screenshot more 'programmly'?
Here is some code I use now:
class FirefoxDriverEx : FirefoxDriver
{
public Process GetFirefoxProcess()
{
var fi = typeof(FirefoxBinary).GetField("process", BindingFlags.NonPublic | BindingFlags.Instance);
return fi.GetValue(this.Binary) as Process;
}
}
Here is the code illustrating process of taking screenshot itself:
using (FirefoxDriverEx driver = new FirefoxDriverEx())
{
driver.Navigate().GoToUrl(url);
var process = driver.GetFirefoxProcess();
if (process != null)
{
var screenCapture = new ScreenCapture();
Win.SetForegroundWindow(process.MainWindowHandle.ToInt32());
}
}
Right now, I'm thinking about some manager that will control a queue of windows to take the screenshots from.
Question edit.
I'm not looking for a solution to just get screenshot 'in memory' and return it back to HTTP stream. So any ways to save screenshot and save it to file and then get it from there is very ambiguous for that purpose.
Question edit #2.
I forgot to mention. Needed screenshot should be made as it seen by user. So, screenshot should have browser window and a site inside of web browser window's bounds. I can't find any way to change mode of taking a screenshot in WebDriver of selenium. WebDriver just take screenshot of a page without any browser window.
I'd recommend getScreenshotAs. It gets even the 'out of view' part of the screen.
Here is some sample code in gr0ovy.
import java.io.IOException
import java.net.URL
import java.nio.file.Path
import java.nio.file.Paths
import java.text.SimpleDateFormat
import org.openqa.selenium.Capabilities
import org.openqa.selenium.TakesScreenshot
import org.openqa.selenium.WebDriverException
import org.openqa.selenium.remote.CapabilityType
import org.openqa.selenium.remote.DriverCommand
import org.openqa.selenium.remote.RemoteWebDriver
import org.openqa.selenium.OutputType
import org.openqa.selenium.WebDriver
public class Selenium2Screenshot {
private WebDriver driver
private String browserType
private boolean skipScreenshots
public Selenium2Screenshot(WebDriver webDriver, String browserType, boolean skipScreenshots) {
this.driver = webDriver
this.browserType = browserType
this.skipScreenshots = skipScreenshots
}
public void takeScreenshot(String filenameBase) {
if (!skipScreenshots) {
Date today
String formattedDate
SimpleDateFormat formatter
Locale currentLocale
File scrFile
currentLocale = new Locale("en", "US")
formatter = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_SSS", currentLocale)
today = new Date()
formattedDate = formatter.format(today)
String filename = getUiAutomationDir() + filenameBase + "_" + browserType + formattedDate + ".png"
Log.logger.info("Screenshot filename = " + filename)
try {
scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE)
JavaIO.copy(scrFile.getAbsolutePath(), filename)
} catch (Exception e) {
Log.logger.error(e.message, e)
}
} else {
Log.logger.info("Skipped Screenshot")
}
}
private String getUiAutomationDir()
{
String workingDir = System.getProperty("user.dir")
Path workingDirPath = Paths.get(workingDir)
String returnString = workingDirPath.toString() + "\\"
return returnString
}
}
Edited on 8/1/12:
Get application handle code. I am surely duplicating code that is on stackoverflow several times, but hopefully this is not the exact same code as in other posts :-)
public static IntPtr FindWindowByPartialCaption(String partialCaption)
{
var desktop = User32.GetDesktopWindow();
var children = EnumerateWindows.GetChildWindows(desktop);
foreach (var intPtr in children)
{
var current = GetText(intPtr);
if (current.Contains(partialCaption))
return intPtr;
}
return IntPtr.Zero;
}
[DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowProc lpEnumFunc, IntPtr lParam);
public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
return GetChildWindows(parent, false);
}
public static List<IntPtr> GetChildWindows(IntPtr parent, bool reverse)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
if (reverse)
{
List<IntPtr> resultList = result.Reverse<IntPtr>().ToList();
return resultList;
}
else
return result;
}
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
GCHandle gch = GCHandle.FromIntPtr(pointer);
List<IntPtr> list = gch.Target as List<IntPtr>;
if (list == null)
{
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
}
list.Add(handle);
// You can modify this to check to see if you want to cancel the operation, then return a null here
return true;
}
}
http://www.pinvoke.net/ is also a great resource.
http://msdn.microsoft.com/en-us/library/windows/desktop/dd162869(v=vs.85).aspx
I personally love this API. Create a bitmap with width and height calculated from the returned rectangle of GetWindowRect API and for HDC parameter use (for example):
thebitmap.GetHdc()
You should be fine.
Edit: also check this.
Btw, you can take screenshot of any window you like, even if they fall back.(note that this will not work for minimized windows. However, if you really need, there are some way arounds for that too.)
If you're looking for a programmatic way to get a screenshot of the main window of a given process, here is a function that does it:
public static Bitmap TakeScreenshot(Process process)
{
// may need a process Refresh before
return TakeScreenshot(process.MainWindowHandle);
}
public static Bitmap TakeScreenshot(IntPtr handle)
{
RECT rc = new RECT();
GetWindowRect(handle, ref rc);
Bitmap bitmap = new Bitmap(rc.right - rc.left, rc.bottom - rc.top);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
PrintWindow(handle, graphics.GetHdc(), 0);
}
return bitmap;
}
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, ref RECT rect);
[DllImport("user32.dll")]
private static extern bool PrintWindow(IntPtr hWnd, IntPtr hDC, int flags);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
Unfortunately, on Aero-equipped OS (Vista/Win7/Win8) it will not capture the full transparent border. The usual transparent border will be blacked instead. Maybe it's enough for what you're trying to acomplish.
I've been using webshotcmd (the paid version is also command line) in a production app for years. It can be configured to wait for the page to load, to wait n seconds after page load, etc. It uses Internet Explorer and works on Windows. Starts pretty fast (in my experience, the msie activex has always been instant to load).
Other than the above, I would recommend something based on a Webkit libray, it would be so much smaller than Firefox, and would start very fast (wkhtmltoimage is for now only available on Linux, but when it will be available for Windows, I would go for it - also command line). Right now just google for webkit screenshot (the huge number of available screenshotters using webkit makes me believe using that DLL would be easy to port to C#).
Edit: Considering your 2nd edit, take a look at Chrome Screen Capture source.
To try it, the extension is available in the store/extension gallery.
I was able to accomplish this by copying the window (piece by piece) into a bitmap that is set to the size of the ScrollRectangle for my webBrowser control. While it is certainly not the most elegant way of achieving this goal, I wanted to share the code in case anyone might be able to use it. Once I had something that was mostly working, I was then able to add some args, and I can now execute this utility from the command line:
Executable_Path URL Filename
/// <summary>
/// This method is called to start the process of copying the webpage to the bitmap
/// this should be called after the page has fully loaded (use DocumentCompleted event to determine
/// if the page has completed loading if calling from the command line.)
/// </summary>
private void copyWebpageToImage()
{
//these two vars will house the current position in the bmp file (starting at 0,0)
int currXPosition = 0;
int currYPosition = 0;
//we need to set the height and width of our bitmap to the scrollrectangle of the webbrowser document object
int width = webBrowser1.Document.Body.ScrollRectangle.Width;
int height = webBrowser1.Document.Body.ScrollRectangle.Height;
//instantiate the bitmap
bm = new Bitmap(wd, ht);
//Instantiate our graphics object
Graphics gfx = Graphics.FromImage((Image)bm);
//this point is used throughout the process, and helps to determine where the form is at on the screen
Point formPoint = Form1.ActiveForm.Location;
formPoint.X = formPoint.X + webBrowser1.Location.X;
formPoint.Y = formPoint.Y + webBrowser1.Location.Y;
formPoint.X = formPoint.X + 8; //offsets for my form (may be different for yours)
formPoint.Y = formPoint.Y + 33; //offsets for my form
//begin our recursive call that will stop when it reaches the end of the page
copyEverythingToBitmap(bm, currXPosition, currYPosition, formPoint, gfx);
}
private void copyEverythingToBitmap(Bitmap bm, int currXPosition, int currYPosition, Point formPoint, Graphics gfx)
{
//check to see if currXPosition and currYPosition are both 0, if so we just began, call the zero copy method
if (currXPosition == 0 && currYPosition == 0)
{
performZeroCopy(bm, currXPosition, currYPosition, formPoint, gfx);
}
//if the current x position is less than the total width of the scrollrectangle - the width of the webbrowser,
//then we need to scroll the window, and copy the contents, y stays the same
else if (currXPosition < bm.Width - webBrowser1.Width)
{
AlterXPosition(bm, ref currXPosition, ref currYPosition, ref formPoint, gfx);
}
//if we are no longer at the zero, zero, and we cannot increase the x position anymore,
//then we need to scroll the window down and copy the contents, x is reset back to zero
else if(currYPosition < bm.Height - webBrowser1.Height)
{
currYPosition = currYPosition + webBrowser1.Height - 20;
currXPosition = 0;
performZeroCopy(bm, currXPosition, currYPosition, formPoint, gfx);
}
}
/// <summary>
/// The name of this method is slightly misleading. It inherently means that X is zero.
/// </summary>
private void performZeroCopy(Bitmap bm, int currXPosition, int currYPosition, Point formPoint, Graphics gfx)
{
webBrowser1.Document.Window.ScrollTo(currXPosition, currYPosition);
gfx.CopyFromScreen(formPoint, new Point(currXPosition, currYPosition), new Size(webBrowser1.Width - 20, webBrowser1.Height - 20));
if (currXPosition < bm.Width - webBrowser1.Width)
{
AlterXPosition(bm, ref currXPosition, ref currYPosition, ref formPoint, gfx);
}
else if(currYPosition < bm.Height - webBrowser1.Height)
{
currYPosition = currYPosition + webBrowser1.Height - 20;
currXPosition = 0;
performZeroCopy(bm, currXPosition, currYPosition, formPoint, gfx);
}
}
private void AlterXPosition(Bitmap bm, ref int currXPosition, ref int currYPosition, ref Point formPoint, Graphics gfx)
{
currXPosition = currXPosition + webBrowser1.Width - 20;
webBrowser1.Document.Window.ScrollTo(bm.Width - currXPosition, currYPosition);
gfx.CopyFromScreen(formPoint, new Point(bm.Width - currXPosition - 3, currYPosition), new Size(webBrowser1.Width - 20, webBrowser1.Height - 20));
if (currXPosition + webBrowser1.Width < bm.Width)
{
//we still have not traversed the full width of the page, call to alterxposition again...
}
else
{
copyEverythingToBitmap(bm, currXPosition, currYPosition, formPoint, gfx);
}
}
private void saveImageToFile(string p)
{
bm.Tag = DateTime.Now;
bm.Save(p, ImageFormat.Jpeg);
}

How to show a TIF image full screen on secondary monitor in C#?

I have a series of images stored in a directory and want to show them successively on the secondary monitor in full screen mode.
I have no clues whatsoever of displaying image full screen mode..
Any idea how to do this in C#?
Use SetWindowPos from the WinAPI.
Example:
[DllImport("user32.dll")]
public static extern void SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int X, int Y, int width, int height, uint flags);
public Form1()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
SetWindowPos(this.Handle, IntPtr.Zero, 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, 64);
}
replace PrimaryScreen with the choosen screen.
I don't know what all can be done with the image. you can just use a Picturebox or create your on control and display it with GDI.
You can just create a borderless form, using its BackgroundImage to show the image. Make it as large as the secondary screen. Like this:
public static Form ShowImage(Image image) {
Form frm = new Form();
frm.ControlBox = false;
frm.FormBorderStyle = FormBorderStyle.None;
frm.BackgroundImage = image;
frm.BackgroundImageLayout = ImageLayout.Zoom;
Screen scr = Screen.AllScreens.Length > 1 ? Screen.AllScreens[1] : Screen.PrimaryScreen;
frm.Location = new Point(scr.Bounds.Left, scr.Bounds.Top);
frm.Size = scr.Bounds.Size;
frm.BackColor = Color.Black;
frm.Show();
return frm;
}
Note that it returns a Form object, call its Close() method to get rid of the image again.

Capture screenshot of active window?

I am making a screen capturing application and everything is going fine. All I need to do is capture the active window and take a screenshot of this active window. Does anyone know how I can do this?
Rectangle bounds = Screen.GetBounds(Point.Empty);
using(Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using(Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
}
bitmap.Save("test.jpg", ImageFormat.Jpeg);
}
for capturing current window use
Rectangle bounds = this.Bounds;
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(new Point(bounds.Left,bounds.Top), Point.Empty, bounds.Size);
}
bitmap.Save("C://test.jpg", ImageFormat.Jpeg);
}
ScreenCapture sc = new ScreenCapture();
// capture entire screen, and save it to a file
Image img = sc.CaptureScreen();
// display image in a Picture control named imageDisplay
this.imageDisplay.Image = img;
// capture this window, and save it
sc.CaptureWindowToFile(this.Handle,"C:\\temp2.gif",ImageFormat.Gif);
http://www.developerfusion.com/code/4630/capture-a-screen-shot/
I suggest next solution for capturing any current active window (not only our C# application) or entire screen with cursor position determination relative to left-top corner of window or screen respectively:
public enum enmScreenCaptureMode
{
Screen,
Window
}
class ScreenCapturer
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
public Bitmap Capture(enmScreenCaptureMode screenCaptureMode = enmScreenCaptureMode.Window)
{
Rectangle bounds;
if (screenCaptureMode == enmScreenCaptureMode.Screen)
{
bounds = Screen.GetBounds(Point.Empty);
CursorPosition = Cursor.Position;
}
else
{
var foregroundWindowsHandle = GetForegroundWindow();
var rect = new Rect();
GetWindowRect(foregroundWindowsHandle, ref rect);
bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
CursorPosition = new Point(Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);
}
var result = new Bitmap(bounds.Width, bounds.Height);
using (var g = Graphics.FromImage(result))
{
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
return result;
}
public Point CursorPosition
{
get;
protected set;
}
}
Here is a snippet to capture either the desktop or the active window.
It has no reference to Windows Forms.
public class ScreenCapture
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow();
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
public static Image CaptureDesktop()
{
return CaptureWindow(GetDesktopWindow());
}
public static Bitmap CaptureActiveWindow()
{
return CaptureWindow(GetForegroundWindow());
}
public static Bitmap CaptureWindow(IntPtr handle)
{
var rect = new Rect();
GetWindowRect(handle, ref rect);
var bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
var result = new Bitmap(bounds.Width, bounds.Height);
using (var graphics = Graphics.FromImage(result))
{
graphics.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
return result;
}
}
How to capture the whole screen:
var image = ScreenCapture.CaptureDesktop();
image.Save(#"C:\temp\snippetsource.jpg", ImageFormat.Jpeg);
How to capture the active window:
var image = ScreenCapture.CaptureActiveWindow();
image.Save(#"C:\temp\snippetsource.jpg", ImageFormat.Jpeg);
Originally found here: http://www.snippetsource.net/Snippet/158/capture-screenshot-in-c
KvanTTT's code worked great. I extended it a bit to allow a little more flexibility on save format, as well as the ability to save by hWnd, .NET Control/Form. You can get a bitmap or save to file, with a few options.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace MosaiqPerformanceMonitor {
public enum CaptureMode {
Screen, Window
}
public static class ScreenCapturer {
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
[StructLayout(LayoutKind.Sequential)]
private struct Rect {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow();
/// <summary> Capture Active Window, Desktop, Window or Control by hWnd or .NET Contro/Form and save it to a specified file. </summary>
/// <param name="filename">Filename.
/// <para>* If extension is omitted, it's calculated from the type of file</para>
/// <para>* If path is omitted, defaults to %TEMP%</para>
/// <para>* Use %NOW% to put a timestamp in the filename</para></param>
/// <param name="mode">Optional. The default value is CaptureMode.Window.</param>
/// <param name="format">Optional file save mode. Default is PNG</param>
public static void CaptureAndSave(string filename, CaptureMode mode = CaptureMode.Window, ImageFormat format = null) {
ImageSave(filename, format, Capture(mode));
}
/// <summary> Capture a specific window (or control) and save it to a specified file. </summary>
/// <param name="filename">Filename.
/// <para>* If extension is omitted, it's calculated from the type of file</para>
/// <para>* If path is omitted, defaults to %TEMP%</para>
/// <para>* Use %NOW% to put a timestamp in the filename</para></param>
/// <param name="handle">hWnd (handle) of the window to capture</param>
/// <param name="format">Optional file save mode. Default is PNG</param>
public static void CaptureAndSave(string filename, IntPtr handle, ImageFormat format = null) {
ImageSave(filename, format, Capture(handle));
}
/// <summary> Capture a specific window (or control) and save it to a specified file. </summary>
/// <param name="filename">Filename.
/// <para>* If extension is omitted, it's calculated from the type of file</para>
/// <para>* If path is omitted, defaults to %TEMP%</para>
/// <para>* Use %NOW% to put a timestamp in the filename</para></param>
/// <param name="c">Object to capture</param>
/// <param name="format">Optional file save mode. Default is PNG</param>
public static void CaptureAndSave(string filename, Control c, ImageFormat format = null) {
ImageSave(filename, format, Capture(c));
}
/// <summary> Capture the active window (default) or the desktop and return it as a bitmap </summary>
/// <param name="mode">Optional. The default value is CaptureMode.Window.</param>
public static Bitmap Capture(CaptureMode mode = CaptureMode.Window) {
return Capture(mode == CaptureMode.Screen ? GetDesktopWindow() : GetForegroundWindow());
}
/// <summary> Capture a .NET Control, Form, UserControl, etc. </summary>
/// <param name="c">Object to capture</param>
/// <returns> Bitmap of control's area </returns>
public static Bitmap Capture(Control c) {
return Capture(c.Handle);
}
/// <summary> Capture a specific window and return it as a bitmap </summary>
/// <param name="handle">hWnd (handle) of the window to capture</param>
public static Bitmap Capture(IntPtr handle) {
Rectangle bounds;
var rect = new Rect();
GetWindowRect(handle, ref rect);
bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
CursorPosition = new Point(Cursor.Position.X - rect.Left, Cursor.Position.Y - rect.Top);
var result = new Bitmap(bounds.Width, bounds.Height);
using (var g = Graphics.FromImage(result))
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
return result;
}
/// <summary> Position of the cursor relative to the start of the capture </summary>
public static Point CursorPosition;
/// <summary> Save an image to a specific file </summary>
/// <param name="filename">Filename.
/// <para>* If extension is omitted, it's calculated from the type of file</para>
/// <para>* If path is omitted, defaults to %TEMP%</para>
/// <para>* Use %NOW% to put a timestamp in the filename</para></param>
/// <param name="format">Optional file save mode. Default is PNG</param>
/// <param name="image">Image to save. Usually a BitMap, but can be any
/// Image.</param>
static void ImageSave(string filename, ImageFormat format, Image image) {
format = format ?? ImageFormat.Png;
if (!filename.Contains("."))
filename = filename.Trim() + "." + format.ToString().ToLower();
if (!filename.Contains(#"\"))
filename = Path.Combine(Environment.GetEnvironmentVariable("TEMP") ?? #"C:\Temp", filename);
filename = filename.Replace("%NOW%", DateTime.Now.ToString("yyyy-MM-dd#hh.mm.ss"));
image.Save(filename, format);
}
}
}
I assume you use Graphics.CopyFromScreen to get the screenshot.
You can use P/Invoke to GetForegroundWindow (and then get its position and size) to determine which region you need to copy from.
You can use the code from this question: How can I save a screenshot directly to a file in Windows?
Just change WIN32_API.GetDesktopWindow() to the Handle property of the window you want to capture.
If you want to use managed code: This will capture any window via the ProcessId.
I used the following to make the window active.
Microsoft.VisualBasic.Interaction.AppActivate(ProcessId);
Threading.Thread.Sleep(20);
I used the print screen to capture a window.
SendKeys.SendWait("%{PRTSC}");
Threading.Thread.Sleep(40);
IDataObject objData = Clipboard.GetDataObject();
Use the following code :
// Shot size = screen size
Size shotSize = Screen.PrimaryScreen.Bounds.Size;
// the upper left point in the screen to start shot
// 0,0 to get the shot from upper left point
Point upperScreenPoint = new Point(0, 0);
// the upper left point in the image to put the shot
Point upperDestinationPoint = new Point(0, 0);
// create image to get the shot in it
Bitmap shot = new Bitmap(shotSize.Width, shotSize.Height);
// new Graphics instance
Graphics graphics = Graphics.FromImage(shot);
// get the shot by Graphics class
graphics.CopyFromScreen(upperScreenPoint, upperDestinationPoint, shotSize);
// return the image
pictureBox1.Image = shot;
Works if the Desktop scaling is set.
public class ScreenCapture
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow();
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
public static Image CaptureDesktop()
{
return CaptureWindow(GetDesktopWindow());
}
public static Bitmap CaptureActiveWindow()
{
return CaptureWindow(GetForegroundWindow());
}
public static Bitmap CaptureWindow(IntPtr handle)
{
var rect = new Rect();
GetWindowRect(handle, ref rect);
GetScale getScale = new GetScale();
var bounds = new Rectangle(rect.Left, rect.Top, (int)((rect.Right - rect.Left)* getScale.getScalingFactor()), (int)((rect.Bottom - rect.Top )* getScale.getScalingFactor()));
var result = new Bitmap(bounds.Width, bounds.Height);
using (var graphics = Graphics.FromImage(result))
{
graphics.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
return result;
}
}
A little tweak to method static void ImageSave() will grant you the option where to save it. Credit goes to Microsoft (http://msdn.microsoft.com/en-us/library/sfezx97z.aspx)
static void ImageSave(string filename, ImageFormat format, Image image, SaveFileDialog saveFileDialog1)
{
saveFileDialog1.Filter = "JPeg Image|*.jpg|Bitmap Image|*.bmp|Gif Image|*.gif";
saveFileDialog1.Title = "Enregistrer un image";
saveFileDialog1.ShowDialog();
// If the file name is not an empty string open it for saving.
if (saveFileDialog1.FileName != "")
{
// Saves the Image via a FileStream created by the OpenFile method.
System.IO.FileStream fs =
(System.IO.FileStream)saveFileDialog1.OpenFile();
// Saves the Image in the appropriate ImageFormat based upon the
// File type selected in the dialog box.
// NOTE that the FilterIndex property is one-based.
switch (saveFileDialog1.FilterIndex)
{
case 1:
image.Save(fs,
System.Drawing.Imaging.ImageFormat.Jpeg);
break;
case 2:
image.Save(fs,
System.Drawing.Imaging.ImageFormat.Bmp);
break;
case 3:
image.Save(fs,
System.Drawing.Imaging.ImageFormat.Gif);
break;
}
fs.Close();
}
}
Your button_click event should be coded something like this...
private void btnScreenShot_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
ScreenCapturer.CaptureAndSave(filename, mode, format, saveFileDialog1);
}//
Based on ArsenMkrt's reply, but this one allows you to capture a control in your form (I'm writing a tool for example that has a WebBrowser control in it and want to capture just its display). Note the use of PointToScreen method:
//Project: WebCapture
//Filename: ScreenshotUtils.cs
//Author: George Birbilis (http://zoomicon.com)
//Version: 20130820
using System.Drawing;
using System.Windows.Forms;
namespace WebCapture
{
public static class ScreenshotUtils
{
public static Rectangle Offseted(this Rectangle r, Point p)
{
r.Offset(p);
return r;
}
public static Bitmap GetScreenshot(this Control c)
{
return GetScreenshot(new Rectangle(c.PointToScreen(Point.Empty), c.Size));
}
public static Bitmap GetScreenshot(Rectangle bounds)
{
Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
using (Graphics g = Graphics.FromImage(bitmap))
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
return bitmap;
}
public const string DEFAULT_IMAGESAVEFILEDIALOG_TITLE = "Save image";
public const string DEFAULT_IMAGESAVEFILEDIALOG_FILTER = "PNG Image (*.png)|*.png|JPEG Image (*.jpg)|*.jpg|Bitmap Image (*.bmp)|*.bmp|GIF Image (*.gif)|*.gif";
public const string CUSTOMPLACES_COMPUTER = "0AC0837C-BBF8-452A-850D-79D08E667CA7";
public const string CUSTOMPLACES_DESKTOP = "B4BFCC3A-DB2C-424C-B029-7FE99A87C641";
public const string CUSTOMPLACES_DOCUMENTS = "FDD39AD0-238F-46AF-ADB4-6C85480369C7";
public const string CUSTOMPLACES_PICTURES = "33E28130-4E1E-4676-835A-98395C3BC3BB";
public const string CUSTOMPLACES_PUBLICPICTURES = "B6EBFB86-6907-413C-9AF7-4FC2ABF07CC5";
public const string CUSTOMPLACES_RECENT = "AE50C081-EBD2-438A-8655-8A092E34987A";
public static SaveFileDialog GetImageSaveFileDialog(
string title = DEFAULT_IMAGESAVEFILEDIALOG_TITLE,
string filter = DEFAULT_IMAGESAVEFILEDIALOG_FILTER)
{
SaveFileDialog dialog = new SaveFileDialog();
dialog.Title = title;
dialog.Filter = filter;
/* //this seems to throw error on Windows Server 2008 R2, must be for Windows Vista only
dialog.CustomPlaces.Add(CUSTOMPLACES_COMPUTER);
dialog.CustomPlaces.Add(CUSTOMPLACES_DESKTOP);
dialog.CustomPlaces.Add(CUSTOMPLACES_DOCUMENTS);
dialog.CustomPlaces.Add(CUSTOMPLACES_PICTURES);
dialog.CustomPlaces.Add(CUSTOMPLACES_PUBLICPICTURES);
dialog.CustomPlaces.Add(CUSTOMPLACES_RECENT);
*/
return dialog;
}
public static void ShowSaveFileDialog(this Image image, IWin32Window owner = null)
{
using (SaveFileDialog dlg = GetImageSaveFileDialog())
if (dlg.ShowDialog(owner) == DialogResult.OK)
image.Save(dlg.FileName);
}
}
}
Having the Bitmap object you can just call Save on it
private void btnCapture_Click(object sender, EventArgs e)
{
webBrowser.GetScreenshot().Save("C://test.jpg", ImageFormat.Jpeg);
}
The above assumes the GC will grab the bitmap, but maybe it's better to assign the result of someControl.getScreenshot() to a Bitmap variable, then dispose that variable manually when finished with each image, especially if you're doing this grabbing often (say you have a list of webpages you want to load and save screenshots of them):
private void btnCapture_Click(object sender, EventArgs e)
{
Bitmap bitmap = webBrowser.GetScreenshot();
bitmap.ShowSaveFileDialog();
bitmap.Dispose(); //release bitmap resources
}
Even better, could employ a using clause, which has the added benefit of releasing the bitmap resources even in case of an exception occuring inside the using (child) block:
private void btnCapture_Click(object sender, EventArgs e)
{
using(Bitmap bitmap = webBrowser.GetScreenshot())
bitmap.ShowSaveFileDialog();
//exit from using block will release bitmap resources even if exception occured
}
Update:
Now WebCapture tool is ClickOnce-deployed (http://gallery.clipflair.net/WebCapture) from the web (also has nice autoupdate support thanks to ClickOnce) and you can find its source code at https://github.com/Zoomicon/ClipFlair/tree/master/Server/Tools/WebCapture
public static void ScreenCapFull_Clip(string strDestinationFolder, string strDestinationFile, bool bWriteToFile, bool bWriteToClipboard, out string strError)
{
strError = String.Empty;
if (strDestinationFile.Trim() == String.Empty) // Sort of hokey
bWriteToFile = false; // strDestinationFile = "c:\\temp\\clip.jpg";
int screenLeft = SystemInformation.VirtualScreen.Left;
int screenTop = SystemInformation.VirtualScreen.Top;
int screenWidth = SystemInformation.VirtualScreen.Width;
int screenHeight = SystemInformation.VirtualScreen.Height;
// Create a bitmap of the appropriate size to receive the full-screen screenshot.
using (Bitmap bitmap = new Bitmap(screenWidth, screenHeight))
{
// Draw the screenshot into our bitmap.
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(screenLeft, screenTop, 0, 0, bitmap.Size);
}
//Save the screenshot as a Jpg image
var uniqueFileName = strDestinationFile; // "C:\\temp\\a.Jpg";
try
{
if(bWriteToFile == true)
bitmap.Save(uniqueFileName, ImageFormat.Jpeg);
}
catch (Exception ex)
{
strError = "Error: Could not write to file: " + uniqueFileName + "-" + ex.Message + "...";
}
if (bWriteToClipboard == false)
return;
try
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
PictureBox pb = new PictureBox();
pb.Image = bitmap; //???
//Put the image in a memorystream. VpaResult.VpaImage is a picturebox.
//VpaResult.VpaImage.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
pb.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
DataObject m_data = new DataObject();
m_data.SetData("PNG", true, ms);
Clipboard.SetDataObject(m_data, true);
}
catch (Exception ex)
{
strError += "Error: Could not write to Clipboard: " + ex.Message + "...";
strError = ex.Message;
}
}
} // End public static void ScreenCapFull_Clip

Categories