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
Related
am trying to show image directly from zip file without extracting file.
ZipArchiveEntry tumbnail = archive.Entries.Where(s => s.FullName.Equals("coverthumb.png")).FirstOrDefault();
if (tumbnail != null)
{
Stream picdata = tumbnail.Open();
await picdata.CopyToAsync (picdata);
BitmapImage bt = new BitmapImage();
bt.SetSource (picdata.AsRandomAccessStream());
image.Source = bt;
}
but getting an
cannot seek exception
please help.
the following code works for images but when tries to read many images at once some times it gives invalid data exception at bitmap creation
async public static Task<BitmapImage> GetImageFromZipEntry(ZipArchiveEntry zipentry)
{
//for extracting image inside a zip as bitmapimage
BitmapImage tm = new BitmapImage();
try {
if (zipentry != null)
{
using (Stream imstream = zipentry.Open())
{
using (MemoryStream immemorystream = new MemoryStream((int)zipentry.Length))
{
await imstream.CopyToAsync(immemorystream);
using (var sourceStream = new MemoryStream(immemorystream.ToArray()))
{
await tm.SetSourceAsync(sourceStream.AsRandomAccessStream());
}
}
}
}
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
tm = null;
}
return tm;
}
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.
I made a project to Cache Images. I want to wait in main thread for complete DownloadImage function and then return that saved bitmap. Is that possible?
Am I doing it even properly?
public static ImageSource GetImage(int id)
{
BitmapImage bitmap = new BitmapImage();
String fileName=string.Format("ImageCache/{0}.jpg", id);
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!myIsolatedStorage.DirectoryExists("ImageCache"))
{
myIsolatedStorage.CreateDirectory("ImageCache");
}
if (myIsolatedStorage.FileExists(fileName))
{
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(fileName, FileMode.Open, FileAccess.Read))
{
bitmap.SetSource(fileStream);
}
}
else
{
DownloadImage(id);
//HERE - how to wait for end of DownloadImage and then do that below??
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(fileName, FileMode.Open, FileAccess.Read))
{
bitmap.SetSource(fileStream);
}
}
}
return bitmap;
}
Here is DownloadImage function:
private static void DownloadImage(Object id)
{
WebClient client = new WebClient();
client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
client.OpenReadAsync(new Uri(string.Format("http://example.com/{0}.jpg", id)), id);
}
private static void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (e.Error == null && !e.Cancelled)
{
try
{
string fileName = string.Format("ImageCache/{0}.jpg", e.UserState);
IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile(fileName);
BitmapImage image = new BitmapImage();
image.SetSource(e.Result);
WriteableBitmap wb = new WriteableBitmap(image);
// Encode WriteableBitmap object to a JPEG stream.
Extensions.SaveJpeg(wb, fileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
fileStream.Close();
}
catch (Exception ex)
{
//Exception handle appropriately for your app
}
}
}
}
You have many way to achieve what you want. It is possible to wait with async await command which is part of Visual Studio Async.
You can download the latest CTP from here. More how to use it.
Personally I would use events.
This one contains some details and code example: http://www.ben.geek.nz/2010/07/one-time-cached-images-in-windows-phone-7/
I am making a WP7 app which download all my twitter feed. In this I want to download all the profile images and store them locally and use them, so that they would be downloaded every time i open the app. Please suggest any of the methods to do so.
What I am doing: using a WebClient to download the image
public MainPage()
{
InitializeComponent();
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri("http://www.libpng.org/pub/png/img_png/pnglogo-blk.jpg"));
}
and store it to a file.
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(fileName1))
myIsolatedStorage.DeleteFile(fileName1);
var fileName1 = "Image.jpg";
using (var fileStream = new IsolatedStorageFileStream(fileName1, FileMode.Create, myIsolatedStorage))
{
using (var writer = new StreamWriter(fileStream))
{
var length = e.Result.Length;
writer.WriteLine(e.Result);
}
var fileStreamLength = fileStream.Length;
fileStream.Close();
}
}
Now I am trying to set the image to a BitMapImage
BitmapImage bi = new BitmapImage();
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(fileName1, FileMode.Open, FileAccess.Read))
{
var fileStreamLength2 = fileStream.Length;
bi.SetSource(fileStream);
}
}
But I am not able to set source of the BitmapImage. It is throwing System.Exception and nothing specific. Am I doing it the right way? I mean the procedure.
EDIT Another observation is the fileStreamLength and fileStreamLength2 are different.
You're not supposed to use DownloadString to download a binary file. Use OpenReadAsync instead, and save the binary array to the isolated storage.
DownloadString will try to convert your data to UTF-16 text, which of course can't be right when dealing with a picture.
I tried using this code for download image:
void downloadImage(){
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri("http://mysite/image.png"));
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
//how get stream of image??
PicToIsoStore(stream)
}
private void PicToIsoStore(Stream pic)
{
using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
var bi = new BitmapImage();
bi.SetSource(pic);
var wb = new WriteableBitmap(bi);
using (var isoFileStream = isoStore.CreateFile("somepic.jpg"))
{
var width = wb.PixelWidth;
var height = wb.PixelHeight;
Extensions.SaveJpeg(wb, isoFileStream, width, height, 0, 100);
}
}
}
The problem is: how get the stream of image?
Thank!
It's easy to get a stream to a file in Isolated Storage. IsolatedStorageFile has an OpenFile method that gets one.
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = store.OpenFile("somepic.jpg", FileMode.Open))
{
// do something with the stream
}
}
You need to put e.Result as a parameter when calling PicToIsoStore inside your client_DownloadStringCompleted method
void client_DownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
{
PicToIsoStore(e.Result);
}
The WebClient class gets response and stores it in the e.Result variable. If you look carefully, the type of e.Result is already Stream so it is ready to be passed to your method PicToIsoStore
There is an easy way
WebClient client = new WebClient();
client.OpenReadCompleted += (s, e) =>
{
PicToIsoStore(e.Result);
};
client.OpenReadAsync(new Uri("http://mysite/image.png", UriKind.Absolute));
Try the following
public static Stream ToStream(this Image image, ImageFormat formaw) {
var stream = new System.IO.MemoryStream();
image.Save(stream);
stream.Position = 0;
return stream;
}
Then you can use the following
var stream = myImage.ToStream(ImageFormat.Gif);