Download an image using Async and save to bitmap [duplicate] - c#

This question already has an answer here:
Download multiple files async and wait for all of them to finish before executing the rest of the code
(1 answer)
Closed 6 years ago.
Following up from my question at this link and trying to implement the accepted answer:
Invoking a method asynchronously and/or on its own thread to increase performance
I'm trying to turn a simple method called DownloadImageFromUrl that takes a string Url and returns a Bitmap into one that will run using async. The current method:
private Bitmap DownloadImageFromUrl(string url)
{
//// METHOD A:
//WebRequest request = System.Net.WebRequest.Create(url);
//WebResponse response = request.GetResponse();
//Stream responseStream = response.GetResponseStream();
//return new Bitmap(responseStream);
// METHOD B:
using (WebClient client = new WebClient())
{
byte[] data = client.DownloadData(url);
using (MemoryStream mem = (data == null) ? null : new MemoryStream(data))
{
return (data == null || mem == null) ? null : (Bitmap)Image.FromStream(mem);
}
}
}
The idea of making this Async is so that in another method, I can use this one to do something like this:
public async Task<HttpResponseMessage> process(string image)
{
var task = DownloadFromBlobAsync(image);
var setupData = DoSomeSetup();
var image = await task;
return DrawTextOnImage(image, setupData);
}
The DoSomeSetup takes fairly long and so does downloading the image, so i'd like to download the image on its own thread while the setup happens.
I'm not sure what tools are available to change this downloadImageFromUrl to return a task.. Any resources or code examples would be helpful.

Sample by charlie from How to download image from url using c#:
using (WebClient client = new WebClient())
{
client.DownloadFileAsync(new Uri(url), #"c:\temp\image35.png");
client.DownloadFile(new Uri(url), #"c:\temp\image35.png");
}
EDITED
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile("fileNameHere");
BitmapImage bitmap = new BitmapImage();
var stream = await DownloadFile(new Uri("http://someuri.com", UriKind.Absolute));
bitmap.SetSource(stream);
WriteableBitmap wb = new WriteableBitmap(bitmap);
// Encode WriteableBitmap object to a JPEG stream.
Extensions.SaveJpeg(wb, fileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
fileStream.Close();
}
possible duplicated:
How to download image from url using c#

Related

C# Get icon from url as System.Drawing.Icon

I'm trying to put icons on a tab. I'm getting the icon from
http://google.com/favicon.ico for now.
I want to get the favicon.ico as System.Drawing.Icon. The original code I'm using is for a normal image, but I need it to be System.Drawing.Icon.
Here's my code so far:
var iconURL = "http://" + url.Host + "/favicon.ico";
System.Drawing.Icon img = null;
WebRequest request = WebRequest.Create(iconURL);
WebResponse response = request.GetResponse();
using (Stream stream = response.GetResponseStream())
{
img = new System.Drawing.Icon(stream);
// then use the image
}
qTabControl1.ActiveTabPage.Icon = img;
This gives me the following error:
You need to copy it to a stream that supports seeking, here is some sample code (using the newer HttpClient and async/await):
async Task<Icon> GetIcon()
{
var httpClient = new HttpClient();
using (var stream = await httpClient.GetStreamAsync(url))
using (var ms = new MemoryStream())
{
stream.CopyTo(ms);
ms.Seek(0, SeekOrigin.Begin); // See https://stackoverflow.com/a/72205381/640195
return new Icon(ms);
}
}

unable to use SaveJpeg method in windows phone 8 (NotSupportedException)

I am using below code to save a remote image in Windows Phone 8. But i keep hitting with System.NotSupportedException: Specified method is not supported. exception at SaveJpeg() method call.
I tried different combinations of method call (you can see commented line). I couldn't able to figure out what i am doing incorrectly.
using (HttpClient client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(imageUrl);
await Task.Run(async () =>
{
if (response.IsSuccessStatusCode)
{
// save image locally
Debug.WriteLine("Downloading image..." + imageName);
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!myIsolatedStorage.DirectoryExists("Images"))
myIsolatedStorage.CreateDirectory("Images");
string path = imageName;
IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile(path);
var buffer = await response.Content.ReadAsStreamAsync();
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
BitmapImage bitmap = new BitmapImage { CreateOptions = BitmapCreateOptions.None };
bitmap.SetSource(buffer);
WriteableBitmap wb = new WriteableBitmap(bitmap);
//System.Windows.Media.Imaging.Extensions.SaveJpeg(wb, fileStream, wb.PixelWidth, wb.PixelHeight, 0, 100);
wb.SaveJpeg(fileStream, wb.PixelWidth, wb.PixelHeight, 0, 98);
});
fileStream.Close();
}
}
});
}
By putting the code block in BeginInvoke block you are calling the SaveJpeg on a different thread (the "UI thread") to the code which calls fileStream.Close().
In effect this means it is very likely that the call to fileStream.Close() will be called before wb.SaveJpeg.
If you move the fileStream.Close() inside the BeginInvoke block, after wb.SaveJpeg() it should work.

