C#,Winform - Setting arguments for Process class with Drawing.Image - c#

I'm generating a picture in the picturebox
pictureBox1.Image = Image.FromStream(imageActions.GetImage(reader["ID_no"].ToString()));
It is working perfectly, but I am also creating an option for the user to edit it via any application (Let's example macromedia) So I created a button and did the thing.
private void button2_Click(object sender, EventArgs e)
{
Process photoViewer = new Process();
photoViewer.StartInfo.FileName = #"C:\Program Files\Macromedia\Fireworks 8\Fireworks.exe";
photoViewer.StartInfo.Arguments = ___________;
photoViewer.Start();
}
I understand that in the photoViewer.StartInfo.Arguments = you can put here the path of the image, but in my case. the image is stored in the Database as Image datatype. any ideas?

In order to load the image in an external application, you will first of all need to save it to the disk.
After the application has closed you will need to load the updated image to display to the user.
The Image property of the PictureBox control has a Save method you can call:
string tempFile = System.IO.Path.GetTempFileName();
pictureBox1.Image.Save(tempFile);
You can then pass the tempFile value as a parameter to the photoViewer process (I used MSPaint as a Proof of Concept):
Process photoViewer = new Process();
photoViewer.StartInfo.FileName = #"C:\Windows\System32\MSPaint.exe";
photoViewer.StartInfo.Arguments = tempFile;
photoViewer.EnableRaisingEvents = true;
photoViewer.Exited += photoViewer_Exited;
photoViewer.Start();
The two lines of photoViewer.EnableRaisingEvents = true and photoViewer.Exited += photoViewer_Exited; will tell your application when the photoViewer process exits, and this is a good place for you to load the image and display to your users.
private void photoViewer_Exited(object sender, EventArgs e)
{
pictureBox1.Image = Image.FromFile(tempFile);
}
Note: string tempFile will need to be a class member variable so it can be accessed in the two functions.

Related

Disable C# Form until external Excel application is closed

I have a button on a C# Windows forms application that runs the code below:
private void btnAddDataToCSV_Click(object sender, EventArgs e)
{
string path = "D:\MyCsvFile.csv";
Process.Start(path);
}
Basically, the user needs to be able to make changes to a CSV file. The user is most comfortable making these changes in Microsoft Excel. I found the above code online from someone who has many years of experience working with MS Office products and C#. This guy explained that the code below works but is more error prone than using "Process.Start()" as shown above.
string path = "D:\MyCsvFile.csv";
var ExcelApp = new Excel.Application();
ExcelApp.Workbooks.OpenText(path, Comma: true);
ExcelApp.Visible = true;
This guy explains that "Process.Start()" works because Windows is set up to use Excel as the default program for opening CSV files.
Anyways, when the user clicks the button above (btnAddDataToCSV), I need my C# form to become disabled (all the buttons grayed out) until the user closes the Excel workbook that is displaying the CSV file. Potentially, I may need the C# program to read the CSV file immediately after the user closes Excel.
Ho do I do this?
I assume... I need to do something like... "disable C# form... then Wait for Excel close event... then once excel close event happens... enable C# form and read CSV file."
Below is the code I have for reading the CSV file:
string path = "D:\MyCsvFile.csv";
var reader = new StreamReader(File.OpenRead(path));
List<string> listA = new List<string>();
List<string> listB = new List<string>();
List<string> listC = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(',');
listA.Add(values[0]);
listB.Add(values[1]);
listC.Add(values[2]);
}
I think that you need to use an event handler for process that exits.
Something like this:
private void btnAddDataToCSV_Click(object sender, EventArgs e)
{
//disable form
string path = "D:\MyCsvFile.csv";
using (myProcess = new Process())
{
myProcess.EnableRaisingEvents = true;
myProcess.Exited += new EventHandler(Excel_Exit);
myProcess.Start(path);
}
}
public void Excel_Exit(object sender, System.EventArgs e){
//enableForm
}
Process.Exited example in documentation: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.exited?view=netcore-3.1
I was unable to get the solution above to work even though the solution is similar to Microsoft's solution.
https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.exited?view=netcore-3.1
I found this:
Why is my process's Exited method not being called?
It says:
"I've come across examples that place new Process() in a using clause. Do not do that if you want to use the Exited feature. The using clause destroys the instance along with any event handles on Exited."
It says:
using(var process = new Process())
Should be:
var process = new Process();
This makes no since because the link above that I provided for Microsoft is an example of how to use the "Process.Exited Event" and it uses "using(var process = new Process())"
But sure enough... for some reason when I tried "var process = new Process();" it worked... This is the code that worked:
private void btnAddDataToCSV_Click(object sender, EventArgs e)
{
var myProcess = new Process();
myProcess.EnableRaisingEvents = true;
myProcess.Exited += new EventHandler(Excel_Exit);
myProcess.StartInfo.FileName = "D:\\MyCsvFile.csv";
myProcess.Start();
}
public void Excel_Exit(object sender, System.EventArgs e)
{
MessageBox.Show("Success!!");
}
Here is the code that does not work... But I don't understand why because it is similar to Microsoft's example.
private Process myProcess;
private void btnAddDataToCSV_Click(object sender, EventArgs e)
{
using (myProcess = new Process())
{
myProcess.EnableRaisingEvents = true;
myProcess.Exited += new EventHandler(Excel_Exit);
myProcess.StartInfo.FileName = "D:\\MyCsvFile.csv";
myProcess.Start();
}
}
public void Excel_Exit(object sender, System.EventArgs e)
{
MessageBox.Show("Success!!");
}
When you close excel... the event never fires... Can someone explain this? Surely Microsoft's example isn't wrong.

