I am having trouble saving a user uploaded image to my "logos" file when the user presses "Save Team" on my form.
For you to get a taster of what the application does I have provided a screenshot here, upon pressing add team all the text box data is written to a text file and I want the image to automatically save into a predefined folder "logos", however I get the GDI++ error whenever I press save.
After reading through a few old threads on the web, I found that it could be caused by a few things such as file permissions, file size, the files name or even an open stream.
Below is the code I am currently using to save out my file which prompts the error:
private void btnAddTeam_Click(object sender, EventArgs e)
{
//VALIDATION FOR TEXT FILE AND OTHER STUFF HERE...
//SAVE THE IMAGE FILE
string filePath = picTeamLogo.ImageLocation;
Image tempImage = Image.FromFile(filePath);
tempImage.Save(#"../logos/");
}
If you are viewing the screenshot, please do not get confused by "arsenal.png" I am aware that that is not the full file path, its conversion is handled in another method, as only the filename is required to be written to the text file.
If anybody has any ideas on where I am going wrong then please point me in the right direction, vague errors such as the GDI one I just received are such a headache!
Alex.
Try this method
public void storeFile(FileUpload File, string dirName)
{
if (!Directory.Exists(MapPath("~/uploads/" + dirName)))
{
Directory.CreateDirectory(MapPath("~/uploads/" + dirName));
}
string saveLocation = MapPath("~/uploads/" + dirName + "/" + Path.GetFileName(File.FileName));
File.SaveAs(saveLocation);
}
that's because you have not specified the file name for save function !
take a look at this :
string filePath = picTeamLogo.ImageLocation;
FileInfo fi = new FileInfo(filePath);
Image tempImage = Image.FromFile(fi.FullName);
tempImage.Save(#"../logo/" + fi.Name);
now it works properly
See this earlier post of mine for similar issue...
A Generic error occurred in GDI+ in Bitmap.Save method
The stream remains locked - you can use memory stream as a temp location then save.
When either a Bitmap object or an Image object is constructed from a
file, the file remains locked for the lifetime of the object. As a
result, you cannot change an image and save it back to the same file
where it originated.
http://support.microsoft.com/?id=814675
string outputFileName = "...";
using (MemoryStream memory = new MemoryStream())
{
using (FileStream fs = new FileStream(outputFileName, FileMode.Create, FileAccess.ReadWrite))
{
tempImage.Save(memory, ImageFormat.Jpeg);
// memory.ToStream(fs) // I think the same
byte[] bytes = memory.ToArray();
fs.Write(bytes, 0, bytes.Length);
}
}
Or alternative is loading image via MemoryStream into the image - so the stream doesn't get locked in the first place...
Related
In my application there are some files. Which I want to be able to copy and paste elsewhere in application.
The file I want to copy and paste I have stored inside a function GetPartialExportString()
My Idea:
When User clicks on "Copy" I create one file somewhere on comp and store it inside new created file
When user clicks "Paste" I Read from the file I generated when I clicked copy and add it there.
MemoryStream destinationStream = new MemoryStream();
protected void CopyCommand()
{
var modelAsString = GetPartialExportString();
string fileName = "copy.xaml";
string targetPath = #"C:\Users\";
string destFile = System.IO.Path.Combine(targetPath, fileName);
//System.IO.Directory.CreateDirectory(targetPath);
// convert string to stream
byte[] byteArray = Encoding.UTF8.GetBytes(modelAsString);
MemoryStream readingStream = new MemoryStream(byteArray);
FileStream file = new FileStream(fileName, FileMode.Create, FileAccess.Write);
readingStream.WriteTo(file);
file.Close();
readingStream.Close();
readingStream.CopyTo(destinationStream);
File.WriteAllText(destFile, modelAsString);
}
protected void PasteCommand()
{
string importString = File.ReadAllText("d:\\temp.txt");
LoadUnitFromXamlString("d:\\temp.txt");
}
It does not work like this. New to this, if someone can help I would appreciate!
File routes are incorect at the moment. But even when they were normal it was not working!
You should avoid overriding Close() method of Stream class for MemoryStream/FileStream objects. Use Dispose() instead.
You should get all the work done by the stream objects first and then dispose them.
After you've copied the contents of readingStream object to file, you'll have to readjust the position of stream buffer to the beginning of the contents present in readingStream object so as to copy it successfully to destinationStream.
Modify your code snippet like this:
readingStream.WriteTo(file);
readingStream.Position = 0;
readingStream.CopyTo(destinationStream);
file.Dispose();
readingStream.Dispose();
File.WriteAllText(destFile, modelAsString);
I've got strange behavior.
I have a code, when I am sending byte[] array to the Image (sometimes png, sometimes jpg).
When I save PNG format - everything is ok, but when I am trying to save JPG, there is an exception: "Cannot access a closed Stream"
Code:
imgTarget.Save(wwwroot + "\\ImageBank\\" + TaskRunID + "_" + TestCaseID + "_" + TestDataID + "_" + ImageCounter + Extension, ImageFormat.Jpeg);
What I have checked:
imgTarget is not null
imgTarget contains correct data (even RawFormat is Png or Jpeg as It should)
imgTarget.Save() throws an exception: System.ObjectDisposedException: 'Cannot access a closed Stream.'
I have tried to use Bitmap - copy imgTarget to new Bitmap and then Save (with the same result)
I have tried to call Save() method with the ImageFormat parameter correctly set to jpeg or png (with the same result) - for both for Image.Save() and Bitmap.Save()
I have checked the correct path and file name (it's ok) (in this case it is C:\MyProd\wwwroot\ImageBank\10611_8_-1_1.jpeg)
Strange is that imgTarget contains data just before calling the method Save() - but right after it is null/disposed...
Anyone any ideas?
EDIT:
I have prepared little bit of code which is failing in the same way - it fails at last line .Save()
// This contains only the URL for the downloading of the file
string url = $"***url to download jpg file***";
// Request for the API - which downloads the jpg file via GET and provide the RawData via Response.RawBytes
APIRequest request = new APIRequest(RestSharp.Method.GET, url, new Authentication("user", "password", "-1"));
// Test case is only class which calls RestSharp (get png or jpg file)
TestCase t = new TestCase();
// This downloads the jpg file and store it as byte[] in t.GetDataFromAPI
t.API(request);
// Using downloaded data as byte[]
byte[] APIImageSource = t.GetDataFromAPI;
// Default extensions for saving files is .png
string Extension = ".png";
Image imgTarget;
// Now I use bytes[] and convert them into the image
imgTarget = ConvertBytesToImage(APIImageSource);
if (t.GetImageFormat(APIImageSource) == ExpectedFormat.JPEG)
{
Extension = ".jpeg";
}
string path = "C:\\Temp\\filename" + Extension;
imgTarget.Save(path + Extension, ImageFormat.Jpeg);
There is Method ConvertBytesToImage:
internal static Image ConvertBytesToImage(byte[] bytes)
{
using (var ms = new MemoryStream(bytes))
{
return Image.FromStream(ms);
}
}
Comment from #Simon Mourier is the solution:
remove the using on the MemoryStream, or remove that ConvertBytesToImage and keep the MemoryStream alive until you completely saved the image. – Simon Mourier 1 min ago
I don't understand why, but I have removed the using statement and now it works.
Thank all of You
I'm using the Movie Maker Library Timeline SDK Control 6.0 dll
And to add a photo you need a STRING of a file name. So far everything is fine
But I want to insert a function that gets an IMAGE object
But the library does not have a function that cables an IMAGE object
What I need is to get the file name out of the IMAGE object
That is: string fileName = image
Image img = default;
using (WebClient client = new WebClient())
{
string url = textBox1.Text;
Stream stream = client.OpenRead(url);
img = Image.FromStream(stream);
axTimelineControl1.AddImageClip(trackIndex: 1, fileName :img.ToString(),
clipStartTime: axTimelineControl1.GetMediaDuration(img.ToString()), clipStopTime: 4);
}
You've got a small bit of an "XY problem" here--you're asking the wrong question. Your axTimelineControl1 expects an image's file name. This implies that it also expects there to be an image saved to disk with that file name.
But all you have is a remote image, behind some URL. client.OpenRead(url) downloads the image into a Stream, but you can't do anything with that directly.
So, you don't want to take that image, and put it into a WinForms Image object. Instead, you want to save that image to disk with a file name, and then give that file name to your axTimelineControl1.
You have a few options for doing that:
1) You could take the Stream you got from client.OpenRead(), turn it into a FileStream and save it to disk.
2) You could use the WebClient to download the image directly to disk, and then give the image's file name to the axTimelineControl1.
Let's do 2) instead. It'll save a few steps.
First, create the file.
string fileName = System.IO.Path.GetTempFileName();
System.IO.File.Create(fileName).Close();
We're creating a "Temp" file here--these are meant to be treated as disposable. Note that Windows doesn't clean them up for you, so once you're done with it, your program should delete it. System.IO.File.Create() gives us a FileStream object, but we don't need it, so we Close() it right away, so that the WebClient will be able to write to our file.
Next, we download our image, and tell WebClient to save it to our newly-created Temp file:
// Defining my own URL here. Feel free to substitute your own.
string url = "https://derpicdn.net/img/view/2018/5/18/1735426.jpeg";
using (var client = new WebClient())
{
client.DownloadFile(url, fileName);
}
Now we have an image on disk, and we can tell the Movie Maker SDK Control where to find it:
float duration = axTimelineControl1.GetMediaDuration(fileName);
axTimelineControl1.AddImageClip(
trackIndex: 1,
fileName: fileName,
clipStartTime: duration,
clipStopTime: 4);
And that should do it.
The entire code listing:
string fileName = System.IO.Path.GetTempFileName();
System.IO.File.Create(fileName).Close();
// Defining my own URL here. Feel free to substitute your own.
string url = "https://derpicdn.net/img/view/2018/5/18/1735426.jpeg";
using (var client = new WebClient())
{
client.DownloadFile(url, fileName);
}
float duration = axTimelineControl1.GetMediaDuration(fileName);
axTimelineControl1.AddImageClip(
trackIndex: 1,
fileName: fileName,
clipStartTime: duration,
clipStopTime: 4);
Don't forget to clean up your temp file!
I am uploading a image for a user & saving it on a specified location. The code is working fine in normal scenario i.e. user selects a image & save it, it works.
Challenge occurs when user selects a image( probably wrong image due to mistake) & don't save it, but again selects a new image & then saves it.
This scenario gives me the error :
"The process cannot access the file because it is being used by another process."
When I try to delete image from the location at the time of error, file can't be deleted with message:
"The action can't be completed because the file is open in IIS Worker Process
Close the file and try again."
Code is like this:
try
{
if (!Directory.Exists(folder))
Directory.CreateDirectory(folder);
msf = new MemoryStream();
bytes=FileUpload1.FileBytes;
msf.Write(bytes, 0, bytes.Length);
using (FileStream stream = new FileStream(folder + "/" + filename, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
{
//converting any graphic file type to jpeg format
Image img = Image.FromStream(msf);
img.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
msf.WriteTo(stream);
IsuploadSuccess = true;
img.Dispose();
}
}
catch
{
IsuploadSuccess = false;
}
finally
{
if (msf != null)
{
msf.Close();
msf.Dispose();
}
}
I have tried adding "FileAccess.ReadWrite" & "FileShare.ReadWrite" in file stream, but doesn't work either with all options in File stream.
Please help...
Instead of getting solution of problem, I finally change approach to get rid to source of challenge. I change file name with UserID (unique) appended with CurrentDateTime converted to string & store it to temp folder until user save the change. This forms a different file each time for the challenge scenario. After save each file in temp folder created by the user (preceded by unique userid) is deleted & last changes are saved to respective directory.
I had this problem and took me few hours to figure it out.
I my case the Bitmap new(path) had locked the file. I had to dispose of it before exiting the using block.
However it is the method by which I debugged it is important.
My approach in pinpointing the source of the problem was to open the folder where the image was saved and tracing the code line by line. After each line I deleted the file and did Ctrl+Z to put it back. If it gave an error when I tried to delete it, then that is the line that locked it. So I got to that line within 5 min.
using (MemoryStream memoryStream = new())
{
if (System.IO.File.Exists(path))
{
using(Bitmap bitmap = new(path)) <-- this solved it
{
ImageConverter imageConverter = new();
bitmap.Save(memoryStream, ImageFormat.Bmp);
bytes = memoryStream.ToArray();
}
}
}
Here is my code:
public static TextWriter twLog = null;
private int fileNo = 1;
private string line = null;
TextReader tr = new StreamReader("file_no.txt");
TextWriter tw = new StreamWriter("file_no.txt");
line = tr.ReadLine();
if(line != null){
fileNo = int.Parse(line);
twLog = new StreamWriter("log_" + line + ".txt");
}else{
twLog = new StreamWriter("log_" + fileNo.toString() + ".txt");
}
System.IO.File.WriteAllText("file_no.txt",string.Empty);
tw.WriteLine((fileNo++).ToString());
tr.Close();
tw.Close();
twLog.Close();
It throws this error:
IOException: Sharing violation on path C:\Users\Water Simulation\file_no.txt
What i'm trying to do is just open a file with log_x.txt name and take the "x" from file_no.txt file.If file_no.txt file is empty make log file's name log_1.txt and write "fileNo + 1" to file_no.txt.After a new program starts the new log file name must be log_2.txt.But i'm getting this error and i couldn't understand what am i doing wrong.Thanks for help.
Well, you're trying to open the file file_no.txt for reading and for writing using separate streams. This may not work as the file will be locked by the reading stream, so the writing stream can't be created and you get the exception.
One solution would be to read the file first, close the stream and then write the file after increasing the fileNo. That way the file is only opened once at a time.
Another way would be to create a file stream for both read and write access like that:
FileStream fileStream = new FileStream(#"file_no.txt",
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.None);
The accepted answer to this question seems to have a good solution also, even though I assume you do not want to allow shared reads.
Possible alternate solution
I understand you want to create unique log files when your program starts. Another way to do so would be this:
int logFileNo = 1;
string fileName = String.Format("log_{0}.txt", logFileNo);
while (File.Exists(fileName))
{
logFileNo++;
fileName = String.Format("log_{0}.txt", logFileNo);
}
This increases the number until it finds a file number where the log file doesn't exist. Drawback: If you have log_1.txt and log_5.txt, the next file won't be log_6.txt but log_2.txt.
To overcome this, you could enumerate all the files in your directory with mask log_*.txt and find the greatest number by performing some string manipulation.
The possibilities are endless :-D
Well this may be old but the accepted answer didn't work for me. This is caused when you try to Read or Write a file you just created from a separate stream. Solving this is very simple, just dispose the filestream you used in creating it and then you can access the file freely.
if (!File.Exists(myfile))
{
var fs = new FileStream(fav, FileMode.Create);
fs.Dispose();
string text = File.ReadAllText(myfile);
}
enter image description here
var stream = new System.IO.FileStream(filePath, System.IO.FileMode.Create);
resizedBitmap.Compress(Bitmap.CompressFormat.Png, 200, stream); //problem here
stream.Close();
return resizedBitmap;
In the Compress method, I was passing the value of the quality parameter as 200, which sadly doesn't allows values outside the range 0-100.
I changed back the value of quality to 100 and the issue got fixed.
None of the proposed options helped me. But I found a solution:
In my case, the problem was with Anti-Virus, with intensive writing to a file, Anti-Virus started scanning the file and at that moment there was a problem with writing to the file.