I am having a really weird issue with my image saving method. First, here is the method:
public static void uploadImageToServer(string savePath, HttpPostedFile imageToUpload, bool overwrite)
{
byte[] myData = new Byte[imageToUpload.ContentLength];
imageToUpload.InputStream.Read(myData, 0, imageToUpload.ContentLength);
FileStream newFile = new FileStream(savePath, FileMode.Create);
newFile.Write(myData, 0, myData.Length);
newFile.Close();
}
As you can see from the input parameters this method works in conjuction with the FileUpload control. Now I am using this method from two pages which both have a FileUpload control. On one page the image uploads file, on the other page it results in a corrupted file.
I am really at a loss as to why the image is being corrupted. I am using the same image, the same method, and the same input control.
Is there any way I can debug this?
Gonna steal alexn's answer <_<
You are over-complicating it. Just use the built-in FileUpload::SaveAs(save_path) that is provided for you.
You can use the Server.MapPath() method to help you get a dynamic path to your root directory, go from there and append the file name to it.
Not sure why you are getting that error. My best guess is either your savePath is broken (or the filename/extension appended to it), or the bytes are not being read/written to perfectly.. Anyway, you should not get that error by using the method I described (considering you don't mess up the file extension :).
Related
I'm doing the file attachment through memory stream because temporary storage is not an option.
Here I did a Jpeg image attachment. I looked at other file types with which you could do the same by switching the MediaTypeNames, and unfortunately .doc and .docx is not among them.
I was wondering whether any of you know of any package and how to use it for this particular occasion?
//...set up MailMessage, add a bunch of non-file content to it
MemoryStream jpgStream = new MemoryStream();
string filename = uploadedFile.FileName;
System.Drawing.Image theImage = System.Drawing.Image.FromStream(uploadedFile.InputStream);
theImage.Save(jpgStream, System.Drawing.Imaging.ImageFormat.Jpeg);
jpgStream.Seek(0L, SeekOrigin.Begin);
emailMessage.Attachments.Add(new Attachment(jpgStream, filename, System.Net.Mime.MediaTypeNames.Image.Jpeg));
//something extra and send email...
You should use MediaTypeNames.Application.Octet as mime type.
From : https://learn.microsoft.com/fr-fr/dotnet/api/system.net.mime.mediatypenames.application.octet?view=netframework-4.7.2
Thanks Benoit Gidon for his answer. I was proved once again that your assumptions are your worst enemy.
Apparently it's as simple as that and you don't need any other special methods as long as you put the file.InputStream in directly into attachment, unlike other S.O. posts make you believe:
https://stackoverflow.com/questions/9095880/attach-multiple-image-formats-not-just-jpg-to-email
https://stackoverflow.com/questions/5336239/attach-a-file-from-memorystream-to-a-mailmessage-in-c-sharp
In case anyone is actually struggling with it, here is the code:
foreach (HttpPostedFileBase file in fullViewModel.filesCollection)
{
string filename = file.FileName;
msg.Attachments.Add(new Attachment(file.InputStream, filename, MediaTypeNames.Application.Octet));
}
I tested this with a .docx document that had 5000 words of content in it, as well as tables and pictures, and it gets reconstructed the way it was in my gmail client.
Just tested that, it also works the same way with .png, so no need for PngBitmapDecoder.
I have build a program which allows me to insert comment and the title of an Image through System.Image.Drawing so right now, I have trouble trying to overwrite the existing Jpeg file with the one that has comment and title added into it, but I am encountering error while deleting the file, so I'm not sure what to do as I have tried disposing the file but I cant saved it in that case, due to the fact that I disposed it too early, but I cant saved it because the existing file name is not deleted so I'm kinda stuck in the middle right now.
Here are my codes for it:
public string EditComment(string OriginalFilepath, string newFilename)
{
image = System.Drawing.Image.FromFile(OriginalFilepath);
PropertyItem propItem = image.PropertyItems[0];
using (var file = System.Drawing.Image.FromFile(OriginalFilepath))
{
propItem.Id = 0x9286; // this is the id for 'UserComment'
propItem.Type = 2;
propItem.Value = System.Text.Encoding.UTF8.GetBytes("HelloWorld\0");
propItem.Len = propItem.Value.Length;
file.SetPropertyItem(propItem);
PropertyItem propItem1 = file.PropertyItems[file.PropertyItems.Count() - 1];
file.Dispose();
image.Dispose();
string filepath = Filepath;
if (File.Exists(#"C:\Desktop\Metadata"))
{
System.IO.File.Delete(#"C:\Desktop\Metadata");
}
string newFilepath = filepath + newFilename;
file.Save(newFilepath, ImageFormat.Jpeg);//error appears here
return filepath;
}
}
The Error shown are:
An exception of type 'System.ArgumentException' occurred in System.Drawing.dll but was not handled in user code
Additional information: Parameter is not valid.
The problem is that opening an image from file locks the file. You can get around that by reading the file into a byte array, creating a memory stream from that, and then opening the image from that stream:
public string EditComment(string originalFilepath, string newFilename)
{
Byte[] bytes = File.ReadAllBytes(originalFilepath);
using (MemoryStream stream = new MemoryStream(bytes))
using (Bitmap image = new Bitmap(stream))
{
PropertyItem propItem = image.PropertyItems[0];
// Processing code
propItem.Id = 0x9286; // this is the id for 'UserComment'
propItem.Type = 2;
propItem.Value = System.Text.Encoding.UTF8.GetBytes("HelloWorld\0");
propItem.Len = propItem.Value.Length;
image.SetPropertyItem(propItem);
// Not sure where your FilePath comes from but I'm just
// putting it in the same folder with the new name.
String newFilepath;
if (newFilename == null)
newFilepath = originalFilePath;
else
newFilepath = Path.Combine(Path.GetDirectory(originalFilepath), newFilename);
image.Save(newFilepath, ImageFormat.Jpeg);
return newFilepath;
}
}
Make sure you do not dispose your image object inside the using block as you did in your test code. Not only does the using block exist exactly so you don't have to dispose manually, but it's also rather hard to save an image to disk that no longer exists in memory. Similarly, you seem to open the image from file twice. I'm just going to assume all of those were experiments to try to get around the problem, but do make sure to clean those up.
The basic rules to remember when opening images are these:
An Image object created from a file will lock the file during the life cycle of the image object, preventing the file from being overwritten or deleted until the image is disposed.
An Image object created from a stream will need the stream to remain open for the entire life cycle of the image object. Unlike with files, there is nothing actively enforcing this, but after the stream is closed, the image will give errors when saved, cloned or otherwise manipulated.
Contrary to what some people believe, a basic .Clone() call on the image object will not change this behaviour. The cloned object will still keep the reference to the original source.
Note, if you actually want a usable image object that is not contained in a using block, you can use LockBits and Marshal.Copy to copy the byte data of the image object into a new image with the same dimensions and the same PixelFormat, effectively making a full data clone of the original image. (Note: I don't think this works on animated GIF files) After doing that, you can safely dispose the original and just use the new cleanly-cloned version.
There are some other workarounds for actually getting the image out, but most of them I've seen aren't optimal. These are the two most common other valid workarounds for the locking problem:
Create a new Bitmap from an image loaded from file using the Bitmap(Image image) constructor. This new object will not have the link to that file, leaving you free to dispose the one that's locking the file. This works perfectly, but it changes the image's colour depth to 32-bit ARGB, which might not be desired. If you just need to show an image on the UI, this is an excellent solution, though.
Create a MemoryStream as shown in my code, but not in a using block, leaving the stream open as required. Leaving streams open doesn't really seem like a good idea to me. Though some people have said that, since a MemoryStream is just backed by a simple array, and not some external resource, the garbage collector apparently handles this case fine...
I've also seen some people use System.Drawing.ImageConverter to convert from bytes, but I looked into the internals of that process, and what it does is actually identical to the last method here, which leaves a memory stream open.
I am trying download an image from a website and put it in a picturebox.
// response contains HttpWebResponse of the page where the image is
using (Stream inputStream = response.GetResponseStream()) {
using (Stream outputStream = File.Open(fileName, FileMode.Create)) {
byte[] buffer = new byte[4096];
int bytesRead;
do {
bytesRead = inputStream.Read(buffer, 0, buffer.Length);
outputStream.Write(buffer, 0, bytesRead);
} while (bytesRead != 0);
}
}
response.Close();
After that, the downloaded image is assigned to a PictureBox like such:
if (imageDownloaded) {
pictureBox1.Image = Image.FromFile(filePath);
}
This all works like a charm first time, but the second time I run the code I get System.IO.IOException: "Additional information: The process cannot access the file ...(file path) ... because it is being used by another process.". I have no idea why...
I looked at 4 other threads such as this one, but they were basically stressing out the need to close streams, which I do, so none of them helped me.
Before you recommend to use pictureBox1.Load() I can't because I need the image downloaded for further development.
EDIT 1: I have actually tried to dispose the image by putting pictureBox1.Image = null before the code above is executed. It is still giving me an exception.
The Image.FromFile docs state:
The file remains locked until the Image is disposed.
So you need to dispose your Image too to be able to overwrite the file.
Try using the Clone method on your image and dispose the original Image.
The thing is related to the Image.FromFile. If we read a documentation, there is a note:
The file remains locked until the Image is disposed.
This pretty much explains the behavior you get.
To resolve this, you might need to create a copy of the image and assign it to a PictureBox .
From MSDN:
The file remains locked until the Image is disposed.
This means its the PictureBox that is holding the file open.
You have two options:
Dispose of the PictureBox image before writing the new file.
Download the file, make a copy of it and load the copy into the PictureBox - this allows you to write over the downloaded file freely.
I'll be the contrarian here. :)
While cloning/copying the image will resolve the exception, it raises a different question: why are you overwriting to the same file for a new image?
It seems to me that a better approach would be to download subsequent files to different file names (if they are really different files), or to simply reuse the file already downloaded instead of hitting the network again (if it's just a new request for the same file).
Even if you want to repeatedly download the same file (perhaps you expect the actual file contents to change), you can still download to a new name (e.g. append a number to the file name, use a GUID for the local file name, etc.)
I'm having some really weird problems trying to load a file pragmatically into my project to save to a local folder.
I can load the file fine in my .xaml code, as so:
<BitmapImage x:Key="Image" UriSource ="/Assets/Submandibular_oedema.jpg" />
And I can display that image on my page. However, when I try to load the image and use it in my xaml.cs code like this
uriMyFile = new Uri("/Assets/Submandibular_oedema.jpg", UriKind.RelativeOrAbsolute);
It cannot find the file and as a result, won't let me do anything with the URI.
For background, my aim is to get the image stream then save it to a local folder.
I know it'll be a stupid little problem, but I can't find any solutions to it.
Thanks!
Try full path (specify your project assembly)
uriMyFile = new Uri("/YourAssemblyName;component/Assets/Submandibular_oedema.jpg",UriKind.RelativeOrAbsolute);
Update after Starktastics comment:
I finally understood your problem: you need the Application.GetResourceStream method to retrieve a stream of your resource, read from that stream and write it to a file stream.
var streamResourceInfo = Application.GetResourceStream(uri);
var stream = streamResourceInfo.Stream;
var byteBuffer = new byte[stream.Length];
using (stream)
{
stream.Read(byteBuffer, 0, byteBuffer.Length);
}
using (var fileStream = new FileStream("photo.jpg", FileMode.Create))
{
fileStream.Write(byteBuffer, 0, byteBuffer.Length);
}
I've updated the solution that you can download here.
Original answer:
If you use a WPF application, make sure that the asset you added to your project is to Build Action 'Resource'. You can check that in the properties pane after you clicked the file.
In any case, your syntax for the URI is correct. I checked it in a small project myself and it works. You can download it here (DropBox link)
Feel free to leave a comment.
Try to use
uriMyFile=new Uri("ms-appx:///Assets/YourImage.png"));
This works for me while trying to show a diffrent map icon for each place.
Okay so I want to download a file from a website, but the file is lacking an extension.
(it's an image file, I know this much, but the link does not provide the actual extension)
When I use webrequest, or webclient to download the file I get a "404 file not found" exception.
WebClient wc = new WebClient();
Stream strm = wc.DownloadFile("http://some_site.some_domain/some_image.","C:/some_directory/save_name.some_extention");
Notice the lack of extention at the end of the URL.
The site in question displays the image fine in a webbrowser, but when viewing just the image there is no extension and thus it's treated an unknown file (not showing an image).
So simply put: how do I download a file if there is no extention specified?
Thanks in advance!
So you're trying to determine what extension to give the file after downloading? If the URL doesn't have one you would have to inspect the actual data of the file.
You might be able to inspect the beginning of the file and see if it matches known valid file types. For instance, PNGs seem to have 'PNG' as bytes 2-4 (at least in the ones I've inspected). By looking at that data you should be able to determine the format with a fairly high accuracy.
This would be my best suggestion, if this doesn't work I don't know how to solve you problem...
List<string> fileExtensions = new List<string>(){"png","gif","bmp","jpg"}// other known image file extensions here...
WebClient wc = new WebClient();
foreach(var extension in fileExtensions)
{
try
{ wc.DownloadFile("http://some_site.some_domain/some_image."+extension,"C:/some_directory/save_name."+extension);
break;
}
catch {}
}
This would just be a work around, I guess... Not a real solution...