Editting the picturebox image using external editor and loading the new image

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

SaveAs and delete same time c# [duplicate]

I am trying to delete local copy(on the computer) of an image file once uploaded using file dialog. It throws The process cannot access the file 'C:\Documents and Settings\username\My Documents\My Pictures\1220.bmp' because it is being used by another process.
private void _btnImportPhoto_Click(object sender, RoutedEventArgs e)
{
//user clicked import/change photo, open file dialog to browse for photo
System.Windows.Forms.OpenFileDialog fileDialog = new System.Windows.Forms.OpenFileDialog();
fileDialog.Multiselect = false;
fileDialog.Filter = ResourceFile.PhotoFileTypes;
if (fileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
FilePath = fileDialog.FileName;
FilePathCopy = fileDialog.FileName;
string safeFilePath = fileDialog.SafeFileName;
Bitmap bitmap = new Bitmap(FilePath);
CurrentPhoto = bitmap;
Bitmap bitmap1 = new Bitmap(FilePathCopy); //A copy to save when if delete local copy is chosen
m_PhotoCopy = bitmap1;
FileSystem.DeleteFile(FilePath);
}
_btnSave.IsEnabled = _btnCancel.IsEnabled = true;
}
}
Please let me know how to work around this issue.
Thanks.
you need to dispose of the bitmap object try doing this. As this will dispose of the bitmap object as soon as it leaves the using context { }
using (Bitmap bitmap1 = new Bitmap(FilePathCopy))
{
//do all bitmap stuff in here
}
First I see
Bitmap bitmap = new Bitmap(FilePath);
CurrentPhoto = bitmap;
Where CurrentPhoto I presume some global variable that you want hold.
This, instead throws and exception:
FileSystem.DeleteFile(FilePath);
Cause image file at FilePath is actually CurrentPhoto. What you can do.
1) If use of CurrentPhoto has any sense inside this function, do what you want to do inside this function, and after dispose CurrentPhoto object, even in a way like #Bobby suggests (using block)
2) If you want to have it by the way, you can try to use Bitmap's Clone
method like this:
CurrentPhoto = bitmap.Clone();
and after call your:
bitmap.Dispose();
FileSystem.DeleteFile(FilePath);
Should work.
Try this...
http://www.lockergnome.com/blade/2006/11/28/windows-error-message-error-deleting-file-or-folder/
It will allow you to delete files or folder.

Increase Performance Navigating Through Pages

