⬆️ ⬇️

Taking screenshots (screens) in a format convenient for WPF

Some time ago I needed a tool with which I could programmatically create snapshots from the whole monitor screen or from some of its areas. In this case, it is necessary to specify the area not only programmatically, but also manually by the user with the mouse. The result obtained should be immediately packed into an instance of one of the classes, which I would be convenient to use to display the resulting screen in the GUI (graphical user interface):





My decision on which class of objects should be packed into the final result is due to the convenience of their (classes) use in WPF:

The System.Drawing.Bitmap class contains the Save method, which allows you to write the resulting snapshot into a raster image file (specifying what type of file you should create).

The System.Windows.Media.Imaging.BitmapImage class is often used as a data source for System.Windows.Controls.Image, used in WPF to display bitmap images.

The System.IO.MemoryStream class was necessary for me in order to be able to save an image to a database table, although, of course, this is far from the only case in which an image presented in this form may be needed.



Searching Google for a ready-made solution and not finding something that would completely correspond to my desire - I sat down to write my library. I decided to implement the necessary functionality as methods of a static class. I assign the class the name ScreenManager. It should implement the following methods:





')

The end result should be presented as a dll-library with an xml-file containing information about it.



The ScreenManager class is made partial in order to distribute the code among different cs files in accordance with the logic of the actions they perform. I will have three such files:



The ProgramMethods.cs file will contain those methods that will allow you to take pictures of the entire screen or its region in transparent mode, without requiring the user to specify the boundaries of the region manually.

The file ManuallyMethods.cs, on the contrary, should encapsulate in itself methods that will prompt the user to specify the screen area with which to take the picture. The user will have to press the left mouse button, thereby indicating the first corner of the area and, without releasing the button, indicate the opposite diagonal angle, releasing the button on it. In the process of moving the mouse pointer on the screen, the area of ​​the selectable border should be indicated by a rectangle of a certain color, which dynamically changes its size as the mouse moves around the monitor screen. If during the selection process, the user presses the Escape key, the snapshot command should be interrupted. The color of the rectangle and the thickness of the lines should be customizable through the static RectangleBrush and RectangleLineWeigth properties of the ScreenManager class.

The InnerMethods.cs file will contain a set of helper methods necessary for the operation of the code for the ManuallyMethods.cs file.



