exception 'System.ArgumentException' - c#

I am loading the data from MySQL in DataGridView and trying to to show the data from grid view to the textboxes and picture box. When I am trying to load the image from datagridview to the picture box it throws an exception. I have wasted my 2 days to resolve it but I remain unsuccessful.
This is the exception which I get when I click on the cell:
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
try
{
id.Text = dataGridView1.Rows[e.RowIndex].Cells[0].Value.ToString();
name.Text = dataGridView1.Rows[e.RowIndex].Cells[1].Value.ToString();
cost.Text = dataGridView1.Rows[e.RowIndex].Cells[2].Value.ToString();
price.Text = dataGridView1.Rows[e.RowIndex].Cells[3].Value.ToString();
status.Text = dataGridView1.Rows[e.RowIndex].Cells[6].Value.ToString();
description.Text = dataGridView1.Rows[e.RowIndex].Cells[4].Value.ToString();
//picture.Image = (Image)dataGridView1.Rows[e.RowIndex].Cells[0].Value;
if (dataGridView1.Rows[e.RowIndex].Cells[5].Value != DBNull.Value)
{
MemoryStream ms = new MemoryStream((byte[])dataGridView1.Rows[e.RowIndex].Cells[5].Value);
picture.Image = Image.FromStream(ms); // here is exception
}
else
{
picture.Image = null;
}
}
catch (Exception ex)
{
MessageBox.Show("Error " + ex);
}
}

