Read BitmapImage from Zip archive - c#

For a WPF project I need to read a BitmapImage from a Zip file. The original fileformat is .png I know how to do this directly from a file system and that is working fine. From a Zip file, unfortunately the image is not shown, though an image seems to be read.
I created a simple test project:
public partial class MainWindow : Window
{
public BitmapImage RouteImage { get; set; }
public MainWindow()
{
InitializeComponent();
LoadBitmap();
DataContext = RouteImage;
}
public void LoadBitmap()
{
RouteImage = new BitmapImage();
var PackedFile = #"D:\Temp\MainContent.ap";
try
{
{
using (ZipArchive archive = ZipFile.OpenRead(PackedFile))
{
var file = archive.GetEntry("RouteInformation/image.png");
if (file != null)
{
using (var zipEntryStream = file.Open())
{
RouteImage.BeginInit();
RouteImage.CacheOption = BitmapCacheOption.OnLoad;
RouteImage.StreamSource = zipEntryStream;
RouteImage.EndInit();
return;
}
}
}
}
}
catch (Exception e)
{
var s = "Exception: " + e.Message;
}
}
}
}
The XAML code looks like this:
<Image Height="128" Width="256" Source="{Binding BitmapImage}"/>
In the debugger it looks like the stream is created and bound to the BitmapImage, but the width and height are set to 1. so I think something is wrong withe the reading of the data in the zip file.

Not sure about the exact reason, but it seems necessary to copy the zip stream to an intermediate MemoryStream and read the BitmapImage from there.
You should also write a view model class with property change notification:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private BitmapImage routeImage;
public BitmapImage RouteImage
{
get { return routeImage; }
set
{
routeImage = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(RouteImage)));
}
}
public void LoadImage(string archiveName, string entryName)
{
using (var archive = ZipFile.OpenRead(archiveName))
{
var entry = archive.GetEntry(entryName);
if (entry != null)
{
using (var zipStream = entry.Open())
using (var memoryStream = new MemoryStream())
{
zipStream.CopyTo(memoryStream); // here
memoryStream.Position = 0;
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = memoryStream;
bitmap.EndInit();
RouteImage = bitmap;
}
}
}
}
}
Assign an instance of the view model to the DataContext of your Window:
public MainWindow()
{
InitializeComponent();
var viewModel = new ViewModel();
DataContext = viewModel;
viewModel.LoadImage(
#"D:\Games\steamapps\common\RailWorks\Content\Routes\00000036-0000-0000-0000-000000002012\MainContent.ap",
"RouteInformation/image.png");
}
and bind the RouteImage property like this:
<Image Source="{Binding RouteImage}"/>
If you are intending to load large image file from the zip archive, I'd recommend to call the view model code in an async method:
public async Task LoadImageAsync(string archiveName, string entryName)
{
RouteImage = await Task.Run(() => LoadImage(archiveName, entryName));
}
private BitmapImage LoadImage(string archiveName, string entryName)
{
BitmapImage bitmap = null;
using (var archive = ZipFile.OpenRead(archiveName))
{
var entry = archive.GetEntry(entryName);
if (entry != null)
{
using (var zipStream = entry.Open())
using (var memoryStream = new MemoryStream())
{
zipStream.CopyTo(memoryStream);
memoryStream.Position = 0;
bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = memoryStream;
bitmap.EndInit();
bitmap.Freeze(); // necessary when loaded in non-UI thread
}
}
}
return bitmap;
}
Call the method from an async Loaded event handler in your MainWindow:
Loaded += async (s, e) => await viewModel.LoadImageAsync
#"D:\Games\steamapps\common\RailWorks\Content\Routes\00000036-0000-0000-0000-000000002012\MainContent.ap",
"RouteInformation/image.png");

In my work to remove an image from a zip container, that using a middle thread as per Clemens answer only created an exception and was not tenable.
Ultimately I was able to use this code to extract a BitmapImage:
public static class StreamExtensions
{
public static BitmapImage ToImage(this Stream stream)
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = stream;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
return bitmap;
}
}
Usage
var image = zipEntry.Open().ToImage();