I’m using WinForms. My application works like a simple image document (tif) viewer. The tif/image documents I work with have multiple pages, so by pressing the next button my application goes to the next page. The problem with my application is that it is slow when I move to the next page. Previously, my application was slower. I’ve modified the application a little bit to make it faster, but it’s still not fast enough.
I’ve compared my application’s speed to Windows Photo Viewer and the result was that my application still needs improvement on performance. Does anyone know how I could make my application faster?
In the link below I’ve provided a sample tif document for testing purposes.
Link: http://www.filedropper.com/tiftestingdoc
My Code:
FileStream _stream;
Image _myImg; // setting the selected tiff
string _fileName;
private int intCurrPage = 0; // defining the current page
private void Open_Btn_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
lblFile.Text = openFileDialog1.FileName; //Shows the filename in the lable
Image img = Image.FromFile(openFileDialog1.FileName);
pictureBox1.Image = img;
Size size = new Size(img.Height, img.Width);
pictureBox1.Size = size;
Open_Image_Control();
}
}
public void Open_Image_Control()
{
Image myBmp;
if (_myImg == null) //I made a copy of the file because i want to be able to modify the file in the directory for example go to directory and delete the file while still having the ability to view it on the application
{
_fileName = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
File.Copy(#"C:\my_Image_document", _fileName);
_stream = new FileStream(_fileName, FileMode.Open, FileAccess.Read);
_myImg = Image.FromStream(_stream);
}
int intPages = _myImg.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page); // getting the number of pages of this tiff
intPages--; // the first page is 0 so we must correct the number of pages to -1
lblNumPages.Text = Convert.ToString(intPages); // showing the number of pages
lblCurrPage.Text = Convert.ToString(intCurrPage); // showing the number of page on which we're on
_myImg.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, intCurrPage); // going to the selected page
myBmp = new Bitmap(_myImg, pictureBox1.Width, pictureBox1.Height);
//myBmp = new Bitmap(_myImg, pictureBox1.Height, pictureBox1.Width);
pictureBox1.Image = myBmp; // showing the page in the pictureBox1
}
private void NextPage_btn_Click(object sender, EventArgs e)
{
if (intCurrPage == Convert.ToInt32(lblNumPages.Text)) // if you have reached the last page it ends here
// the "-1" should be there for normalizing the number of pages
{ intCurrPage = Convert.ToInt32(lblNumPages.Text); }
else
{
intCurrPage++; //page increment (Goes to next page)
Open_Image_Control();
}
}
Load the image directly into the PictureBox, then to change pages call the pictureBox1.Image.SelectActiveFrame() method directly and refresh the PictureBox.
This prevents making new bitmaps copies of each page each time.
That was causing extra memory to be allocated each time and slowness while it copies all the pixels from the page.
Please see the code changes below:
// Variable to hold the current page number
private int intCurrPage = 0;
private int intTotalPages = 0;
private void Open_Btn_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
lblFile.Text = openFileDialog1.FileName;
// Before loading you should check the file type is an image
pictureBox1.Image = Image.FromFile(openFileDialog1.FileName);
pictureBox1.Size = new Size(pictureBox1.Image.Height, pictureBox1.Image.Width);
// Reset the current page when loading a new image
intCurrPage = 0;
intTotalPages = pictureBox1.Image.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
lblNumPages.Text = intTotalPages.ToString();
}
}
private void NextPage_btn_Click(object sender, EventArgs e)
{
// Check that the current page is not going past the max page
if (intCurrPage < (intTotalPages-1))
{
//page increment (Go to next page)
intCurrPage++;
// Directly increment the active frame within the image already in the PictureBox
pictureBox1.Image.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, intCurrPage);
// Adjust the size of the picturebox control to the size of the current page.
// not sure if this is necessary, but including it due to prior example
pictureBox1.Size = new Size(pictureBox1.Image.Height, pictureBox1.Image.Width);
// Refresh the PictureBox so that it will show the currently active frame
pictureBox1.Refresh();
lblCurrPage.Text = intCurrPage.ToString();
}
}
Also, your code to copy the image had a hard coded directory name that was throwing errors for me, so I removed that.

PictureBox to Bitmap or Image?

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.

Categories

Resources