If binary representation of the image is malformed, you'll get this error:
var imageBytes = Convert.FromBase64String(#"Qk16AAAAAAAAAHYAAAAoAAAAAQAAAAEAAAABAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAA////APAAAAA=");
var img = Image.FromStream(new MemoryStream(imageBytes)); // ok
var badImageBytes = Convert.FromBase64String(#"Qk16AAAAAAAAAHYAAAAoAAAAAQAAAAEAAAABAAQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAA////APAAAA==");
var badImg = Image.FromStream(new MemoryStream(badImageBytes )); // not ok
The simplest way to check consistency of the value will be to save it to the file and try open with any image viewer.
var bytes = (byte[])dataGridView1.Rows[e.RowIndex].Cells[5].Value;
File.WriteAllText(#"C:\Temp\image.base64.txt", Convert.ToBase64String(bytes)); // if image is not confidential you may share it with the community in the comment
File.WriteAllBytes(#"C:\Temp\image.bmp", bytes);
Please note that only following image formats are supported:
BMP
GIF
JPEG
PNG
TIFF
The reason why it is malformed could be different:
someone uploaded non-valid image
there are some data transformation (compression/encryption)
data was truncated in the storage (check DDL of the column if it is SQL)

Related

How can I save a User's uploaded image to a temp file that I can access later, but gets deleted after that

I've created an image uploader for users to upload/crop their profile pics. When a user uploads a file, it gets saved to a file that gets accessed immediately after for them to crop it.
I've tried using Path.GetTempPath() as well as Path.GetTempFileName(), but my cropper was unable to locate the file locations for some reason.
Any suggestions are greatly appreciated.
UPDATE: So I added File.Delete(filePath) to the end of btnCropClick, but I get an error saying The process cannot access the file because it is being used by another process. How can I "release" that file to be deleted instantly ?
Below is the code for where a user uploads their orignal image of choice
protected void btnUploadClick(object sender, EventArgs e)
{
//Upload Original Image Here
String UploadFileName = "";
String UploadFilePath = "";
if (fileUploader.HasFile)
{
String ext = Path.GetExtension(fileUploader.FileName).ToLower();
if (ext == ".jpg" || ext == ".jpeg" || ext == ".png")
{
UploadFileName = "orig_" + Guid.NewGuid().ToString() + ext;
UploadFilePath = Path.Combine(Server.MapPath("images/OriginalImages"), UploadFileName);
try
{
fileUploader.SaveAs(UploadFilePath); //TODO: Need to make this a temp file that gets "destroyed" later
imgUpload.ImageUrl = "images/OriginalImages/" + UploadFileName;
panCrop.Visible = true;
}
catch (Exception ex)
{
lblMsg.Text = "Error! Please Try Again. ";
}
}
else
{
lblMsg.Text = "Invalid File Type Selected. | Please Choose .jpg, .jpeg, or .png file only.";
}
}
else
{
lblMsg.Text = "Please Click 'Choose File' & Select An Image To Upload";
}
}
And here is the code for the cropper (Not sure anything in here needs to be changed, but I'll include it anyway for context & relevancy
protected void btnCropClick(object sender, EventArgs e)
{
//Crop Image Here & Save
String fileName = Path.GetFileName(imgUpload.ImageUrl);
String filePath = Path.Combine(Server.MapPath("images/OriginalImages"), fileName);
String cropFileName = "";
String cropFilePath = "";
if (File.Exists(filePath))
{
System.Drawing.Image orgImg = System.Drawing.Image.FromFile(filePath);
Rectangle CropArea = new Rectangle(
Convert.ToInt32(X.Value),
Convert.ToInt32(Y.Value),
Convert.ToInt32(W.Value),
Convert.ToInt32(H.Value)
);
try
{
Bitmap bitMap = new Bitmap(CropArea.Width, CropArea.Height);
using (Graphics g = Graphics.FromImage(bitMap))
{
g.DrawImage(orgImg, new Rectangle(0, 0, bitMap.Width, bitMap.Height), CropArea, GraphicsUnit.Pixel);
Bitmap resized = new Bitmap(bitMap, new Size(200, 200)); //Resize image to save as 200x200
cropFileName = "crop_" + fileName; //+UserID so each fileName is unique
cropFilePath = Path.Combine(Server.MapPath("images/CroppedImages"), cropFileName);
resized.Save(cropFilePath); //Where final, cropped image is saved
imgHeadshot.ImageUrl = "images/CroppedImages/" + cropFileName;
}
}
catch (Exception ex)
{
throw;
}
panCrop.Visible = false;
}
}
Was able to dispose of the original file by adding:
orgImg.Dispose();
bitMap.Dispose();
File.Delete(filePath);
to the end of btnCropClick method.

load image from PC as stream

I am trying to load a picture from my PC as a raw image in order to use it with the Microsoft cognitive services emotion (UWP).
below is a piece of my code:
//Chose Image from PC
private async void chosefile_Click(object sender, RoutedEventArgs e)
{
//Open Dialog
FileOpenPicker open = new FileOpenPicker();
open.ViewMode = PickerViewMode.Thumbnail;
open.SuggestedStartLocation = PickerLocationId.Desktop;
open.FileTypeFilter.Add(".jpg");
open.FileTypeFilter.Add(".jpeg");
open.FileTypeFilter.Add(".gif");
open.FileTypeFilter.Add(".png");
file = await open.PickSingleFileAsync();
if (file != null)
{//imagestream is declared as IRandomAccessStream.
imagestream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
var image = new BitmapImage();
image.SetSource(imagestream);
imageView.Source = image;
}
else
{
//
}
}
The part above works fine, it selects a photo from the pc (dialog box) and displays it in Image box.
private async void analyse_Click(object sender, RoutedEventArgs e)
{
try
{
emotionResult = await emotionServiceClient.RecognizeAsync(imagestream.AsStream());
}
catch
{
output.Text = "something is wrong in stream";
}
try {
if(emotionResult!= null)
{
Scores score = emotionResult[0].Scores;
output.Text = "Your emotions are: \n" +
"Happiness: " + score.Happiness + "\n" +
"Sadness: " + score.Sadness;
}
}
catch
{
output.Text = "Something went wrong";
}
}
I think the error is due to imagestream.AsStream()
imagestream is declared as IRandomAccessStream.
Can someone please tell me how to fix that part and if the error is in fact due to not loading the image correctly?
EDIT:
Also is there a better way to do this, instead of using stream to pass the emotionServiceClient a saved file instead of a stream?
Your problem is that you've advanced the stream position by virtue of creating the BitmapImage, so your read position is at the end by the time you call emotionServiceClient.RecognizeAsync. So you'll need to 'rewind':
var stream = imagestream.AsStreamForRead();
stream.Position = 0;
emotionResult = await emotionServiceClient.RecognizeAsync(stream);
Why not use their example, instead of trying to hold the file in memory, why don't you hold a path, and then use the path to read the stream at the time.
https://www.microsoft.com/cognitive-services/en-us/Emotion-api/documentation/GetStarted
In there example;
using (Stream imageFileStream = File.OpenRead(imageFilePath))
{
//
// Detect the emotions in the URL
//
emotionResult = await emotionServiceClient.RecognizeAsync(imageFileStream);
return emotionResult;
}
So you would be capturing imageFilePath as the result of the open file dialog.

Delete or have Control of an Image while your Application is Using it C#

I’m using WinForms. In my form I have a picturebox. On form load, my program opens an image document into my picturebox from my C:/image directory. The problem is when my program opens that image I cannot go into my C:/image directory and delete this picture because my application is using it. When I go to C:/image directory and try to delete the picture I get this error.
My goal is to have control over the image document that means i have the ability to delete the specific document even if its being used by my application.
Test: I tested if you can delete an image while viewing it at the same time with "Windows Photo Viewer" installed into in my computer, and that application lets you. Windows photo viewer doesn't lock the images. When you delete an image from the directory the image goes away in windows photo viewer as well. I want to accomplish something similar.
Suggested code: I tried implementing this but, i think i'm implementing it incorrectly.
Image img;
using (var bmpTemp = new Bitmap("image_file_path"))
{
img = new Bitmap(bmpTemp);
}
Below i provided my code i wrote to load the picture into my picture box.
private void Form1_Load(object sender, EventArgs e) //When form load you do this:
{
try // Get the tif file from C:\image\ folder
{
string path = #"C:\image\";
string[] filename = Directory.GetFiles(path, "*.tif"); //gets a specific image doc.
pictureBox1.Load(filename[0]);
lblFile.Text = filename[0];
RefreshImage(); // refreshing and showing the new file
opened = true; // the files was opened.
Image img1 = Image.FromFile(lblFile.Text);
pictureBox1.Image = img1;
pictureBox1.Width = img1.Width;
pictureBox1.Height = img1.Height;
picWidth = pictureBox1.Width;
picHeight = pictureBox1.Height;
getRatio();
}
catch (Exception ex)
{
MessageBox.Show("No files or " + ex.Message);
}
}
Make a copy of the image file bits before creating the image:
private void Form1_Load(object sender, EventArgs e) //When form load you do this:
{
try // Get the tif file from C:\image\ folder
{
string path = #"C:\image\";
string[] filename = Directory.GetFiles(path, "*.tif"); //gets a specific image doc.
FileInfo fi = new FileInfo(filename[0]);
byte [] buff = new byte[fi.Length];
using ( FileStream fs = File.OpenRead(fileToDisplay) )
{
fs.Read(buff, 0, (int)fi.Length);
}
MemoryStream ms = new MemoryStream(buff);
Bitmap img1 = new Bitmap(ms);
opened = true; // the files was opened.
pictureBox1.Image = img1;
pictureBox1.Width = img1.Width;
pictureBox1.Height = img1.Height;
picWidth = pictureBox1.Width;
picHeight = pictureBox1.Height;
getRatio();
}
catch (Exception ex)
{
MessageBox.Show("No files or " + ex.Message);
}
}

Delete an image being used by another process

I am writing a winform application in C# to open an image and overlay another image on top of it.
The bottom image is a .jpg and the top one is a .bmp converted from .svg. The .jpg and the .svg are the only ones I want to keep in the folder. The .bmp works as a temp.
I was using the following code to overlay the images. But I am having trouble to delete the temp .bmp as it is used by another process. I think it is this combine code still have access to the last .bmp file.
Could anyone help me on this? Thanks.
private void buttonSearch_Click(object sender, EventArgs e)
{
FailInfo.Text = "";
deletebmp(strFolderPath);
...
// Check if the specified front image exists. Yes, show the file name and convert SVG to BMP. No, show the error msg.
if (File.Exists(strFilePathF))
{
labelFront.Text = strFileNameF;
var svgConvert = SvgDocument.Open(svgFilePathF);
svgConvert.Draw().Save(bmpFilePathF);
pictureBoxFront.Image = Image.FromFile(strFilePathF);
}
else
{
labelFront.Text = "Couldn't find the file!";
pictureBoxFront.Image = null;
}
// Check if the specified back image exists. Yes, show the file name and convert SVG to BMP. No, show the error msg.
if (File.Exists(strFilePathBF))
{
labelBack.Text = strFileNameBF;
strFilePathB = strFilePathBF;
pictureBoxBack.Image = Image.FromFile(strFilePathB);
labelResult.Text = "FAIL";
labelResult.BackColor = Color.FromArgb(255, 0, 0);
var svgConvert = SvgDocument.Open(svgFilePathBF);
bmpFilePathB = strFolderPath + strFileNameBF + ".bmp";
svgConvert.Draw().Save(bmpFilePathB);
svgFilePathB = svgFilePathBF;
inspectionres(svgFilePathB);
labelreason.Visible = true;
}
else if (File.Exists(strFilePathBP))
{
labelBack.Text = strFileNameBP;
strFilePathB = strFilePathBP;
pictureBoxBack.Image = Image.FromFile(strFilePathB);
labelResult.Text = "PASS";
labelResult.BackColor = Color.FromArgb(0, 255, 0);
var svgConvert = SvgDocument.Open(svgFilePathBP);
bmpFilePathB = strFolderPath + strFileNameBP + ".bmp";
svgConvert.Draw().Save(bmpFilePathB);
svgFilePathB = svgFilePathBP;
inspectionres(svgFilePathB);
labelreason.Visible = false;
}
else
{
labelBack.Text = "Couldn't find the file!";
pictureBoxBack.Image = null;
labelResult.Text = "ERROR";
labelResult.BackColor = Color.FromArgb(0, 255, 255);
labelreason.Visible = false;
}
}
//
// Overlay the SVG file on top of the JPEG file
//
private Bitmap Combine(string jpegFile, string bmpFile)
{
Image image1 = Image.FromFile(jpegFile);
Image image2 = Image.FromFile(bmpFile);
Bitmap temp = new Bitmap(image1.Width, image1.Height);
using (Graphics g = Graphics.FromImage(temp))
{
g.DrawImageUnscaled(image1, 0, 0);
g.DrawImageUnscaled(image2, 0, 0);
}
return temp;
}
//
// Show the overlaid graphic in the picturebox
//
private void checkBoxOverlay_CheckedChanged(object sender, EventArgs e)
{
try
{
if (FindFront)
if (checkBoxOverlay.Checked)
pictureBoxFront.Image = Combine(strFilePathF, bmpFilePathF);
else
pictureBoxFront.Image = Image.FromFile(strFilePathF);
else
pictureBoxFront.Image = null;
if (FindBack)
if (checkBoxOverlay.Checked)
pictureBoxBack.Image = Combine(strFilePathB, bmpFilePathB);
else
pictureBoxBack.Image = Image.FromFile(strFilePathB);
else
pictureBoxBack.Image = null;
}
catch (Exception ex)
{
MessageBox.Show("Error loading image" + ex.Message);
}
}
//
// Option of changing the image folder
//
private void buttonPath_Click(object sender, EventArgs e)
{
FolderBrowserDialog FolderBrowserDialog1 = new FolderBrowserDialog();
if (FolderBrowserDialog1.ShowDialog() == DialogResult.OK)
{
strFolderPath = FolderBrowserDialog1.SelectedPath + "\\";
}
}
//
// Pull the inspection result info from the SVG file
//
private void inspectionres(string filename)
{
XDocument document = XDocument.Load(filename);
XElement svg_Element = document.Root;
string sb = null;
var faillist = (from svg_path in svg_Element.Descendants("{http://www.w3.org/2000/svg}text") select svg_path).ToList();
foreach (var item in faillist)
{
sb += item.ToString();
}
}
//
// Delete all the .bmp files generated from .svg files
//
private void deletebmp(string path)
{
// Unload the images from the picturebox if applicable
pictureBoxFront.Image = null;
pictureBoxBack.Image = null;
string[] files = Directory.GetFiles(path, "*.bmp");
for (int i = 0; i < files.Length; i ++ )
File.Delete(files[i]);
}
}
Image implements IDisposable, so simply setting the pictureBox.Image property to null will not release resources (in your case, the file). Your Combine method also leaves the images open. You have to call Dispose before attempting to delete the file:
Image image1 = Image.FromFile(path1);
File.Delete(path1); // error - file is locked
Image image2 = Image.FromFile(path2);
image2.Dispose();
File.Delete(path2); // works
An alternative approach (and I assume you're using WinForms here, in WPF it's a little different) would be to load the bitmap from the file manually (using FromStream). Then, you can close the stream immediately and delete the file:
Image image;
using (Stream stream = File.OpenRead(path))
{
image = System.Drawing.Image.FromStream(stream);
}
pictureBox.Image = image;
File.Delete("e:\\temp\\copy1.png"); //works
Vesan's answer didn't helped me so I found an different solution.
So I can safe/open an image and if I want instantly delete the image.
i used it for my dataGridView_SelectionChanged:
private void dataGridViewAnzeige_SelectionChanged(object sender, EventArgs e)
{
var imageAsByteArray = File.ReadAllBytes(path);
pictureBox1.Image = byteArrayToImage(imageAsByteArray);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
All above answers are perfectly fine, but I've got a different approach.
Using Image abstract class, you will not get quite a lot of options for manipulating and resizing image.
Rather you do as follows:-
Bitmap img = new Bitmap(item);
img.SetResolution(100, 100);
Image imgNew = Image.FromHbitmap(img.GetHbitmap());
pictureBox1.Image = imgNew;
img.Dispose();

Deleting Image that's in PictureBox

I've searched and read a lot of the different ways to do this... and tried many of them.
When the program loads it loads printmark.png into the picture box.
Of course every time I try to delete the PNG file it says it's in use. As you can see I've tried both the Image.FileFrom and the picturebox.Load method.
This is the code I have.
private void GetCurrentLogos()
{
Image CurrentWM = Image.FromFile(#"C:\pics\logo.png");
Image CurrentPM = Image.FromFile(#"C:\pics\printmark.png");
pbWatermark.Image = CurrentWM;
pbPrintmark.Image = CurrentPM;
//pbWatermark.Load(#"C:\pics\logo.png");
//pbPrintmark.Load(#"C:\pics\printmark.png");
}
private void btnSetPM_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
ListViewItem item = listView1.SelectedItems[0];
txtNewPM.Text = item.Tag.ToString();
pbPrintmark.Image.Dispose();
pbPrintmark.Image = null;
pbPrintmark.Refresh();
Application.DoEvents();
renameMark("printmark.png", txtNewPM.Text);
}
}
private void renameMark(string MarkType, string FileName)
{
string path = txtPath.Text;
string FullSource = path + FileName;
string FullDest = path + MarkType;
if(File.Exists(FullDest))
{
File.Delete(FullDest);
}
System.IO.File.Copy(FullSource, FullDest);
}
See Image.FromFile():
The file remains locked until the Image is disposed.
To get around this, pass the returned image to a new Bitmap so that the original lock gets released:
Image tmp = Image.FromFile(#"C:\pics\logo.png");
Image CurrentWM = new Bitmap(tmp);
tmp.Dispose();
As noted in some of the answers to this question, an image created by Image.FromFile keeps the underlying file open. This is by design, as the MSDN documentation says ("The file remains locked until the Image is disposed."). You can get around this by loading the file into a MemoryStream, then creating the image from that stream.
tmp.Dispose(); didnt worked for me so maybe u need also a different solution.
I used it for my dataGridView_SelectionChanged:
private void dataGridViewAnzeige_SelectionChanged(object sender, EventArgs e)
{
var imageAsByteArray = File.ReadAllBytes(path);
pictureBox1.Image = byteArrayToImage(imageAsByteArray);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}

Categories

Resources