Related

UWP: Unable to load image on listview

I have a program where it gets images from website and bind it to the list. I tested the link on my browser and it's shows the image however, when I run, it showing error:
WinRT information: The value cannot be converted to type
ImageSource.
I was previously worked on some projects with list view and I never got this error before.
<ListView Grid.Row="1" ItemsSource="{x:Bind AllSongs}"
Margin="50,20,50,0">
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:SongList">
<StackPanel Orientation="Horizontal">
<Image Source="{x:Bind Image}"/>
<TextBlock Text="{x:Bind Name}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My xaml.cs code
public sealed partial class MainPage : Page
{
ObservableCollection<SongList> AllSongs;
public MainPage()
{
this.InitializeComponent();
AllSongs = new ObservableCollection<SongList>();
}
private async void searchButton_Click(object sender, RoutedEventArgs e)
{
MyProgress.IsActive = true;
MyProgress.Visibility = Visibility.Visible;
var allSongs = await SongListManager.GetSongListsAsync(singerAlbumSearchbar.Text);
foreach (var songs in allSongs)
AllSongs.Add(songs);
MyProgress.IsActive = false;
MyProgress.Visibility = Visibility.Collapsed;
}
}
And the code I use to get the links
public class SongListManager
{
public static async Task<List<SongList>> GetSongListsAsync(string SingerName)
{
var newSongList = new List<SongList>();
HttpClient client = new HttpClient();
var jsonData = await client.GetStringAsync("https://theaudiodb.com/api/v1/json/1/searchalbum.php?s=" + SingerName);
var response = JsonConvert.DeserializeObject<Rootobject>(jsonData);
for (int i = 0; i < response.album.Length; i++)
{
newSongList.Add(new SongList() { Image = response.album[i].strAlbumThumb, Name = response.album[i].strAlbum });
}
return newSongList;
}
}
Make the variable type of the image to ImageSource in your SongList class and set bitmapimage from the url of your thumbnail image. I tried it works fine.
public sealed partial class MainPage : Page
{
ObservableCollection<SongList> AllSongs;
public MainPage()
{
this.InitializeComponent();
AllSongs = new ObservableCollection<SongList>();
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
AllSongs= new ObservableCollection<SongList>( await GetSongListsAsync("drake"));
SongListView.ItemsSource = AllSongs;
base.OnNavigatedTo(e);
}
private async Task<List<SongList>> GetSongListsAsync(string SingerName)
{
List<SongList> songs = new List<SongList>();
HttpClient client = new HttpClient();
var jsonData = await client.GetStringAsync("https://theaudiodb.com/api/v1/json/1/searchalbum.php?s=" + SingerName);
var response = JsonConvert.DeserializeObject<RootObject>(jsonData);
foreach (var song in response.album.FindAll(g => !string.IsNullOrEmpty(g.strAlbumThumb)))
{
var bytes = await new HttpClient().GetByteArrayAsync(song.strAlbumThumb);
MemoryStream stream = new MemoryStream(bytes.ToArray());
var ImageStream =stream.AsRandomAccessStream();
var bitmapimage = new BitmapImage();
await bitmapimage.SetSourceAsync(ImageStream);
songs.Add(new SongList() { Image = bitmapimage, name = song.strAlbum });
}
return songs;
}
}
public class RootObject
{
public List<Album> album { get; set; }
}
public class Album
{
public string strAlbumThumb { get; set; }
public string strAlbum { get; set; }
}
public class SongList
{
public ImageSource Image { get; set; }
public string name { get; set; }
}
ItemsSource="{x:Bind AllSongs}"
There we go. Are you sure the AllSongs type is ImageSource? From what I see it's a list, not an image.
ImageSource can't be image because of that I think below code will help you to turn your Image to ImageSource.
using (var ms = new MemoryStream())
{
image.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = ms;
bitmapImage.EndInit();
return bitmapImage;
}
You can check this answer link.

How to get and display image as byte array from database on Windows Phone 8.1