After the library code is completely written, you will need to create a test application (let's call it “WPF test”), demonstrating the work of the library. This will be a small WPF window, with an Image and Button object, sufficient for the required demonstration.



Well, that's all ... The following is the source code for the cs-files I mentioned above:

ProgramMethods.cs file



1: using System;<br> 2: using System.Collections. Generic ;<br> 3: using System.Linq;<br> 4: using System.Text;<br> 5: using System.Windows.Forms;<br> 6: using System.Drawing;<br> 7: using System.Drawing.Imaging;<br> 8: using System.Windows.Media.Imaging;<br> 9: using System.IO;<br> 10: using System.Windows.Shapes;<br> 11: using System.Windows.Controls;<br> 12: using System.Windows.Input;<br> 13: using System.Windows;<br> 14: <br> 15: namespace Bushman.Screens<br> 16: {<br> 17: /// <summary> <br> 18: /// <br> 19: /// <br> 20: /// </summary> <br> 21: public static partial class ScreenManager<br> 22: {<br> 23: // , (.. ). <br> 24: /// <summary> <br> 25: /// , BitmapImage. . <br> 26: /// </summary> <br> 27: /// <param name="rect"> System.Drawing.Rectangle, , <br> 28: /// </param> <br> 29: /// <param name="format"> , </param> <br> 30: /// <returns> , BitmapImage</returns> <br> 31: public static BitmapImage GetBitmapImageFromScreen(System.Drawing.Rectangle rect, ImageFormat format)<br> 32: {<br> 33: using (MemoryStream ms = new MemoryStream())<br> 34: {<br> 35: Screen screen = Screen.FromRectangle(rect);<br> 36: Bitmap bitmap = new Bitmap (rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); <br> 37: Graphics graphics = Graphics .FromImage(bitmap);<br> 38: graphics.CopyFromScreen(rect.X, rect.Y, 0, 0, rect.Size, CopyPixelOperation.SourceCopy); <br> 39: bitmap.Save(ms, format);<br> 40: BitmapImage img = new BitmapImage();<br> 41: img.BeginInit();<br> 42: img.CacheOption = BitmapCacheOption.OnLoad;<br> 43: img.StreamSource = ms;<br> 44: img.EndInit();<br> 45: return img;<br> 46: }<br> 47: }<br> 48: /// <summary> <br> 49: /// , BitmapImage. . <br> 50: /// </summary> <br> 51: /// <returns> , BitmapImage</returns> <br> 52: public static BitmapImage GetBitmapImageFromScreen( ImageFormat format)<br> 53: {<br> 54: System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);<br> 55: return GetBitmapImageFromScreen(rect, format);<br> 56: }<br> 57: <br> 58: /// <summary> <br> 59: /// , MemoryStream. . <br> 60: /// </summary> <br> 61: /// <param name="rect"> System.Drawing.Rectangle, , <br> 62: /// </param> <br> 63: /// <param name="format"> , </param> <br> 64: /// <returns> , MemoryStream</returns> <br> 65: public static MemoryStream GetMemoryStreamFromScreen(System.Drawing.Rectangle rect, ImageFormat format)<br> 66: {<br> 67: MemoryStream ms = new MemoryStream();<br> 68: Screen screen = Screen.FromRectangle(rect);<br> 69: Bitmap bitmap = new Bitmap (rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);<br> 70: Graphics graphics = Graphics .FromImage(bitmap);<br> 71: graphics.CopyFromScreen(rect.X, rect.Y, 0, 0, rect.Size, CopyPixelOperation.SourceCopy);<br> 72: bitmap.Save(ms, format);<br> 73: return ms;<br> 74: }<br> 75: <br> 76: /// <summary> <br> 77: /// , MemoryStream. . <br> 78: /// </summary> <br> 79: /// <returns> , MemoryStream</returns> <br> 80: public static MemoryStream GetMemoryStreamFromScreen( ImageFormat format)<br> 81: {<br> 82: System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);<br> 83: return GetMemoryStreamFromScreen(rect, format);<br> 84: }<br> 85: <br> 86: /// <summary> <br> 87: /// , Bitmap. . <br> 88: /// </summary> <br> 89: /// <param name="rect"> System.Drawing.Rectangle, , <br> 90: /// </param> <br> 91: /// <returns> , Bitmap</returns> <br> 92: public static Bitmap GetBitmapFromScreen(System.Drawing.Rectangle rect)<br> 93: {<br> 94: Screen screen = Screen.FromRectangle(rect);<br> 95: Bitmap bitmap = new Bitmap (rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);<br> 96: Graphics graphics = Graphics .FromImage(bitmap);<br> 97: graphics.CopyFromScreen(rect.X, rect.Y, 0, 0, rect.Size, CopyPixelOperation.SourceCopy); <br> 98: return bitmap;<br> 99: }<br> 100: <br> 101: /// <summary> <br> 102: /// , Bitmap. . <br> 103: /// </summary> <br> 104: /// <returns> , Bitmap</returns> <br> 105: public static Bitmap GetBitmapFromScreen()<br> 106: {<br> 107: System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);<br> 108: return GetBitmapFromScreen(rect);<br> 109: }<br> 110: }<br> 111: } <br><br> * This source code was highlighted with Source Code Highlighter .




ManuallyMethods.cs file



1: using System;<br> 2: using System.Collections. Generic ;<br> 3: using System.Linq;<br> 4: using System.Text;<br> 5: using System.Windows.Forms;<br> 6: using System.Drawing;<br> 7: using System.Drawing.Imaging;<br> 8: using System.Windows.Media.Imaging;<br> 9: using System.IO;<br> 10: using System.Windows.Shapes;<br> 11: using System.Windows.Controls;<br> 12: using System.Windows.Input;<br> 13: using System.Windows;<br> 14: <br> 15: namespace Bushman.Screens<br> 16: {<br> 17: // , () <br> 18: public static partial class ScreenManager<br> 19: {<br> 20: // , () , <br> 21: //************************************** <br> 22: <br> 23: // , : <br> 24: static Window win; //, <br> 25: static System.Windows.Point firstPoint; // <br> 26: static System.Windows.Point secondPoint; // ( ) <br> 27: static Canvas canvas;<br> 28: static System.Windows.Controls.Image image;<br> 29: static List <Line> lines; // , <br> 30: static ImageFormat format;<br> 31: static MemoryStream result;<br> 32: static System.Windows.Media.Brush rectangleBrush = System.Windows.Media.Brushes.Black;<br> 33: static double rectangleLineWeigth = 5;<br> 34: <br> 35: /// <summary> <br> 36: /// , <br> 37: /// </summary> <br> 38: public static System.Windows.Media.Brush RectangleBrush<br> 39: {<br> 40: get { return rectangleBrush; }<br> 41: set { rectangleBrush = value ; }<br> 42: }<br> 43: /// <summary> <br> 44: /// , <br> 45: /// </summary> <br> 46: public static double RectangleLineWeigth<br> 47: {<br> 48: get { return rectangleLineWeigth; }<br> 49: set { rectangleLineWeigth = value ; }<br> 50: }<br> 51: <br> 52: /// <summary> <br> 53: /// , <br> 54: /// </summary> <br> 55: /// <param name="imgFormat"> , </param> <br> 56: /// <returns> MemoryStream</returns> <br> 57: public static MemoryStream GetMemoryStreamFromScreenManually( ImageFormat imgFormat)<br> 58: {<br> 59: format = imgFormat;<br> 60: // , <br> 61: win = new Window() { WindowState = WindowState.Maximized, WindowStyle = WindowStyle.None };<br> 62: <br> 63: // , BitmapImage <br> 64: BitmapImage bitmapImage = ScreenManager.GetBitmapImageFromScreen( ImageFormat .Png);<br> 65: <br> 66: // <br> 67: image = new System.Windows.Controls.Image() { Source = bitmapImage };<br> 68: canvas = new Canvas() { Width = Screen.PrimaryScreen.Bounds.Width, Height = Screen.PrimaryScreen.Bounds.Height };<br> 69: canvas.Children.Add(image);<br> 70: Canvas.SetTop(image, 0);<br> 71: Canvas.SetLeft(image, 0);<br> 72: win.Content = canvas;<br> 73: <br> 74: // <br> 75: image.MouseLeftButtonDown += new MouseButtonEventHandler(image_MouseLeftButtonDown);<br> 76: // <br> 77: // <br> 78: image.MouseMove += new System.Windows.Input.MouseEventHandler(image_MouseMove);<br> 79: <br> 80: //================ <br> 81: //************************************************************ <br> 82: //================ <br> 83: <br> 84: // , 2- , <br> 85: // , <br> 86: image.MouseLeftButtonUp += new MouseButtonEventHandler(image_MouseLeftButtonUp);<br> 87: // Escape , , <br> 88: image.KeyDown += new System.Windows.Input.KeyEventHandler(image_KeyDown);<br> 89: // <br> 90: win.ShowDialog();<br> 91: return result;<br> 92: }<br> 93: <br> 94: /// <summary> <br> 95: /// , <br> 96: /// </summary> <br> 97: /// <param name="imgFormat"> , </param> <br> 98: /// <returns> Bitmap</returns> <br> 99: public static Bitmap GetBitmapFromScreenManually( ImageFormat imgFormat)<br> 100: {<br> 101: MemoryStream ms = GetMemoryStreamFromScreenManually(imgFormat);<br> 102: return new Bitmap (ms);<br> 103: }<br> 104: <br> 105: /// <summary> <br> 106: /// , <br> 107: /// </summary> <br> 108: /// <param name="imgFormat"> , </param> <br> 109: /// <returns> BitmapImage</returns> <br> 110: public static BitmapImage GetBitmapImageFromScreenManually( ImageFormat imgFormat)<br> 111: {<br> 112: MemoryStream ms = GetMemoryStreamFromScreenManually(imgFormat);<br> 113: BitmapImage bitmapImg = new BitmapImage();<br> 114: bitmapImg.BeginInit();<br> 115: bitmapImg.CacheOption = BitmapCacheOption.OnLoad;<br> 116: bitmapImg.StreamSource = ms;<br> 117: bitmapImg.EndInit();<br> 118: bitmapImg.Freeze();<br> 119: return bitmapImg;<br> 120: }<br> 121: }<br> 122: } <br><br> * This source code was highlighted with Source Code Highlighter .




InnerMethods.cs file



1: using System;<br> 2: using System.Collections. Generic ;<br> 3: using System.Linq;<br> 4: using System.Text;<br> 5: using System.Windows.Forms;<br> 6: using System.Drawing;<br> 7: using System.Drawing.Imaging;<br> 8: using System.Windows.Media.Imaging;<br> 9: using System.IO;<br> 10: using System.Windows.Shapes;<br> 11: using System.Windows.Controls;<br> 12: using System.Windows.Input;<br> 13: using System.Windows;<br> 14: <br> 15: namespace Bushman.Screens<br> 16: {<br> 17: // , () <br> 18: public static partial class ScreenManager<br> 19: {<br> 20: static void image_KeyDown( object sender, System.Windows.Input.KeyEventArgs e)<br> 21: {<br> 22: if (e.Key == Key.Escape) win.Close();<br> 23: }<br> 24: <br> 25: static void image_MouseLeftButtonDown( object sender, MouseButtonEventArgs e)<br> 26: {<br> 27: firstPoint = e.GetPosition(win);<br> 28: lines = new List <Line>();<br> 29: for ( int i = 0; i < 4; i++)<br> 30: {<br> 31: Line item = new Line();<br> 32: item.Stroke = RectangleBrush;<br> 33: item.StrokeThickness = RectangleLineWeigth;<br> 34: canvas.Children.Add(item);<br> 35: Canvas.SetTop(item, firstPoint.Y);<br> 36: Canvas.SetLeft(item, firstPoint.X);<br> 37: item.StrokeEndLineCap = System.Windows.Media.PenLineCap.Round;<br> 38: item.StrokeStartLineCap = System.Windows.Media.PenLineCap.Round;<br> 39: item.Y2 = 0;<br> 40: item.X2 = 0;<br> 41: lines.Add(item);<br> 42: item.MouseLeftButtonUp += new MouseButtonEventHandler(image_MouseLeftButtonUp);<br> 43: item.KeyDown += new System.Windows.Input.KeyEventHandler(image_KeyDown);<br> 44: }<br> 45: }<br> 46: <br> 47: static void image_MouseMove( object sender, System.Windows.Input.MouseEventArgs e)<br> 48: {<br> 49: if (e.LeftButton == MouseButtonState.Pressed)<br> 50: {<br> 51: lines[0].Y2 = e.GetPosition(win).Y - firstPoint.Y;<br> 52: <br> 53: lines[1].X2 = e.GetPosition(win).X - firstPoint.X;<br> 54: <br> 55: lines[2].Y1 = lines[0].Y2;<br> 56: lines[2].Y2 = lines[2].Y1;<br> 57: lines[2].X2 = lines[1].X2;<br> 58: <br> 59: lines[3].X1 = lines[1].X2;<br> 60: lines[3].X2 = lines[3].X1;<br> 61: lines[3].Y2 = lines[0].Y2;<br> 62: }<br> 63: }<br> 64: <br> 65: static void image_MouseLeftButtonUp( object sender, MouseButtonEventArgs e)<br> 66: {<br> 67: GetSecondPoint(e.GetPosition(win));<br> 68: }<br> 69: <br> 70: static void GetSecondPoint(System.Windows.Point point)<br> 71: {<br> 72: foreach (Line line in lines)<br> 73: {<br> 74: canvas.Children.Remove(line);<br> 75: }<br> 76: secondPoint = point;<br> 77: int top = ( int ) Math .Min(firstPoint.Y, secondPoint.Y);<br> 78: int left = ( int ) Math .Min(firstPoint.X, secondPoint.X);<br> 79: int height = ( int )( Math .Max(firstPoint.Y, secondPoint.Y) - Math .Min(firstPoint.Y, secondPoint.Y));<br> 80: int width = ( int )( Math .Max(firstPoint.X, secondPoint.X) - Math .Min(firstPoint.X, secondPoint.X));<br> 81: <br> 82: // , , <br> 83: System.Drawing.Rectangle rect = new System.Drawing.Rectangle(left, top, width, height);<br> 84: result = ScreenManager.GetMemoryStreamFromScreen(rect, format);<br> 85: // <br> 86: win.Close();<br> 87: }<br> 88: //************************************** <br> 89: }<br> 90: } <br><br> * This source code was highlighted with Source Code Highlighter .




The following is the code for the WpfTest test application:



Window1.xaml file



1: < Window x:Class ="WpfTest.Window1" <br> 2: xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation" <br> 3: xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml" <br> 4: Title ="ScreenManager testing" Height ="300" Width ="300" > <br> 5: < Grid > <br> 6: < Grid.RowDefinitions > <br> 7: < RowDefinition Height ="100*" /> <br> 8: < RowDefinition Height ="Auto" /> <br> 9: </ Grid.RowDefinitions > <br> 10: < Image Name ="img" HorizontalAlignment ="Center" ></ Image > <br> 11: < StackPanel Name ="stack" Grid . Row ="1" > <br> 12: < Button Name ="btnSaveScreen" > Save screen (manually method) </ Button > <br> 13: </ StackPanel > <br> 14: </ Grid > <br> 15: </ Window > <br><br> * This source code was highlighted with Source Code Highlighter .




Window1.xaml.cs file



1: using System;<br> 2: using System.Collections. Generic ;<br> 3: using System.Linq;<br> 4: using System.Text;<br> 5: using System.Windows;<br> 6: using System.Windows.Controls;<br> 7: using System.Windows.Data;<br> 8: using System.Windows.Documents;<br> 9: using System.Windows.Input;<br> 10: using System.Windows.Media;<br> 11: using System.Windows.Media.Imaging;<br> 12: using System.Windows.Navigation;<br> 13: using System.Windows.Shapes;<br> 14: using System.Drawing.Imaging;<br> 15: using System.Drawing;<br> 16: using Bushman.Screens;<br> 17: using System.IO;<br> 18: <br> 19: namespace WpfTest<br> 20: {<br> 21: /// <summary> <br> 22: /// Interaction logic for Window1.xaml <br> 23: /// </summary> <br> 24: public partial class Window1 : Window<br> 25: {<br> 26: public Window1()<br> 27: {<br> 28: InitializeComponent();<br> 29: MyInitialize();<br> 30: }<br> 31: void MyInitialize()<br> 32: {<br> 33: btnSaveScreen.Click += new RoutedEventHandler(btnSaveScreenManually_Click);<br> 34: }<br> 35: <br> 36: void btnSaveScreenManually_Click( object sender, RoutedEventArgs e)<br> 37: {<br> 38: string dirName = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "ScreenResults" );<br> 39: DirectoryInfo dir = new DirectoryInfo(dirName);<br> 40: if (!dir.Exists) dir = Directory .CreateDirectory(dirName);<br> 41: System.Drawing.Rectangle rect = new System.Drawing.Rectangle(50, 50, 300, 200);<br> 42: Bitmap bitmap;<br> 43: MemoryStream ms;<br> 44: <br> 45: /// , . , <br> 46: /// . <br> 47: <br> 48: // 1 <br> 49: //bitmap = ScreenManager.GetBitmapFromScreen(); <br> 50: //bitmap.Save(System.IO.Path.Combine(dir.FullName, "GetBitmapFromScreen_0.png")); <br> 51: //bitmap.Dispose(); <br> 52: <br> 53: // 2 <br> 54: //bitmap = ScreenManager.GetBitmapFromScreen(rect); <br> 55: //bitmap.Save(System.IO.Path.Combine(dir.FullName, "GetBitmapFromScreen_1.png")); <br> 56: //bitmap.Dispose(); <br> 57: <br> 58: // 3 <br> 59: //bitmap = ScreenManager.GetBitmapFromScreenManually(ImageFormat.Png); <br> 60: //bitmap.Save(System.IO.Path.Combine(dir.FullName, "GetBitmapFromScreenManually.png")); <br> 61: //bitmap.Dispose(); <br> 62: <br> 63: // 4 <br> 64: //img.Source = ScreenManager.GetBitmapImageFromScreen(ImageFormat.Png); <br> 65: <br> 66: // 5 <br> 67: //img.Source = ScreenManager.GetBitmapImageFromScreen(rect, ImageFormat.Png); <br> 68: <br> 69: // 6 <br> 70: img.Source = ScreenManager.GetBitmapImageFromScreenManually( ImageFormat .Png);<br> 71: <br> 72: // 7 <br> 73: //ms = ScreenManager.GetMemoryStreamFromScreen(ImageFormat.Png); <br> 74: //bitmap = new Bitmap(ms); <br> 75: //bitmap.Save(System.IO.Path.Combine(dir.FullName, "GetMemoryStreamFromScreen_0.png")); <br> 76: //bitmap.Dispose(); <br> 77: <br> 78: // 8 <br> 79: //ms = ScreenManager.GetMemoryStreamFromScreen(rect, ImageFormat.Png); <br> 80: //bitmap = new Bitmap(ms); <br> 81: //bitmap.Save(System.IO.Path.Combine(dir.FullName, "GetMemoryStreamFromScreen_1.png")); <br> 82: //bitmap.Dispose(); <br> 83: <br> 84: // 9 <br> 85: //ms = ScreenManager.GetMemoryStreamFromScreenManually(ImageFormat.Png); <br> 86: //bitmap = new Bitmap(ms); <br> 87: //bitmap.Save(System.IO.Path.Combine(dir.FullName, "GetMemoryStreamFromScreenManually.png")); <br> 88: //bitmap.Dispose(); <br> 89: }<br> 90: }<br> 91: } <br><br> * This source code was highlighted with Source Code Highlighter .




The result of the test application is as follows (the result is displayed in the “ScreenManager testing” window):







The code is written using MS Visual Studio 2008 SP1 and .Net Framework 3.5 SP1.

The source code of the project is here .

Release version of the library here .

Source: https://habr.com/ru/post/94292/



All Articles