Saving screenshots in a serial manner - c#

I'm trying to capture screenshots as long as the user interrupts, but I've gone far to get a single screenshot and save it using a hard-coded filename. It goes like this:
Bitmap bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
bmpScreenshot.Save("Screenshot.jpeg", ImageFormat.Jpeg);
The problem is this enables me to take a single screenshot, and I need multiple screenshots to be saved at the same time. I can't find a suitable way to do this without hard-coding and jeopardizing the code at the same time. I would really appreciate help on this.
Thanks.

The taking a screenshot part is probably fast and needs to happen no matter what.
You can take many screenshots and save them later. You can use a ConcurrentQueue to do that:
Bitmap bmpScreenshot = Bitmap bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height,PixelFormat.Format32bppArgb);
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
_queue.Enqueue(bmpScreenshot);
And then have a thread that dequeues and saves:
index = 0;
while (_queue.Count > 0)
{
Bitmap bitmap = null;
if (_queue.TryDequeue(out bitmap))
{
bitmap.Save("Screenshot" + index + ".jpeg", ImageFormat.Jpeg);
index++;
}
}
An even more robust solution would be to use TPL Dataflow, but that may be an overkill.

Related

Take a screenshot of part of screen in c# [duplicate]

This question already has answers here:
C#: how to take a screenshot of a portion of screen
(4 answers)
Closed 1 year ago.
I want to take a screenshot of a specific part of a website using C# or .net Code, I can't create a Windows form application as it must be embedded into something else.
Here is what I got so far:
using System.Drawing.Imaging;
using System.Drawing;
using System;
using System.Windows.Forms;
try
{
//Creating a new Bitmap object
Bitmap captureBitmap = new Bitmap(1024, 768, PixelFormat.Format32bppArgb);
//Bitmap captureBitmap = new Bitmap(int width, int height, PixelFormat);
//Creating a Rectangle object which will
//capture our Current Screen
Rectangle captureRectangle = Screen.AllScreens[0].Bounds;
//Creating a New Graphics Object
Graphics captureGraphics = Graphics.FromImage(captureBitmap);
//Copying Image from The Screen
captureGraphics.CopyFromScreen(captureRectangle.Left,captureRectangle.Top,0,0,captureRectangle.Size);
//Saving the Image File (I am here Saving it in My E drive).
captureBitmap.Save(#"E:\Capture.jpg",ImageFormat.Jpeg);
//Displaying the Successfull Result
MessageBox.Show("Screen Captured");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
This code works fine as long as I am creating a windows form application, but as soon as I change it to console it doesn't work even after adding the "using System.Windows.Forms;" and it produces this error:
//Screen does not exist in the current context
So Is there any solution for this or any other way I could take a screenshot of a specific part of a website Programmatically without connecting to it at all.
Thanks in advance.
I actually found an answer one minute after posting from the suggested links "which btw didn't show in search I did for 2 days for some reason" but anyway
its This question
and its as simple as
Rectangle rect = new Rectangle(0, 0, 100, 100);
Bitmap bmp = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bmp);
g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size,
CopyPixelOperation.SourceCopy);
bmp.Save(fileName, ImageFormat.Jpeg);

Making screenshots very fast and out of memory

I am trying to make screenshots of my screen very fast.
So, I use this code in my main class
[STAThread]
static void Main(string[] args)
{
int x = 1;
int screenshotsAmount = 0;
List<Bitmap> screenshots = new List<Bitmap>();
while (x == 1)
{
screenshots.Add(FullsizeScreenshot.makeScreenshot());
Clipboard.SetImage(screenshots[screenshotsAmount]);
Console.WriteLine("Screenshot " + screenshotsAmount + " has been made and added to the Bitmap list!");
screenshotsAmount++;
}
}
And I have a method in my .dll, that creates screenshots
// Class for making standard screenshots
public struct FullsizeScreenshot
{
// Making fullscreen screenshot
public static Bitmap makeScreenshot()
{
Bitmap screenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
Graphics gfxScreenshot = Graphics.FromImage(screenshot);
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
gfxScreenshot.Dispose();
return screenshot;
}
}
Everything works correct, but when the number of screenshots becomes bigger than 109, my program crash with System.ArgumentException
An unhandled exception of type "System.ArgumentException" in System.Drawing.dll
Additional information: Invalid parameter.
This line throws it:
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
or this:
Bitmap screenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
I tried to use using (Bitmap screenshot....) and .Dispose(), but it doesn't work correct, because these classes (Bitmap and Graphics) are classes and they just create links instead of making copies. As a result, when I dispose the Bitmap in makeScreenshot() it broke the Bitmap in my List.
So, what should I do? Maybe I should make a copy, but I don't know how.
Suppose you have a display of 1920x1080, that's 2,073,600 pixels, there are 4 bytes per pixel in a PixelFormat.Format32bppArgb So that's 8,294,400 bytes, or around 8 MB. 109 images would be 872 MB. Surprised that's crashing there, but you get the idea, it's too much memory.
If you want to make an animated gif, think how large that's going to be, full screen? Well I hope you're not planing on that, that's not practical for a gif. After you take the screenshot, resize it down immediately to the target resolution so it takes less memory.