I want to get image as byte array from database using local WCF service and display it on a Page using Image control. I cannot make it working.
This is the simplest code just to start… Eventually I want to use binding in XAML.
//I use following code for getting bytes (it’ s working)
private async Task GetPhotoAsync(string code)
{
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(HttpMethod.Get,
$"http://192.168.0.5/Service/TerminalService.svc/GetPhoto?Code={code}"))
{
using (var response = await httpClient.SendAsync(request))
{
if (response.IsSuccessStatusCode)
{
ImageBuffer = (await response.Content.ReadAsByteArrayAsync());
}
else
{
throw new Exception($"Error.{Environment.NewLine}{response}");
}
}
}
}
}
...
public byte[] ImageBuffer
{
get { return _imageBuffer; }
set { SetProperty(ref imageBuffer, value); }
}
public class BindableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null) eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
...
//Method used to convert bytes into BitmapImage and set source of control Image.
public async void SetImageFromByteArray(byte[] data, Image image)
{
using (InMemoryRandomAccessStream raStream = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(raStream))
{
// Write the bytes to the stream
writer.WriteBytes(data);
// Store the bytes to the MemoryStream
await writer.StoreAsync();
// Not necessary, but do it anyway
await writer.FlushAsync();
// Detach from the Memory stream so we don't close it
writer.DetachStream();
}
raStream.Seek(0);
BitmapImage bitMapImage = new BitmapImage();
bitMapImage.SetSource(raStream);
image.Source = bitMapImage;
}
}
When MainPage is loaded I run method GetPhotoAsync().
After a while I set Image.Source by pressing button and run method SetImageFromByteArray().
Nothing is displayed.
I also tried these solutions without success:
with binding properties -
https://marcominerva.wordpress.com/2013/04/15/how-to-convert-a-byte-array-to-image-in-a-windows-store-app/
using converter -
Windows Phone 8 - Load byte[] array into XAML image with Binding
TaskCompletionNotifier -
Async Implementation of IValueConverter
You can try this, it works for me.
First you have to set up property in your ViewModel which you bind the Image control to.
public BitmapImage ImageSource
{
get { return _imageSource; }
set { SetProperty(ref _imageSource, value); }
}
...
public async Task GetPhotoAsync(string twrKod)
{
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(HttpMethod.Get,
$"http://192.168.0.5/Service/TerminalService.svc/GetPhoto?Code={code}"))
{
using (var response = await httpClient.SendAsync(request))
{
if (response.IsSuccessStatusCode)
{
var imageStream = await response.Content.ReadAsStreamAsync();
var memStream = new MemoryStream();
await imageStream.CopyToAsync(memStream);
memStream.Position = 0;
var bitmap = new BitmapImage();
bitmap.SetSource(memStream.AsRandomAccessStream())
ImageSource = bitmap;
}
}
}
}
}
Make sure you have MemoryStream to be return type of WCF Service. For example:
public Stream GetPhoto(string code)
{
byte[] bytes = null;
var myCommand = new SqlCommand())
myCommand.Connection = new SqlConnection(Settings.Default.ConnectionString);
objSql.ObjCommand.CommandText = "dbo.GetPhotoProc";
objSql.ObjCommand.CommandType = CommandType.StoredProcedure;
objSql.ObjCommand.Parameters.Add("#code", SqlDbType.NVarChar).Value = code;
objSql.Reader = objSql.ObjCommand.ExecuteReader();
if (!objSql.Reader.HasRows) return null;
while (objSql.Reader.Read())
{
bytes = (byte[])objSql.Reader.GetValue(0);
}
if (bytes == null) return Stream.Null;
var ms = new MemoryStream(bytes) { Position = 0 };
if (WebOperationContext.Current != null)
WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
return ms;
}
Interface for WCF
[WebGet(UriTemplate = "GetPhoto?Code={code}", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract]
Stream GetPhoto(string code);

Load a image from web URL in WP8

I have a Web image with specified URL, it can be browsed in the browser.
i tried to retrieve it from web url and when program goes to bitmapImage.SetSource(ms); i get a exception "
ex = {System.Exception: The component cannot be found. (Exception from HRESULT: 0x88982F50)
at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
at MS.Internal.XcpImports.BitmapSource_SetSource(BitmapSource bitmapSource, CValue& byteStream)
at System.Wi...
"
i did searched other questions on stackoverflow...but no help on this. any one can help me?
byte array did have data, in the runtime debugging, it returns imageByteArray = {byte[1227]}; my option is that exception occurs when converting byte array to BitmapImage.
in the httpclient wrapper class:
public static async Task<Byte[]> GetWebImageByImageName(string ImageName)
{
//Uri imageServerUril = new Uri(ImageName);
var requestMessage = new HttpRequestMessage(HttpMethod.Get, ImageName);
var responseMessage = await client.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead);
var responseData = await responseMessage.Content.ReadAsByteArrayAsync();
return responseData;
}
in the view model:
private async void ReadArticleList(int pageNumber)
{
string webURL = "http://....."; // the web URL is no problem
try
{
byte[] imageByteArray = await CollectionHttpClient.GetWebImageByImageName(webURL);//
//Convert it to BitmapImage
using (MemoryStream ms = new MemoryStream(imageByteArray))
{
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.CreateOptions = BitmapCreateOptions.DelayCreation;
bitmapImage.SetSource(ms); // the exception got here
item.BitImage = bitmapImage;
}
IsLoading = false;
}
catch(Exception ex)
{
if (ex.HResult == -2146233088 && ex.Message.Equals("Response status code does not indicate success: 404 ()."))
{
MessageBox.Show("The network is not set right. Internet cannot be accessed.");
}
else
{
MessageBox.Show("sorry, no data.");
}
IsLoading = false;
}
}
* for Detail *
BitImage is a instance of BitmapImage;
item.BitImage: item is a instance of Article
image format is JPEG
Article model is in below:
public class Article : INotifyPropertyChanged
{
private long _Id;
public long ID
{
get { return _Id; }
set
{
if (_Id != value)
{
_Id = value;
NotifyPropertyChanged("ID");
}
}
}
private string _subject;
public string Subject
{
get
{
return _subject;
}
set
{
if (_subject != value)
{
_subject = value;
NotifyPropertyChanged("Subject");
}
}
}
private string _words;
public string Words
{
get
{
return _words;
}
set
{
if (_words != value)
{
_words = value;
NotifyPropertyChanged("Words");
}
}
}
private DateTime _publishDate;
public DateTime PublishDate
{
get
{ return _publishDate; }
set
{
if (_publishDate != value)
{
_publishDate = value;
NotifyPropertyChanged("PublishDate");
}
}
}
public List<string> ImagePathList = new List<string>();
public BitmapImage BitImage = new BitmapImage();
private string _firstImage;
public string FirstImage
{
get
{
return _firstImage;
}
set
{
if (_firstImage != value)
{
_firstImage = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
If you just want to display an image from a remote server without saving it, do the following:
imageControl1.Source = new BitmapImage(new Uri("http://delisle.saskatooncatholic.ca/sites/delisle.saskatooncatholic.ca/files/sample-1.jpg", UriKind.Absolute));
If you want to save the image to IsolatedStorage you can do the following:
WebClient webClientImg = new WebClient();
webClientImg.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
webClientImg.OpenReadAsync(new Uri("http://delisle.saskatooncatholic.ca/sites/delisle.saskatooncatholic.ca/files/sample-1.jpg", UriKind.Absolute));
void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
isSpaceAvailable = IsSpaceIsAvailable(e.Result.Length);
if (isSpaceAvailable)
{
SaveToJpeg(e.Result);
}
else
{
MessageBox.Show("You are running low on storage space on your phone. Hence the image will be loaded from the internet and not saved on the phone.", "Warning", MessageBoxButton.OK);
}
}
Function to check if IsolatedStorage space is available or else it will not download the image.
private bool IsSpaceIsAvailable(long spaceReq)
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
long spaceAvail = store.AvailableFreeSpace;
if (spaceReq > spaceAvail)
{
return false;
}
return true;
}
}
If space was available, save as image to IsolatedStorage using the below function:
private void SaveToJpeg(Stream stream)
{
using (IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream isostream = iso.CreateFile("image1.jpg"))
{
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(stream);
WriteableBitmap wb = new WriteableBitmap(bitmap);
// Encode WriteableBitmap object to a JPEG stream.
Extensions.SaveJpeg(wb, isostream, wb.PixelWidth, wb.PixelHeight, 0, 85);
isostream.Close();
LoadImageFromIsolatedStorage(); //Load recently saved image into the image control
}
}
}
Load the image in image control from IsolatedStorage:
private void LoadImageFromIsolatedStorage()
{
byte[] data;
try
{
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream isfs = isf.OpenFile("image1.jpg", FileMode.Open, FileAccess.Read))
{
data = new byte[isfs.Length];
isfs.Read(data, 0, data.Length);
isfs.Close();
}
}
MemoryStream ms = new MemoryStream(data);
BitmapImage bi = new BitmapImage();
bi.SetSource(ms);
imageControl1.Source = bi;
}
catch
{
}
}
Image taken randomly from Google Search. Credits to the image lie to the owner.
Hope this helps. :)
#Mark , you are correct, this works according to what you suggest.
i think the problem is if i used code below, i got the byte array is byte[1227]
var requestMessage = new HttpRequestMessage(HttpMethod.Get, ImageName);
var responseMessage = await client.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead);
var responseData = await responseMessage.Content.ReadAsByteArrayAsync();
return responseData;
and if i use var byteArray = await client.GetByteArrayAsync(ImageName); the byte array size is byte[5996]
i do not know why this happens, but Mark's solution works.
all my code is as below:
in a MVVM pattern
// get image from URL, ImageName is an absolute Url
public static async Task<BitmapImage> GetWebImageByImageName(string ImageName)
{
//Uri imageServerUril = new Uri(ImageName);
var byteArray = await client.GetByteArrayAsync(ImageName);
//Convert byte array to BitmapImage
BitmapImage bitmapImage;
using (MemoryStream ms = new MemoryStream(byteArray))
{
bitmapImage = new BitmapImage();
bitmapImage.SetSource(ms);
}
return bitmapImage;
}
in the ViewModel
public void LoadPage(int pageNumber)
{
if (pageNumber == 1)
{
this.ArticleCollection.Clear();
}
IsLoading = true;
ReadArticleList(pageNumber);
}
private async void ReadArticleList(int pageNumber)
{
try
{
List<Article> articleList = new List<Article>();
articleList = await CollectionHttpClient.GetArticlesByPageAsync(pageNumber);
foreach (var item in articleList)
{
item.BitImage = await CollectionHttpClient.GetWebImageByImageName(item.ImagePathList[0]);
this.ArticleCollection.Add(item);
}
IsLoading = false;
}
catch(Exception ex)
{
if (ex.HResult == -2146233088 && ex.Message.Equals("Response status code does not indicate success: 404 ()."))
{
MessageBox.Show("The network is not set right. Internet cannot be accessed.");
}
else
{
MessageBox.Show("sorry, no data.");
}
IsLoading = false;
}
}
Model is:
public class Article : INotifyPropertyChanged
{
private long _Id;
public long ID
{
get { return _Id; }
set
{
if (_Id != value)
{
_Id = value;
NotifyPropertyChanged("ID");
}
}
}
private string _subject;
public string Subject
{
get
{
return _subject;
}
set
{
if (_subject != value)
{
_subject = value;
NotifyPropertyChanged("Subject");
}
}
}
private string _words;
public string Words
{
get
{
return _words;
}
set
{
if (_words != value)
{
_words = value;
NotifyPropertyChanged("Words");
}
}
}
private DateTime _publishDate;
public DateTime PublishDate
{
get
{ return _publishDate; }
set
{
if (_publishDate != value)
{
_publishDate = value;
NotifyPropertyChanged("PublishDate");
}
}
}
private ObservableCollection<string> _imagePathList = new ObservableCollection<string>();
public ObservableCollection<string> ImagePathList
{
get { return this._imagePathList; }
set
{
if (this._imagePathList != value)
{
this._imagePathList = value;
// I'm going to assume you have the NotifyPropertyChanged
// method defined on the view-model
this.NotifyPropertyChanged();
}
}
}
BitmapImage _image;
public BitmapImage BitImage
{
get
{
return _image;
}
set
{
if (ImagePathList.Any())
{
value = new BitmapImage(new Uri(ImagePathList.FirstOrDefault(), UriKind.RelativeOrAbsolute));
_image = value;
}
}
}
private Uri _firstImage;
public Uri FirstImage
{
get
{
return _firstImage;
}
set
{
if (_firstImage != value)
{
_firstImage = value;
NotifyPropertyChanged("FirstImage");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
First if you have the url you can give url to the binding paramter and it will automatically show the image or if you want to download the image and save it & then display it so here is the code for byte to image & image to byte.
{
BitmapImage image = new BitmapImage();
MemoryStream ms = new MemoryStream();
WriteableBitmap wb = new WriteableBitmap(image);
wb.SaveJpeg(ms, image.PixelWidth, image.PixelHeight, 0, 100);
imageBytes = ms.ToArray();
}
Use this to save image because i am using it my code.

Image from Byte Array not showing

I have an application that takes photos, converts them into byte arrays and saves them locally in the Isolated Storage. It then reads them out and converts them back into an BitmapImage.
However, I can't seem to show the images in a ListBox. I am using the same code I have in another page that works perfectly.
The BitmapImage has a image in it, but that is as much as I know. Whether that image is legitimate or not, I don't know or know how to check.
Any ideas would be greatly appreciated.
SEE CODE BELOW
Convert Image
public byte[] ImageToBytes(BitmapImage img)
{
using (MemoryStream ms = new MemoryStream())
{
WriteableBitmap btmMap = new WriteableBitmap(img.PixelWidth, img.PixelHeight);
// write an image into the stream
Extensions.SaveJpeg(btmMap, ms, img.PixelWidth, img.PixelHeight, 0, 100);
return ms.ToArray();
}
}
public BitmapImage BytesToImage(byte[] bytes)
{
BitmapImage bitmapImage = new BitmapImage();
MemoryStream ms = new MemoryStream(bytes);
bitmapImage.SetSource(ms);
return bitmapImage;
}
Class with image
public class NewItem
{
ObservableCollection<BitmapImage> images = new ObservableCollection<BitmapImage>();
[DataMember]
public ObservableCollection<BitmapImage> Images
{
get { return images; }
set { images = value; }
}
[DataMember]
public string Notes { get; set; }
[DataMember]
public string ItemID { get; set; }
}
Saving to storage
public static void AddOrUpdateUnsavedItems(NewItem _item)
{
var store = IsolatedStorageFile.GetUserStoreForApplication();
List<NewItem> allunsaveditems = new List<NewItem>();
if (store.FileExists("unsaveditem"))
{
allunsaveditems.Add(_item);
allunsaveditems.AddRange(LoadUnsavedItemsFromIsolatedStorage());
store.DeleteFile("unsaveditem");
}
UnsavedRegisters.Clear();
foreach (NewItem ni in allunsaveditems)
{
StoredItem newUnsavedItem = new StoredItem();
newUnsavedItem.ItemID = ni.ItemID;
newUnsavedItem.Notes = ni.Notes;
foreach (BitmapImage bmp in ni.Images)
{
newUnsavedItem.ImageBytes.Add(newUnsavedItem.ImageToBytes(bmp));
}
UnsavedRegisters.Add(newUnsavedItem);
}
using (var stream = new IsolatedStorageFileStream("unsaveditem", FileMode.OpenOrCreate, FileAccess.Write, store))
{
DataContractSerializer dcs = new DataContractSerializer(typeof(List<StoredItem>));
dcs.WriteObject(stream, UnsavedRegisters);
}
}
Loading from storage
public static List<NewItem> LoadUnsavedItemsFromIsolatedStorage()
{
List<NewItem> unsavedItems = new List<NewItem>();
try
{
var store = IsolatedStorageFile.GetUserStoreForApplication();
if (store.FileExists("unsaveditem"))
{
using (var stream = new IsolatedStorageFileStream("unsaveditem", FileMode.OpenOrCreate, FileAccess.Read, store))
{
if (stream.Length > 0)
{
DataContractSerializer dcs = new DataContractSerializer(typeof(List<StoredItem>));
List<StoredItem> storedItems = dcs.ReadObject(stream) as List<StoredItem>;
foreach (StoredItem si in storedItems)
{
NewItem ni = new NewItem();
ni.ItemID = si.ItemID;
ni.Notes = si.Notes;
foreach (byte[] imageBytes in si.ImageBytes)
{
ni.Images.Add(si.BytesToImage(imageBytes));
}
unsavedItems.Add(ni);
}
}
}
}
}
catch (Exception)
{
//MessageBox.Show("and error happened getting the unsaved items");
// handle exception
return null;
}
return unsavedItems;
}
This should not be a problem, I had this working for a BitmapSource, Which I believe BitmapImage inherits from, try the code below in your listbox
<Border Height="200" Width="200">
<Border.Background>
<ImageBrush ImageSource="{Binding ItemImage}" />
</Border.Background>
</Border>
ItemImage is the Property holding your BitmapSource image.
I don't know what has changed, but it started working.

Throws Exception "Operation not permitted on IsolatedStorageFileStream" When read from isloated storage

In my app I have to download all the images from the remote server and display it in a list view .When i tried to extract the images from isolated storage I have got an exception
"Operation not permitted on IsolatedStorageFileStream"
.here is my code
public static object ExtractFromLocalStorage(Uri imageFileUri)
{
byte[] data;
string isolatedStoragePath = GetFileNameInIsolatedStorage(imageFileUri); //Load from local storage
if (null == _storage)
{
_storage = IsolatedStorageFile.GetUserStoreForApplication();
}
BitmapImage bi = new BitmapImage();
//HERE THE EXCEPTION OCCURS
using (IsolatedStorageFileStream sourceFile = _storage.OpenFile(isolatedStoragePath, FileMode.Open, FileAccess.Read))
{
data = new byte[sourceFile.Length];
// Read the entire file and then close it
sourceFile.Read(data, 0, data.Length);
// Create memory stream and bitmap
MemoryStream ms = new MemoryStream(data);
// Set bitmap source to memory stream
bi.SetSource(ms);
sourceFile.Close();
}
return bi;
}
the above function is used to get the bitmap image from isolated storage,and my model class is
public class Details
{
public string id { get; set; }
public string name { get; set; }
public Uri imgurl { get; set; }
[IgnoreDataMember]
public BitmapImage ThumbImage{get;set;}
}
and i am using a singlton class to call the function to get image.
public class SingleTon
{
static SingleTon instance = null;
private SingleTon()
{
}
public static SingleTon Instance()
{
if (instance == null)
{
instance = new SingleTon();
}
return instance;
}
public BitmapImage getImage(Uri uri)
{
lock (this)
{
BitmapImage image = new BitmapImage();
image = (BitmapImage)CacheImageFileConverter.ExtractFromLocalStorage(uri);
return image;
}
}
public void writeImageToIsolatedStorage(Uri imageUri)
{
lock (this)
{
CacheImageFileConverter.DownloadFromWeb(imageUri);
}
}
}
this is the code for set the image to the object
SingleTon singleton = SingleTon.Instance();
List<(Details > datalist = new Details()
foreach (Details items in DataList)
{
items.ThumbImage = singleton.getImage(items.imgurl );
datalist.add(items);
}
please any one help me with a solution.
This exception usually occurs if you haven't closed a previously open Stream to the same file. Check CacheImageFileConverter.DownloadFromWeb and make sure your output Stream is wrapped in a using block.
That exception might also be thrown if the file doesn't exist, but I'm not 100% sure. Maybe through in a call to IsolatedStorageFile.FileExists() before you open it just to be sure.

Categories