I'm trying to save an image from the web to the isolated storage from a background task but it throws
An unhandled exception of type 'System.UnauthorizedAccessException' occurred in System.Windows.ni.dll
i'm using this piece of code
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(tempJPEG))
{
myIsolatedStorage.DeleteFile(tempJPEG);
}
IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile(tempJPEG);
StreamResourceInfo sri = null;
Uri uri = new Uri(tempJPEG, UriKind.Relative);
sri = Application.GetResourceStream(uri);
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(e.Result);
WriteableBitmap wb = new WriteableBitmap(bitmap);
// Encode WriteableBitmap object to a JPEG stream.
Extensions.SaveJpeg(wb, fileStream, wb.PixelWidth, wb.PixelHeight, 0, 100);
//wb.SaveJpeg(fileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
fileStream.Close();
}
This works 100% when it's runing from the app , but not from the background task.
Any tips on how to save the image ?
You need to invoke this code Dispatcher.BeginInvoke() since WriteableBitmap needs to execute on the UI thread and not a background thread. See # http://codeblog.vurdalakov.net/2012/02/solution-wp7-unauthorizedaccessexceptio.html
Related
I'm developing a WP8 app using Nokia Imaging SDK.
I'm trying to add filter effect to an image and render it into a WriteableBitmap.
Here is my code:
private async void PhotoChosen(object sender, PhotoResult photoResult)
{
if (photoResult != null)
{
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(photoResult.ChosenPhoto);
WriteableBitmap wb = new WriteableBitmap(bitmap.PixelWidth, bitmap.PixelHeight);
StreamImageSource source = new StreamImageSource(photoResult.ChosenPhoto);
var effects = new FilterEffect(source);
effects.Filters = new IFilter[] { new SketchFilter() };
var renderer = new WriteableBitmapRenderer(effects, wb);
await renderer.RenderAsync();
}
}
All is going fine, but when this line is processing:
await renderer.RenderAsync();
This ArgumentException is thrown:
Value does not fall within the expected range
I think I've made a mistake creating the IImageProvider effects or the WriteableBitmap wb
Does anyone got this problem and found an issue ?
Thanks :)
You need to set the stream position before setting it as source for StreamImageSource.
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(photoResult.ChosenPhoto);
WriteableBitmap wb = new WriteableBitmap(bitmap.PixelWidth, bitmap.PixelHeight);
photoResult.ChosenPhoto.Position = 0;
StreamImageSource source = new StreamImageSource(photoResult.ChosenPhoto);
You need to do this because you have called bitmap.SetSource(photoResult.ChosenPhoto). That means that the stream has already been read once, therefore it's position is at the very end of the stream. When StreamImageSource tries to read it, it is already at the end, thus "Value does not fall within the expected range."
I can load JPEGs fine using the specialised JPEG load jpeg method, I can also save PNGs fine using the many methods detailed on SO.
However whenever I create a stream for loading a PNG from isolated storage it results in a BitmapImage of zero size.
Here is what I have ...
public static async Task<BitmapImage> ReadBitmapImageFromIsolatedStorage(string fn)
{
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
if (local != null)
{
Stream file = await local.OpenStreamForReadAsync(fn);
BitmapImage bi = new BitmapImage();
bi.SetSource(file);
return bi;
}
return null;
}
I've tried many variations as well. It seems there is some kind of delay to reading the stream when creating BitmapImages which means often the stream is disposed of before the BitmapImage reads it. In WPF there is an option that can be set but WIndows Phone BitmapImage does not have this option.
Try this:
BitmapImage image = new BitmapImage();
image.DecodePixelWidth = 500; //desired width, optional
image.DecodePixelHeight = 500; //desired height, optional
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists("imagepath"))
{
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile("imagepath", FileMode.Open, FileAccess.Read))
{
image.SetSource(fileStream);
}
}
}
This is what I found works in the end using the new Windows.Storage APIs
I'm not 100% clear what the problem was originally but this works. This has some extra functionality in that if it fails to read, it retries a second or so later ...
public static async Task<BitmapImage> ReadBitmapImageFromIsolatedStorage(string fn)
{
Uri uri = new Uri(String.Format("ms-appdata:///local/{0}", fn));
// FileAccessAttempts is just an int that determines how many time
// to try reading before giving up
for (int i = 0; i < AppConfig.FileAccessAttempts; i++)
{
try
{
StorageFile file = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
Stream stream = await file.OpenStreamForReadAsync();
BitmapImage bi = new BitmapImage();
bi.SetSource(stream);
return bi;
}
catch
{
// Similar functions also have a ~1 second retry interval so introduce
// a random element to prevent blocking from accidentally synched retries
Random r = new Random();
System.Threading.Thread.Sleep(950 + (int)Math.Floor(r.Next() * 50.0));
}
}
return new BitmapImage();
}
i am trying to save an image i.e., present in my project to the isolated storage. i tried using the following code but it is throwing System.NullReferenceException.
IsolatedStorageFileStream fileStream1 = myIsolatedStorage.CreateFile("shared/shellcontent/image.jpg");
Uri uri = new Uri(#"/myapp;/component/contact.bmp", UriKind.Relative);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.UriSource = uri;
WriteableBitmap wb = new WriteableBitmap(bitmapImage); //throwing exception
Extensions.SaveJpeg(wb, fileStream1, wb.PixelWidth, wb.PixelHeight, 0, 85);
i tried with jpg image also. copy to output directory set to copy if never. also tried with build action set to content
.............
just tried this code and the exception isn't showing now but still when am setting it to a tile background. its blank
Uri uri = new Uri("contact.jpg", UriKind.Relative);
StreamResourceInfo sri = null;
sri = Application.GetResourceStream(uri);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(sri.Stream);
WriteableBitmap wb = new WriteableBitmap(bitmapImage);
Extensions.SaveJpeg(wb, fileStream1, wb.PixelWidth, wb.PixelHeight, 0, 85);
update:
issue is resolved. filestream was not closed. silly me
How can I convert a WriteableBitmap to stream on WP8 platform?
Final goal is to dump the image output produced by native code to the CameraRoll library using SavePictureToCameraRoll(filename, stream)
You can encode your bitmap to stream with WritableBitmap.SaveJpeg method and use this stream as a parameter to MediaLibrary.SavePictureToCameraRoll.
Note: before calling MediaLibrary.SavePictureToCameraRoll don't forget to set the stream position to 0 if you're using a MemoryStream. Like this:
var wb = new WriteableBitmap(bitmap);
var fileStream = new MemoryStream();
wb.SaveJpeg(fileStream, wb.PixelWidth, wb.PixelHeight, 100, 100);
fileStream.Seek(0, SeekOrigin.Begin);
var m = new MediaLibrary();
m.SavePictureToCameraRoll("test", fileStream);
I have stored few images in isolatedstorage and I am trying to replace them by using
using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication()){
if (isStore.FileExists(fileName)){
isStore.DeleteFile(fileName);
}
using (IsolatedStorageFileStream targetStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write)){
// Initialize the buffer for 4KB disk pages.
byte[] readBuffer = new byte[4096];
int bytesRead = -1;
// Copy the thumbnail to the local folder.
while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0){
targetStream.Write(readBuffer, 0, bytesRead);
targetStream.Close();
}
}
Now When I am trying to access the new file I end up seeing the old photo. the new photo is not replaced immediately.
But when I close the app and again fetch it I get the new photo. What is wrong?
I was using an ImageBrush to paint the background grid and was binding only the ImageSource of the ImageBrush. I guess this ImageBrush was not getting updated so instead of changing the source of the ImageBrush I created a new object of it and assigned it to Grid.Background. so now it works :)