I would like to print an image of a dialog, as if [alt][Print Scrn] were used. Does the framework allow for this to be done programmatically?
The Graphics.CopyFromScreen(..) method should do what you need.
Here's a good sample I found on the web:
http://www.geekpedia.com/tutorial181_Capturing-screenshots-using-Csharp.html
EDIT: Code sample: (I created it as an extension method)
public static class FormExtensions
{
public static void SaveAsImage(this Form form, string fileName, ImageFormat format)
{
var image = new Bitmap(form.Width, form.Height);
using (Graphics g = Graphics.FromImage(image))
{
g.CopyFromScreen(form.Location, new Point(0, 0), form.Size);
}
image.Save(fileName, format);
}
}
can be used:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.SaveAsImage("foo.bmp", ImageFormat.Bmp);
}
}
What you could probably do is use the existing DLL that has that functionality for windows. It looks like you need to grab either some key commands or do it with a form button, and use the User32.dll. Since interop can sometimes be a big pain, I found a resource here that might help you do what you want:
http://www.cornetdesign.com/2005/04/screen-print-capture-in-c-using_08.html
If you really want just the dialog, use Control.DrawToBitmap to get a BMP image from it.
Related
I'm trying to save and restore the window bounds using Cocoa with C#. I tried the following according to docs, but it does not work. What I'm missing?
public class MyWindow: NSWindow
{
internal MyWindow() : base()
{
SetSavedFrame();
//Attach window will close event to MyWindow_WillClose
[...]
}
[...]
void SetSavedFrame()
{
FrameAutosaveName = AUTOSAVE_NAME;
if (SetFrameUsingName(FrameAutosaveName, true))
return;
SetFrame(new RectangleF (0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT), true);
Center();
}
void MyWindow_WillClose(object sender, EventArgs args)
{
SaveFrameUsingName(FrameAutosaveName);
}
}
If I cat the content of my .plist file, it is always the same, so I think the problem is, at least, when saving the preferences.
Thank you.
Is there any way to capture or copy the loaded image from the web browser to the picture box?
The image I am tring to copy is "captcha" image and every request it will change. I need the loaded image in the web browser be the same as the picture box.
I have tried to split the img tag and request the image again. It worked but the picture box image was not the same as the one the web browser shows.
Here is what I have done so far. It contains one web browser, one picture box, one text box, and one button
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.IO;
using System.Net;
namespace arman_dobare_kir_mishavad
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string str2 = webBrowser1.DocumentText;
string[] strArray2;
strArray2 = Regex.Split(Regex.Split(str2, "<img id=\"content1_imgCaptcha\" src=\"")[1], "\"");
textBox1.Text = strArray2[0];
this.pictureBox1.ImageLocation = "http://www.hashkiller.co.uk" + strArray2[0];
return;
}
public void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
}
}
}
This i quite a tricky one that took me months to solve.
First things first. As you have discovered nearly all captcha images are dynamically generated images, this means that each time you request the image, even though the url (src tag) is the same, a new captcha image will always generated.
Your best bet to solve this is by "snipping" the already loaded captcha image out of your webbrowser. Trust me, this is the best way, if not the only way.
The good news is, it can easily be done with a built in method
webBrowser.DrawToBitmap(Bitmap,Rectangle)
My Sample Code: (how to use webbrowser.DrawToBitmap for an specific Element)
private void button1_Click(object sender, EventArgs e)
{
int CaptchaWidth = getXoffset(webBrowser1.Document.GetElementById("Captch-Element-Name"));
int CaptchaHeight = getYoffset(webBrowser1.Document.GetElementById("Captch-Element-Name"));
Bitmap bitmap = new Bitmap(CaptchaWidth, CaptchaHeight);
webBrowser1.DrawToBitmap(bitmap, new Rectangle(0, 0, CaptchaWidth, CaptchaHeight));
//now load the image into your pictureBox (you might need to convert the bitmap to a image)
}
//Methods to get Co-ordinates Of an Element in your webbrowser
public int getXoffset(HtmlElement el)
{
int xPos = el.OffsetRectangle.Left;
HtmlElement tempEl = el.OffsetParent;
while (tempEl != null)
{
xPos += tempEl.OffsetRectangle.Left;
tempEl = tempEl.OffsetParent;
}
return xPos;
}
public int getYoffset(HtmlElement el)
{
int yPos = el.OffsetRectangle.Top;
HtmlElement tempEl = el.OffsetParent;
while (tempEl != null)
{
yPos += tempEl.OffsetRectangle.Top;
tempEl = tempEl.OffsetParent;
}
return yPos;
}
So, the bad news is that c# has a annoying little bug in the drawtobitmap method (which is mentioned on the msdn site). What happens is sometimes a blank image will be returned when you run it.... yeah... not really what you want when you trying to crack Captchas right!
Luckily! Another stackOverflow user and i spent months working on a bug free version of this method that makes use of native GDI+.
And it works perfectly, so if drawtobitmap doesn't work the way you expect, here is an alternative.
Sample:
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
public Bitmap CaptureWindow(Control ctl)
{
//Bitmap bmp = new Bitmap(ctl.Width, ctl.Height); // includes borders
Bitmap bmp = new Bitmap(ctl.ClientRectangle.Width, ctl.ClientRectangle.Height); // content only
using (Graphics graphics = Graphics.FromImage(bmp))
{
IntPtr hDC = graphics.GetHdc();
try { PrintWindow(ctl.Handle, hDC, (uint)0); }
finally { graphics.ReleaseHdc(hDC); }
}
return bmp;
}
So you'll simply call:
CaptureWindow(webBrowser1);
This will return a image of the entire webbrowser, then just snip-out the section containing the captcha image.
You can view my questions were i had the similar problems here (most weren't even answered):
Extracting a image from a WebBrowser Control
Screenshot method generates black images
Reset Webbrowser control to update settings
Now that you have the captcha images you'll need to decrypt them. So ask another question, send me the link and ill share my methods.
Im glad you didnt have to endure my nightmare. Don't forget to mark this as a solution, and as useful!
I am having problems using the WaveformTimeLine class in the WPF Sound Visualization Library using the NAUDIO class library.I have followed the instructions they have put out in their documentation but it's just not working for me.
My code behind looks like:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private OpenFileDialog dialogBox = new OpenFileDialog();
private void open_Click(object sender, RoutedEventArgs e)
{
//Get Audio File
dialogBox.Filter = "Wave File (*.mp3 ; *.wav) | *.mp3;*.wav;";
if (dialogBox.ShowDialog() == true)
{
NAudioEngine.Instance.OpenFile(dialogBox.FileName);
fileLocation = dialogBox.FileName;
}
var soundEngine = NAudioEngine.Instance;
soundEngine.PropertyChanged += NAudioEngine_PropertyChanged;
soundEngine.OpenFile(fileLocation);
if (NAudioEngine.Instance.CanPlay) NAudioEngine.Instance.Play();
myWave = new WaveformTimeline();
myWave.RegisterSoundPlayer(soundEngine);
}
The code doesn't throw any errors but it also doesn't do anything too.Can someone with experience with this API or similar APIs please help me solve this problem.
Key mistake was the line
myWave = new WaveformTimeline();
After adding the WaveformTimeline control in XAML design view, you don't initialise the control again in the code behind because you will be given another instance of the WaveformTimeline object.
I am trying to change the code http://sites.google.com/site/webcamlibrarydotnet/winfrom-and-csharp-sample-code-and-download from picture box to image or bitmap as I dont want to display any image or plan to display, all I want is that it will output the image to file.
I have tried changing the webcam.cs from PictureBox _FrameImage to Bitmap _FrameImage and PictureBox ImageControl to Bitmap ImageControl and casting (Bitmap) at e.WebCamImage
As well as changing it on the main form:
private void bWebcam_Click(object sender, EventArgs e)
{
WebCam webcam = new WebCam();
Bitmap image = null;
webcam.InitializeWebCam(ref image);
webcam.Start();
webcam.Stop();
FileStream fstream = new FileStream("testWebcam.jpg", FileMode.Create);
image.Save(fstream, System.Drawing.Imaging.ImageFormat.Jpeg);
fstream.Close();
}
Unhappyly it doesnt seem to work so
how could I change it from picture
box to Bitmap or Image or similar
storage before saving it to a file or
save it to file directly ?
The source code I am using is:
http://sites.google.com/site/webcamlibrarydotnet/winfrom-and-csharp-sample-code-and-download
Instead of using the WebCam class, why not just use the WebCamCapture class directly (since you are not displaying this in a form) and handle the ImageCapture event directly. The event argument for the event contains the Image. You could, in the event handler save the image to disk. Alternately, if you want to use the sample and the WebCam class, and you have a form. Use a PictureBox but leave it hidden (set Visible to false) and then just copy the image from there and save to disk when you need to.
Here is some sample code of using the WebCamCapture class instead of the WebCam class. It should be noted that this code is based on the sample code from the link provided in the question. I have kept the style of the sample so that code lines up.
Edit: Adding example of using WebCamCapture instead of WebCam class. This code should be used to modify Form1.cs in the sample code.
// Instead of having WebCam as member variable, have WemCamCapture
WebCamCapture webCam;
// Change the mainWinForm_Load function
private void mainWinForm_Load(object sender, EventArgs e)
{
webCam = new WebCamCapture();
webCam.FrameNumber = ((ulong)(0ul));
webCam.TimeToCapture_milliseconds = 30;
webCam.ImageCaptured += webcam_ImageCaptured;
}
// Add the webcam Image Captured handler to the main form
private void webcam_ImageCaptured(object source, WebcamEventArgs e)
{
Image imageCaptured = e.WebCamImage;
// You can now stop the camera if you only want 1 image
// webCam.Stop();
// Add code here to save image to disk
}
// Adjust the code in bntStart_Click
// (yes I know there is a type there, but to make code lineup I am not fixing it)
private void bntStart_Click(object sender, Event Args e)
{
webCam.Start(0);
}
Using reflector you can see that internally the WebCam class uses a timer to simulate a framerate. Therefore calling start and stop right after each other will never generate an image since the application doesnt handle application events (and therefore the timer tick event) in between starting and stopping. You should register on the ImageChanged event and call stop in there.
Good luck
** Edit: the start logic **
public void Start(ulong FrameNum)
{
try
{
this.Stop();
this.mCapHwnd = capCreateCaptureWindowA("WebCap", 0, 0, 0, this.m_Width, this.m_Height, base.Handle.ToInt32(), 0);
Application.DoEvents();
SendMessage(this.mCapHwnd, 0x40a, 0, 0);
SendMessage(this.mCapHwnd, 0x432, 0, 0);
this.m_FrameNumber = FrameNum;
this.timer1.Interval = this.m_TimeToCapture_milliseconds;
this.bStopped = false;
this.timer1.Start();
}
catch (Exception exception)
{
MessageBox.Show("An error ocurred while starting the video capture. Check that your webcamera is connected properly and turned on.\r\n\n" + exception.Message);
this.Stop();
}
}
In WebCam.cs you have:
public void InitializeWebCam(ref System.Windows.Forms.PictureBox ImageControl)
{
webcam = new WebCamCapture();
webcam.FrameNumber = ((ulong)(0ul));
webcam.TimeToCapture_milliseconds = FrameNumber;
webcam.ImageCaptured += new WebCamCapture.WebCamEventHandler(webcam_ImageCaptured);
_FrameImage = ImageControl;
}
void webcam_ImageCaptured(object source, WebcamEventArgs e)
{
_FrameImage.Image = e.WebCamImage;
}
If you modify the ImageCaptured code you can do what you want: e.WebCamImage is an Image.
for example you could change/add constructor to accept a file name and, in the ImageCaptured event, you could save image to file.
I am looking to create a very basic screen sharing application in C#. No remote control necessary. I just want a user to be able to broadcast their screen to a webserver.
How should I implement this? (Any pointer in the right direction will be greatly appreciated).
It does NOT need to be high FPS. Would be sufficient to even update ever 5s or so. Do you think it would be sufficient to just upload a screenshot ever 5 seconds to my web server?
I previously blogged about how remote screen sharing software works here, it is not specific to C# but it gives a good fundamental understanding on the topic. Also linked in that article is the remote frame buffer spec which you'll also probably want to read up on.
Basically you will want to take screenshots and you can transmit those screenshots and display them on the other side. You can keep the last screenshot and compare the screenshot in blocks to see which blocks of the screenshot you need to send. You would typically do some sort of compression before sending the data.
To have remote control you can track mouse movement and transmit it and set the pointer position on the other end. Also ditto about keystrokes.
As far as compression goes in C#, you can simply use JpegBitmapEncoder to create your screenshots with Jpeg compression with the quality that you want.
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.QualityLevel = 40;
To compare file blocks you are probably best to create a hash on the old block and the new one, and then check to see if they are the same. You can use any hashing algorithm you want for this.
Here's code to take a screenshot, uncompressed as a bitmap:
public static Bitmap TakeScreenshot() {
Rectangle totalSize = Rectangle.Empty;
foreach (Screen s in Screen.AllScreens)
totalSize = Rectangle.Union(totalSize, s.Bounds);
Bitmap screenShotBMP = new Bitmap(totalSize.Width, totalSize.Height, PixelFormat.
Format32bppArgb);
Graphics screenShotGraphics = Graphics.FromImage(screenShotBMP);
screenShotGraphics.CopyFromScreen(totalSize.X, totalSize.Y, 0, 0, totalSize.Size,
CopyPixelOperation.SourceCopy);
screenShotGraphics.Dispose();
return screenShotBMP;
}
Now just compress it and send it over the wire, and you're done.
This code combines all screens in a multiscreen setup into one image. Tweak as needed.
Well, it can be as simple as taking screenshots, compressing them, and then sending them over the wire. However, there is existing software that already does this. Is this for practice?
I'm looking to do something similar, and I just found this up on CodeProject. I think this will help you.
http://www.codeproject.com/Articles/371955/Motion-JPEG-Streaming-Server
The key player on sharing/replicating a screen is a COM Component called: RPDViewer
Add that com component to your window form and in References as well..
and thin add this code to your form load and you will get the screen replicated in your form:
using RDPCOMAPILib;
using System;
using System.Windows.Forms;
namespace screenSharingAttempt
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
RDPSession x = new RDPSession();
private void Incoming(object Guest)
{
IRDPSRAPIAttendee MyGuest = (IRDPSRAPIAttendee)Guest;
MyGuest.ControlLevel = CTRL_LEVEL.CTRL_LEVEL_INTERACTIVE;
}
//access to COM/firewall will prompt
private void button1_Click(object sender, EventArgs e)
{
x.OnAttendeeConnected += Incoming;
x.Open();
}
//connect
private void button2_Click(object sender, EventArgs e)
{
IRDPSRAPIInvitation Invitation = x.Invitations.CreateInvitation("Trial", "MyGroup", "", 10);
textBox1.Text = Invitation.ConnectionString;
}
//Share screen
private void button4_Click(object sender, EventArgs e)
{
string Invitation = textBox1.Text;// "";// Interaction.InputBox("Insert Invitation ConnectionString", "Attention");
axRDPViewer1.Connect(Invitation, "User1", "");
}
//stop sharing
private void button5_Click(object sender, EventArgs e)
{
axRDPViewer1.Disconnect();
}
}
}