Getting black image while taking screenshot of videos c#

I have used the below code for taking screenshots in c# and it worked. However when I tried to take screenshots when a video is played, I am getting only black pixels for the video part and the rest of the screen is captured.
Please could anyone help me on this.
Here's my code :
String filePath = Path.Combine(Application.StartupPath, "Temp.Jpeg");
Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics graphics = Graphics.FromImage(bitmap as Image);
graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
bitmap.Save("Temp.Jpeg", ImageFormat.Jpeg);
System.IO.FileStream Imagestream = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
Also please may I know why I am getting these black pixels?

C# method CopyfFromScreen crashes after 200 uses?

For my program I need a method which takes a screenshot every half a minute. I googled and came up with this method:
public static Bitmap CaptureScreen()
{
Bitmap BMP = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics GFX = Graphics.FromImage(BMP);
GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Seen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
return BMP;
}
Well all works fine for the first 200 uses of the method or so. Then the function crashes at CopyFromScreen and it says that it caused an invalid argument exception. I'm slightly confused why that is because the parameters don't change.
Could it be that the function itself just has a bug? If so are there any alternatives to take a screenshot?
Probably two separate failures to dispose. Both Graphics and Image / Bitmap implement IDisposable, so the "obvious" of the two is here:
using(Graphics GFX = Graphics.FromImage(BMP)) {
GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,Seen.PrimaryScreen.Bounds.Y,
0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
}
return BMP;
However: the caller of your method should also be using the result of CaptureScreen (to release the bitmap's GDI+ handle), i.e.
using(var screen = CaptureScreen()) {
// some work here
}

CopyFromScreen not working

This one is slightly confusing...
I am using Adobe's PDF Viewer control to view PDFs but I want the user to be able to drag an image onto the PDF and then when they click save it adds the image to the PDF at that location.
Implementing the PDF viewer proved quite difficult but I decided in the end to use Adobe's control, take a picture and then allow the user to draw the image ontop of the picture of the PDF. When they click save I am going to use PDFSharp to put the image onto the PDF once I've worked out where it goes but the problem I have at the moment is that I can't get a picture of the PDF.
The following code is used to get the picture but the Panel that it is attached to just appears with a white background with a red 'X' and border...
using (Bitmap bitmap = new Bitmap(adobePDFViewer1.Width, adobePDFViewer1.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(new Point(adobePDFViewer1.Left, adobePDFViewer1.Top), Point.Empty, adobePDFViewer1.Size);
}
panelOverPdfViewer.BackgroundImage = bitmap;
}
I don't think this is the best way of doing it but I couldn't work out any others. Any help would be appreciated!
EDIT:
Following a very helpful answer below this is working code:
Here is the code I used:
Bitmap printscreen = new Bitmap(adobePDFViewer1.Width, adobePDFViewer1.Height);
Graphics graphics = Graphics.FromImage(printscreen as Image);
int left = this.Left + 396;
int top = this.Top + 30;
graphics.CopyFromScreen(left, top, 0, 0, printscreen.Size);
pictureBoxOverPDFView.Image = printscreen;
Look at this this Print-Screen
and try this for test work of CopyFromScreen
private void PrintScreen()
{
Bitmap printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics graphics = Graphics.FromImage(printscreen as Image);
graphics.CopyFromScreen(0, 0, 0, 0, printscreen.Size);
printscreen.Save(#"C:\Temp\printscreen.jpg", ImageFormat.Jpeg);
}

Categories