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.
Related
I try to open an external editor during Runtime and edit an image which is currently is set to a PictureBox, edit the image and update the image after closing the editor.
For this, I have a simple c# windows application with a PictureBox two Button one to load PictureBox Image from file and another to edit the image using MS Paint.
Here is the code:
public partial class Form1 : Form
{
string myImagePath = #"C:\temp\bt_logo.png";
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
pictureBox1.Image = Image.FromFile(myImagePath);
}
private void button2_Click(object sender, EventArgs e)
{
System.Diagnostics.ProcessStartInfo launchEditor = new System.Diagnostics.ProcessStartInfo();
launchEditor.FileName = "mspaint";
launchEditor.Arguments = myImagePath;
launchEditor.UseShellExecute = true;
System.Diagnostics.Process.Start(launchEditor);
}
}
The Editor is openned successfully but the changes cannot be saved because of access problem:
Any idea how to solve this problem?
EDIT1:
In order to stop accessing the image when the editor is open, I modified the code of button2_Click() as follows:
pictureBox1.Image = null;
System.Diagnostics.ProcessStartInfo launchEditor = new System.Diagnostics.ProcessStartInfo();
launchEditor.FileName = "mspaint";
launchEditor.Arguments = myImagePath;
launchEditor.UseShellExecute = true;
System.Diagnostics.Process.Start(launchEditor);
pictureBox1.Image = Image.FromFile(myImagePath);
same resault. As another try, I made a copy of the image, modified it and copied it to the original image,
System.IO.File.Copy(myImagePath, myImagePath_temp, true);
System.Diagnostics.ProcessStartInfo launchEditor = new System.Diagnostics.ProcessStartInfo();
launchEditor.FileName = "mspaint";
launchEditor.Arguments = myImagePath_temp;
launchEditor.UseShellExecute = true;
System.Diagnostics.Process.Start(launchEditor);
System.IO.File.Copy(myImagePath_temp, myImagePath, true);
the same resault!
This question is essentially a duplicate of
Open Image from file, then release lock?
Image.FromFile locks the file on disk, until the image variable in your code is disposed of. You should observe the accepted answer to that question above; it provides a way to load the image data from disk, copy it inside the memory of your program, and then release the lock on the file and use the copy of the bitmap data in your picturebox
You'll find an answer on how to load your image without it being locked in the file system. I'm writing an answer instead of a comment because I wanted to give a bit of further advice to the rest of the program
Take a look at the FileSystemWatcher class; Notification when a file changes?
you can use it to detect changes to your file so the picture box can be updated when the file is saved rather than when paint is quit- this will be easier than coding to detect the app closing
everyone. I have been stuck here dealing with this bugs for days, but I still couldn't figure it out.
My guess: I think my code has some problem as I did not dispose the object properly after using it, (I'm not very familiar with these concepts of releasing resources, threading) .
I got these code by taking reference of what people did on youtube, but despite me doing exactly the same thing, my code didn't work out nicely.
SITUATION:
I have two picture boxes, left one can take video of me, right one take the snapshot, if you press button1 , you will start the video, clone_button will copy a image i.e. take a snapshot, and save_image should save it to the path reference, however, i get a generic error occured in GDI+ again and again while I'm trying to save it. Also, my debugger seemed to get crazy (i.e. failed to terminate the vshost.exe ) once I ran this program, I have to restart the computer to get my code running again, which is bleak and frustrating.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Imaging;
//AForge.Video dll
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Imaging;
using AForge.Imaging.Filters;
using AForge;
namespace WebCameraCapture
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private FilterInfoCollection CaptureDevice; // list of webcam
private VideoCaptureDevice FinalFrame;
private void Form1_Load(object sender, EventArgs e)
{
CaptureDevice = new FilterInfoCollection(FilterCategory.VideoInputDevice);//constructor
foreach (FilterInfo Device in CaptureDevice)
{
comboBox1.Items.Add(Device.Name);
}
comboBox1.SelectedIndex = 0; // default
FinalFrame = new VideoCaptureDevice();
}
private void button1_Click(object sender, EventArgs e)
{
FinalFrame = new VideoCaptureDevice(CaptureDevice[comboBox1.SelectedIndex].MonikerString);// specified web cam and its filter moniker string
FinalFrame.NewFrame += new NewFrameEventHandler(FinalFrame_NewFrame);// click button event is fired,
FinalFrame.Start();
}
void FinalFrame_NewFrame(object sender, NewFrameEventArgs eventArgs) // must be void so that it can be accessed everywhere.
// New Frame Event Args is an constructor of a class
{
pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone();// clone the bitmap
}
private void From1_CLosing(object sender, EventArgs e)
{
if (FinalFrame.IsRunning==true) FinalFrame.Stop();
}
private void save_Click(object sender, EventArgs e)
{
if (pictureBox2.Image != null)
{
Bitmap varBmp = new Bitmap(pictureBox2.Image);
Bitmap newBitmap = new Bitmap(varBmp);
varBmp.Dispose();
varBmp = null;
varBmp.Save(#"C:\a.png", ImageFormat.Png);
}
else
{ MessageBox.Show("null exception"); }
}
private void clone_Click(object sender, EventArgs e)
{
pictureBox2.Image = (Bitmap)pictureBox1.Image.Clone();
}
}
}
Any AForge.net user can just PRESS the LINK below and try it out. Thanks!
SAMPLE
After having a look at your code, to me it appears that you are disposing of your image right before you save it. Meaning that your program can't save the image, because it doesn't exist anymore. Actually it reads that you've essentially removed the captured image twice, once on dispose, the second when you set it as null.
So if you move the two code segments after the save, it should be working. Granted without using a dialog box to change the name of the file, you'll surely receive an error unless you remove that file after each time it has been created.
private void save_Click(object sender, EventArgs e)
{
if (pictureBox2.Image != null)
{
//Save First
Bitmap varBmp = new Bitmap(pictureBox2.Image);
Bitmap newBitmap = new Bitmap(varBmp);
varBmp.Save(#"C:\a.png", ImageFormat.Png);
//Now Dispose to free the memory
varBmp.Dispose();
varBmp = null;
}
else
{ MessageBox.Show("null exception"); }
}
If you open the task manager, you can watch how much memory your program is soaking up.
Disposing of the memory after you're done using it, gives it back to the system.
You don't have a dispose inside your FinalFrame_NewFrame thread, so when the camera is reading images,
you should see the memory usage continue to climb until you stop the program.
I've added dispose to my thread, putting the memory usage under control, but now I'm debugging my image saves. Because I'm disposing, I can't save the image lol. My program ends up trying to save a null image file and throws the appropriate error.
I'm using a 2nd picurebox just as you are, but using for example, pbox2.image = pbox1.image, doesn't copy the data, it copies the memory location with the image data, so when I dispose pbox1 to free memory, the image data disappears with the memory location.
So, I had the same issue, and it was resolved one, by moving the dispose method, and two, I had to change the path, it didnt want to save to C:, so I put it on my desktop, you may not have had this issue if you were running as admin but I did so for anyone else who sees this, dont save to the root of C:.
I'm trying to capture the finger print scanned by this device-> http://www.nitgen.com/eng/product/finkey.html
I'm able to scan the fingerprint and save the binary data successfully. I'm also able to display the fingerprint in the picture box. However when I'm trying to save the fingerprint displayed in the picture box, I'm getting an error that the Image of the picturebox is null.
Below is my code of capturing the fingerprint and saving the image from the picturebox.
public class Form1 : System.Windows.Forms.Form
{
public NBioBSPCOMLib.NBioBSP objNBioBSP;
public NBioBSPCOMLib.IExtraction objExtraction;
private PictureBox pictureExtWnd;
private void Form1_Load(object sender, System.EventArgs e)
{
// Create NBioBSP object
objNBioBSP = new NBioBSPCOMLib.NBioBSPClass();
objExtraction = (NBioBSPCOMLib.IExtraction)objNBioBSP.Extraction;
pictureExtWnd.Image = new Bitmap(pictureExtWnd.Width, pictureExtWnd.Height);
}
private void buttonEnroll_Click(object sender, System.EventArgs e)
{
//tell NBIO to not display their fingerprint scanning window
objExtraction.WindowStyle = NBioBSPType.WINDOW_STYLE.INVISIBLE;
//set the color of the fingerprint captured
objExtraction.FPForeColor = "000000";
//set the color of the background where the fingerprint will be displayed
objExtraction.FPBackColor = "FFFFFF";
//tell NBIO that the scanned fingerprint will be displayed in the picturebox
//by giving the handle control to NBIO
objExtraction.FingerWnd = pictureExtWnd.Handle.ToInt32();
//start scanning the fingerprint. This is also where the fingerprint
//is displayed in the picturebox.
objExtraction.Capture((int)NBioBSPType.FIR_PURPOSE.VERIFY);
//if there's no problem while scanning the fingerprint, save the fingerprint image
if (objExtraction.ErrorCode == NBioBSPError.NONE)
{
string fileName = RandomString.GetRandomString(16, true) + ".bmp";
using (SaveFileDialog sfdlg = new SaveFileDialog())
{
sfdlg.Title = "Save Dialog";
sfdlg.Filter = "Bitmap Images (*.bmp)|*.bmp|All files(*.*)|*.*";
if (sfdlg.ShowDialog(this) == DialogResult.OK)
{
pictureExtWnd.Image.Save(sfdlg.FileName, ImageFormat.Bmp);
MessageBox.Show("FingerPrint Saved Successfully.");
}
}
}
else
{
MessageBox.Show("FingerPrint Saving Failed!");
}
}
}
I've tried enclosing inside
using(Graphics g = new Graphics)
{
objExtraction.Capture((int)NBioBSPType.FIR_PURPOSE.VERIFY);
}
since I've read that when doing edits on an image, you need to use graphics. but nothing is happening obviously since the api isn't using the graphic object I instantiated.
UPDATE:
This is what I ended up doing:
using (SaveFileDialog sfdlg = new SaveFileDialog())
{
sfdlg.Title = "Save Dialog";
sfdlg.Filter = "Bitmap Images (*.bmp)|*.bmp|All files(*.*)|*.*";
if (sfdlg.ShowDialog(this) == DialogResult.OK)
{
Graphics gfx = this.pictureExtWnd.CreateGraphics();
Bitmap bmp = new Bitmap(this.pictureExtWnd.Width, this.pictureExtWnd.Height);
this.pictureExtWnd.DrawToBitmap(bmp, new Rectangle(0, 0, this.pictureExtWnd.Width, this.pictureExtWnd.Height));
bmp.Save(sfdlg.FileName, ImageFormat.Bmp);
gfx.Dispose();
//pictureExtWnd.Image.Save(sfdlg.FileName, ImageFormat.Bmp);
MessageBox.Show("Saved Successfully...");
}
}
objExtraction.FingerWnd = pictureExtWnd.Handle.ToInt32();
You passed the window handle to the fingerprint scanner. That's a common way to tell a chunk of native code about a window that it can draw to. It will typically sub-class the window procedure to respond to WM_PAINT requests, for example, same idea as NativeWindow.WndProc().
Implied however is that the Image property is useless. That native code has no idea that this is a PictureBox control and that it has an Image property. It only knows about the native window that was created for the control.
Do look in the api for an option to save the image, this ought to be available. If not then your first shot at saving it is using the picture box' DrawToBitmap() method. Which may work if the scanner implements the WM_PRINT message handler. If that doesn't work then your only other backup plan is to use Graphics.CopyFromScreen(). Which will always work, as long as the window is in the foreground. Similar to using the PrtSc button on your keyboard, a screen-shot.
This seems like a serious bug :
private void LayoutRoot_Drop(object sender, DragEventArgs e)
{
if ((e.Data != null) && (e.Data.GetDataPresent(DataFormats.FileDrop)))
{
FileInfo[] files = (FileInfo[])e.Data.GetData(DataFormats.FileDrop);
using (FileStream fileStream = files[0].OpenRead())
{
//Code reaching this point.
BitmapImage bmpImg = new BitmapImage();
bmpImg.ImageOpened += new EventHandler<RoutedEventArgs>(bmpImg_ImageOpened);
bmpImg.ImageFailed += new EventHandler<ExceptionRoutedEventArgs>(bmpImg_ImageFailed);
try
{
bmpImg.SetSource(fileStream);
}
catch
{
//Code dosen't reach here.
}
}
}
}
void bmpImg_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
//Code dosen't reach here.
}
void bmpImg_ImageOpened(object sender, RoutedEventArgs e)
{
//Code dosen't reach here.
}
I am experiencing a very strange behivour. Running this code on my computer, it works - when you drag a JPG on the LayoutRoot I can break inside bmpImg_ImageOpened().
But on a different machine it won't work - when dragging a JPG, I can break in the drop event but after SetSource() nothing happens : no exceptions are thrown, and non of the callbacks are invoked.
I tried it on another machine and it also didn't work.
edit:
On all of the machines, when adding an Image class and setting it's Source property to the bitmapImage, the image is shown fine. so I guess it's an issue with the callbacks. This is not enough because I still need those events.
I am banging my head here, what could it be ?
This is simply how Silverlight has always behaved. ImageOpened only fires if the image is downloaded and decoded (i.e. using Source). It does not fire when using SetSource. If you need access to the dimensions after loading your image either use WriteableBitmap for the PixelWidth and PixelHeight properties (instead of BitmapImage) or do something like:
img.Source = bmpImg;
Dispatcher.BeginInvoke(() =>
{
FakeImageOpened(); // Do logic in here
});
You have to set
bitmapImage.CreateOptions = BitmapCreateOptions.None;
Then the ImageOpened event is fired. This is because the default Options are CreateDelayed
Greetings
Christian
http://www.wpftutorial.net
In my (Silverlight) weather app I am downloading up to 6 seperate weather radar images (each one taken about 20 mins apart) from a web site and what I need to do is display each image for a second then at the end of the loop, pause 2 seconds then start the loop again. (This means the loop of images will play until the user clicks the back or home button which is what I want.)
So, I have a RadarImage class as follows, and each image is getting downloaded (via WebClient) and then loaded into a instance of RadarImage which is then added to a collection (ie: List<RadarImage>)...
//Following code is in my radar.xaml.cs to download the images....
int imagesToDownload = 6;
int imagesDownloaded = 0;
RadarImage rdr = new RadarImage(<image url>); //this happens in a loop of image URLs
rdr.FileCompleteEvent += ImageDownloadedEventHandler;
//This code in a class library.
public class RadarImage
{
public int ImageIndex;
public string ImageURL;
public DateTime ImageTime;
public Boolean Downloaded;
public BitmapImage Bitmap;
private WebClient client;
public delegate void FileCompleteHandler(object sender);
public event FileCompleteHandler FileCompleteEvent;
public RadarImage(int index, string imageURL)
{
this.ImageIndex = index;
this.ImageURL = imageURL;
//...other code here to load in datetime properties etc...
client = new WebClient();
client.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
client.OpenReadAsync(new Uri(this.ImageURL, UriKind.Absolute));
}
private void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
StreamResourceInfo sri = new StreamResourceInfo(e.Result as Stream, null);
this.Bitmap = new BitmapImage();
this.Bitmap.SetSource(sri.Stream);
this.Downloaded = true;
FileCompleteEvent(this); //Fire the event to let the app page know to add it to it's List<RadarImage> collection
}
}
}
As you can see, in the class above I have exposed an event handler to let my app page know when each image has downloaded. When they have all downloaded I then run the following code in my xaml page - but only the last image ever shows up and I can't work out why!
private void ImageDownloadedEventHandler(object sender)
{
imagesDownloaded++;
if (imagesDownloaded == imagesToDownload)
{
AllImagesDownloaded = true;
DisplayRadarImages();
}
}
private void DisplayRadarImages()
{
TimerSingleton.Timer.Stop();
foreach (RadarImage img in radarImages)
{
imgRadar.Source = img.Bitmap;
Thread.Sleep(1000);
}
TimerSingleton.Timer.Start(); //Tick poroperty is set to 2000 milliseconds
}
private void SingleTimer_Tick(object sender, EventArgs e)
{
DisplayRadarImages();
}
So you can see that I have a static instance of a timer class which is stopped (if running), then the loop should show each image for a second. When all 6 have been displayed then it pauses, the timer starts and after two seconds DisplayRadarImages() gets called again.
But as I said before, I can only ever get the last image to show for some reason and I can't seem to get this working properly.
I'm fairly new to WP7 development (though not to .Net) so just wondering how best to do this - I was thinking of trying this with a web browser control but surely there must be a more elegant way to loop through a bunch of images!
Sorry this is so long but any help or suggestions would be really appreciated.
Mike
You can use a background thread with either a Timer or Sleep to periodically update your image control.
Phạm Tiểu Giao - Threads in WP7
You'll need to dispatch updates to the UI with
Dispatcher.BeginInvoke( () => { /* your UI code */ } );
Why don't you add the last image twice to radarImages, set the Timer to 1000 and display just one image on each tick?