Windows 8 How to open a BitmapImage as a stream?

In a Windows 8 app, how do I convert a BitmapImage to a Stream? I have a List of BitmapImages and I'm going to use that List to upload each image to a server and I need to use a Stream to do that. So is there a way to convert each individual BitmapImage into a Stream?
No, there isn't. You need to track the original sources or use a WriteableBitmap instead.
Retrieve the bitmap image:
public async void ContinueFileOpenPicker(FileOpenPickerContinuationEventArgs args)
{
if (args.Files.Count > 0)
{
var imageFile = args.Files[0] as StorageFile;
// Ensure the stream is disposed once the image is loaded
using (IRandomAccessStream fileStream = await imageFile.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
// Set the image source to the selected bitmap
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
ImageControl.Source = bitmapImage;
await _viewModel.Upload(imageFile);
}
}
}
Create the file stream:
internal async Task Upload(Windows.Storage.StorageFile file)
{
var fileStream = await file.OpenAsync(FileAccessMode.Read);
fileStream.Seek(0);
var reader = new Windows.Storage.Streams.DataReader(fileStream.GetInputStreamAt(0));
await reader.LoadAsync((uint)fileStream.Size);
Globals.MemberId = ApplicationData.Current.LocalSettings.Values[Globals.PROFILE_KEY];
var userName = "Rico";
var sex = 1;
var url = string.Format("{0}{1}?memberid={2}&name={3}&sex={4}", Globals.URL_PREFIX, "api/Images", Globals.MemberId, userName,sex);
byte[] image = new byte[fileStream.Size];
await UploadImage(image, url);
}
Create a memory stream from the image:
public async Task UploadImage(byte[] image, string url)
{
Stream stream = new System.IO.MemoryStream(image);
HttpStreamContent streamContent = new HttpStreamContent(stream.AsInputStream());
Uri resourceAddress = null;
Uri.TryCreate(url.Trim(), UriKind.Absolute, out resourceAddress);
Windows.Web.Http.HttpRequestMessage request = new Windows.Web.Http.HttpRequestMessage(Windows.Web.Http.HttpMethod.Post, resourceAddress);
request.Content = streamContent;
var httpClient = new Windows.Web.Http.HttpClient();
var cts = new CancellationTokenSource();
Windows.Web.Http.HttpResponseMessage response = await httpClient.SendRequestAsync(request).AsTask(cts.Token);
}

How to save images from web in Isolated Storage?

In my application I have list of urls to images. And what I need to do is download this images and save them in Isolated Storage.
What I already have:
using (IsolatedStorageFile localFile = IsolatedStorageFile.GetUserStoreForApplication()) {
...
foreach (var item in MyList)
{
Uri uri = new Uri(item.url, UriKind.Absolute);
BitmapImage bitmap = new BitmapImage(uri);
WriteableBitmap wb = new WriteableBitmap(bitmap);
using (IsolatedStorageFileStream fs = localFile.CreateFile(GetFileName(item.url)))//escape file name
{
wb.SaveJpeg(fs, wb.PixelWidth, wb.PixelHeight, 0, 85);
}
}
...
}
This code have place inside function in my App.xaml.cs file. I have tried many solutions, in this one the problem is "Invalid cross-thread access".
How can I make it work?
You get invalid cross-thread access if you create WriteableBitmap on non-UI thread. Ensure that that code is run on the main thread by using Dispatcher:
Deployment.Current.Dispatcher.BeginInvoke(() =>
// ...
);
Solution for this problem is:
foreach (var item in MyList)
{
Uri uri = new Uri(item.url, UriKind.Absolute);
HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
request.BeginGetResponse((ar) =>
{
var response = request.EndGetResponse(ar);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
using (var stream = response.GetResponseStream())
{
var name = GetFileName(item.url);
if (localFile.FileExists(name))
{
localFile.DeleteFile(name);
}
using (IsolatedStorageFileStream fs = localFile.CreateFile(name))
{
stream.CopyTo(fs);
}
}
});
}, null);
}
#Mateusz Rogulski
You should use WebClient, and i suggest you following solution for your problem. just try.
public string YourMethod(string yoursUri)
{
BitmapImage image=new BitmapImage();
WebClient client = new WebClient();
client.OpenReadCompleted += async (o, args) =>
{
Stream stream = new MemoryStream();
await args.Result.CopyToAsync(stream);
image.SetSource(stream);
};
client.OpenReadAsync(new Uri(yoursUri));//if passing object than you can write myObj.yoursUri
return image;
}
now you have image and you can save into your isolatedStorage with valid checks wherever you call this function

How write a file using StreamWriter in Windows 8?

I'm having trouble when creating a StreamWriter object in windows-8, usually I just create an instance just passing a string as a parameter, but in Windows 8 I get an error that indicates that it should recieve a Stream, but I noticed that Stream is an abstract class, Does anybody knows how will be the code to write an xml file?, BTW I'm using .xml because I want to save the serialized object, or does anyone knows how to save to a file a serialized object in Windows 8?.
Any ideas?
Currently using Windows 8 Consumer Preview
Code:
StreamWriter sw = new StreamWriter("person.xml");
Error:
The best overloaded method match for 'System.IO.StreamWriter.StreamWriter(System.IO.Stream)' has some invalid arguments
Instead of StreamWriter you would use something like this:
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile file = await folder.CreateFileAsync();
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter dataWriter = new DataWriter(outputStream))
{
//TODO: Replace "Bytes" with the type you want to write.
dataWriter.WriteBytes(bytes);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
await outputStream.FlushAsync();
}
}
You can look at the StringIOExtensions class in the WinRTXamlToolkit library for sample use.
EDIT*
While all the above should work - they were written before the FileIO class became available in WinRT, which simplifies most of the common scenarios that the above solution solves since you can now just call await FileIO.WriteTextAsync(file, contents) to write text into file and there are also similar methods to read, write or append strings, bytes, lists of strings or IBuffers.
You can create a common static method which you can use through out application like this
private async Task<T> ReadXml<T>(StorageFile xmldata)
{
XmlSerializer xmlser = new XmlSerializer(typeof(List<myclass>));
T data;
using (var strm = await xmldata.OpenStreamForReadAsync())
{
TextReader Reader = new StreamReader(strm);
data = (T)xmlser.Deserialize(Reader);
}
return data;
}
private async Task writeXml<T>(T Data, StorageFile file)
{
try
{
StringWriter sw = new StringWriter();
XmlSerializer xmlser = new XmlSerializer(typeof(T));
xmlser.Serialize(sw, Data);
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter dataWriter = new DataWriter(outputStream))
{
dataWriter.WriteString(sw.ToString());
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
await outputStream.FlushAsync();
}
}
}
catch (Exception e)
{
throw new NotImplementedException(e.Message.ToString());
}
}
to write xml simply use
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync("data.xml",CreationCollisionOption.ReplaceExisting);
await writeXml(Data,file);
and to read xml use
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync("data.xml");
Data = await ReadXml<List<myclass>>(file);

Categories