System.OutOfMemoryException while reading and binding image from isolated storage - windows-phone-7

This is the code I am using for binding image in XAML
<Border toolkit:TiltEffect.IsTiltEnabled="true" Height="350" Width="400" Grid.ColumnSpan="3">
<Grid Height="350" Width="400" Margin="70,0,70,0" x:Name="Container1">
<Grid.Background>
<ImageBrush ImageSource="{Binding ImageCollection[0]}" Stretch="Uniform" AlignmentX="Left" AlignmentY="Center"/>
</Grid.Background>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<i:InvokeCommandAction Command="{Binding ImageTapCommand}" CommandParameter="CONTAINER0"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
</Border>
Likewise I am using 4 border for displaying my recent images.
In my ViewModel I am using the below method for reading image from isolated storage.
public Stream GetFileStream(string filename, ImageLocation location)
{
try
{
lock (SyncLock)
{
if (location == ImageLocation.RecentImage)
{
filename = Constants.IsoRecentImage + #"\" + filename;
}
using (var iSf = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!iSf.FileExists(filename)) return null;
var fs = iSf.OpenFile(filename, FileMode.Open, FileAccess.Read);
return fs;
}
}
}
catch (Exception ex)
{
return null;
}
}
And after getting the stream I will use this below written method four building the WritableBitmap for UI binding
private WriteableBitmap BuildImage(Stream imageStream)
{
using (imageStream)
{
var image = new BitmapImage();
image.SetSource(imageStream);
return new WriteableBitmap(image);
}
}
In this case my issue is after navigating to and from my page for two - three times. The app crashes on BuildImage() method where I am using " image.SetSource(imageStream);" method. I tried many alternatives but failed. The exception I am getting is "System.OutOfMemoryException "
I tried Image control instead of Image brush.
I tried Bitmap instead of WritableBitmap etc. but the result is same.
The app crashing rate will reduce if I use small images. But the crash rate is high with the images taken through camera.
I am trying for a solution to this issue for last one week, But didn't find any alternative to fix the issue.
I found a link that talks about similar issue But didn't get many to solve the issue

Try this,
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
bitmapImage.CreateOptions = BitmapCreateOptions.None;
var bmp = new WriteableBitmap((BitmapSource) bitmapImage);
bitmapImage.UriSource = (Uri) null;
return bmp;

Silverlight caches images by default to improve performance. You should call
image.UriSource = null after using the BitmapImage to dispose of the resources.

Are you reseting/disposing the IsolatedStorageFileStream and the IsolatedStorageFile after you use them?

Have you tried forcing the garbage collector to run to see if that makes any difference.
GC.Collect();
This is not intended as a solution - you should never have to call GC.Collect, but it might help determine whether your problem is a memory leak or just a delay in the memory being reclaimed.

Related

Image From Music Library Not Showing in UWP app

I'm new to UWP development & I'm just showing image in my app from the Music Library.
Infact, I have added Music Library in the app's "Capabilities" & I can confirm that I have access to Music Library as I can read & write files in it.
But when I try to load a image in XAML, it just does not shows...
<Image Height="200" Width="200" Source="C:/Users/Alex Mercer/Music/Album/albumArt.png" />
Please help me understand & solve the problem.
😃 Thanks a lot!
Although we enable the corresponding capabilities, accessing files through paths is still strictly restricted in UWP.
In fact, it is not a good idea to write the full path in XAML, because you cannot guarantee that the path must exist on the device where the application is installed.
To display the pictures in the music library, you can do this:
xaml
<Image Height="200" Width="200" x:Name="AlbumImage" Loaded="AlbumImage_Loaded"/>
xaml.cs
private async void AlbumImage_Loaded(object sender, RoutedEventArgs e)
{
try
{
var albumFolder = await KnownFolders.MusicLibrary.GetFolderAsync("Album");
var albumPic = await albumFolder.GetFileAsync("albumArt.png");
var bitmap = new BitmapImage();
using (var stream = await albumPic.OpenAsync(FileAccessMode.Read))
{
await bitmap.SetSourceAsync(stream);
}
AlbumImage.Source = bitmap;
}
catch (FileNotFoundException)
{
// File or Folder not found
}
catch (Exception)
{
throw;
}
}

The converted PDF image looks so blurry in UWP

I want to convert a pdf file to an image UI control in UWP using c#, xaml.
I've read another way to use the Flip Viewer, but I need each image file of the converted PDF file.
so I modified a bit of the existing sample To open a pdf file.
And my problem is that the quality of the converted image file is extremely bad.
I can not even see the letters.
but this quality problem is same on other pdf sample.
Take a look at my code.
private PdfDocument pdfDocument;
private async void LoadDocument()
{
pdfDocument = null;
//Output means my image UI control (pdf image will be added)
Output.Source = null;
//PageNumberBox shows current page
PageNumberBox.Text = "1";
var picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".pdf");
StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
try
{
pdfDocument = await PdfDocument.LoadFromFileAsync(file);
}
catch (Exception ex)
{
}
if (pdfDocument != null)
{ // I use this text to move page.
PageCountText.Text = pdfDocument.PageCount.ToString();
}
}
uint pageNumber;
if (!uint.TryParse(PageNumberBox.Text, out pageNumber) || (pageNumber < 1) || (pageNumber > pdfDocument.PageCount))
{
return;
}
Output.Source = null;
// Convert from 1-based page number to 0-based page index.
uint pageIndex = pageNumber-1 ;
using (PdfPage page = pdfDocument.GetPage(pageIndex))
{
var stream = new InMemoryRandomAccessStream();
await page.RenderToStreamAsync(stream);
BitmapImage src = new BitmapImage();
Output.Source = src;
await src.SetSourceAsync(stream);
}
}
And this is my xaml code.
<Grid>
<ScrollViewer >
<TextBlock Name="ViewPageLabel"VerticalAlignment="center">Now page</TextBlock>
<TextBox x:Name="PageNumberBox" InputScope="Number" Width="30" Text="1" TextAlignment="Right" Margin="5,0,5,0"
AutomationProperties.LabeledBy="{Binding ElementName=ViewPageLabel}"/>
<TextBlock VerticalAlignment="Center">of <Run x:Name="PageCountText"/>.</TextBlock>
</ScrollViewer>
</Grid>
Is there any suggestions?
Please help me.
Thanks for reading this.
Ran into this issue recently, didn't see any definitive answer here, so here it goes:
JosephA is on the right track, but PdfPageRenderOptions does not have anything about image fidelity/quality or anything like that like I had hoped. However, it does allow you to specify image dimensions. All you have to do is scale up the dimensions.
I suspect what's going on is that the PDF has a scale that it would "like" to use, which is smaller than the image you want to draw. Without specifying dimensions, it's drawing the "small" image and then it's getting scaled up, causing the blurriness.
Instead, if you tell it to draw the image at a higher resolution explicitly, it will do PDF magic to make those lines crisper, and the resulting raster image won't have to scale/blur.
PdfPage page = _document.GetPage(pageIndex);
await page.RenderToStreamAsync(stream, new PdfPageRenderOptions {
DestinationWidth = (uint)page.Dimensions.MediaBox.Width * s,
DestinationHeight = (uint)page.Dimensions.MediaBox.Height * s
});
Something like this helps, where "s" is the scale factor to achieve the dimensions you need.
PdfPage.Dimensions has a number of different properties other than just "MediaBox" that you may want to explore as well depending on your use case.
It sounds like you are encountering the common problem where you need to dynamically adjust the resolution the PDF page is rendered at to an image.
I am not familiar with the that PDF library however it appears you need to use the RenderToStreamAsync() overload that takes a PdfPageRenderOptions parameter to accomplish this.

How to show image files from a directory in a flipview?

I found many samples of displaying images from a resource in a Windows Store app and got it to display images within a sample, but I would require the flipview to show images in a directory, or at least to show image file names I provide by code. With everything I tried so far the flipview remains empty. I maybe missing something obvious, this is the relevant part of the XAML:
<FlipView x:Name="flipView1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="809,350,9,7" Width="548" Height="411" >
<FlipView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path=Image }" Stretch="Uniform"/>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
this works, but it requires me to add the images a resource first....
ImageBrush brush1 = new ImageBrush();
brush1.ImageSource = new BitmapImage(new Uri("ms-appx:///Assets/P1000171.jpg"));
FlipViewItem flipvw1 = new FlipViewItem();
flipvw1.Background = brush1;
flipView1.Items.Add(flipvw1);
but (for example) this doesn't:
string name = String.Format(#"c:\temp\P1000171.JPG");
Uri uri = new Uri(name);
BitmapImage img = new BitmapImage(uri);
flipView1.Items.Add(img);
What do I miss?
In the meantime I've found the answer myself which I now add for future readers. The above example won't work because a Windows 8 app isn't allowed to access most of the PC's directories without the user having selected one using a FolderPicker. The program can re-use that directory later with:
StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", folder);
I've changed the above XAML here:
<Image Source="{Binding}" Stretch="UniformToFill"/>
The Task below will show all .JPG files in the Pictures library in a Flipview, if, in the Package.appxmanifest, Capabilities, "Pictures library" has been checked:
public async Task flipviewload()
{
IReadOnlyList<StorageFile> fileList = await picturesFolder.GetFilesAsync();
var images = new List<BitmapImage>();
if (fileList != null)
{
foreach (StorageFile file in fileList)
{
string cExt = file.FileType;
if (cExt.ToUpper()==".JPG")
{
Windows.Storage.Streams.IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
using (Windows.Storage.Streams.IRandomAccessStream filestream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
images.Add(bitmapImage);
}
}
}
}
flpView.ItemsSource = images;
}

ListBox with multiple captured images windows phone

Does anyone know how to make a listbox with multiple images. I want to be able to capture an image and then display on the screen, then capture another and display after the first one and so on. It is basically images gallery page that I want to create. I would like to store them somewhere on the phone, so they can be retrieved when the application runs again.
So it should be something like in the picture: http://blog.xamarin.com/wp-content/uploads/2012/02/wp2.png
Thank you in advance, I have been doing researches about it but can't find anything.
Well, that is fairly easy. You use a ListBox set the ItemsPanel to a WrapPanel, and either bind ItemsSource to a ObservableCollection (or List/Array, but ObservableCollection is better suited for Bindings).
There are multible ways to do it
Lets take the easiest approach. In xaml you define your ListBox:
<ListBox x:Name="listbox">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="5"
Background="{StaticResource PhoneChromeBrush}"
Height="180"
Width="180">
<Image Source="{Binding}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In your code behind, you can load the images with something like this:
ObservableCollection<BitmapImage> images = new ObservableCollection<BitmapImage>();
List<String> bitmapuris = ....
using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
foreach(var bitmapuri in bitmapuris)
{
System.Windows.Media.Imaging.BitmapImage bitmap = new System.Windows.Media.Imaging.BitmapImage();
if (isoStore.FileExists(bitmapuri))
{
using (IsolatedStorageFileStream stream = isoStore.OpenFile(bitmapuri, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
bitmap.CreateOptions = System.Windows.Media.Imaging.BitmapCreateOptions.BackgroundCreation;
bitmap.SetSource(stream);
}
}
images.Add(bitmap);
}
}
listbox.ItemsSource = images;
With bitmapuris being a List with all of your saved images urls.
Thats basicly what I'm using in some of my apps (though I use ViewModels and Bindings and don't set ItemsSource manually)
Hope this helps
edit:
On how to capture and save images you can read this article:
http://www.c-sharpcorner.com/UploadFile/mahakgupta/capture-save-and-edit-image-in-windows-phone-7/
I would save the Images in a specific folder i.e. "/Images/". That way you can load all images you previously captured on you app start with the code I posted above with List<String> bitmapuris set with this method:
List<String> getFiles(String folderpath)
{
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
return storage.GetFileNames(folderpath).ToList();
}
like this List<String> bitmapuris = getFiles("/Images/*");
and when you captured an image you can simple add your image to your ListBox this way:
System.Windows.Media.Imaging.BitmapImage bitmap = new System.Windows.Media.Imaging.BitmapImage();
bitmap.CreateOptions = System.Windows.Media.Imaging.BitmapCreateOptions.BackgroundCreation;
bitmap.SetSource(myimagestream);
images.Add(bitmap);
providing images is the ObservableCollection<BitmapImage> you set as an ItemsSource to your ListBox.
This is now almost your fully working app, when compined with the link from above.

pass data from viewmodel to code behind windows phone

I was trying to use the MVVM pattern on my first (very simple) WP7 app but I got seriously stuck and now I am just trying to get it working without caring about MVVM.
I have a MainViewModel for my MainPage, which works fine. I have a button that passes some data and navigates to a "details page." I had setup a navigation service to navigate to the details page and pass parameters, which works fine. I just couldn't get the databinding to the view working. Since it is a simple app, I decided I would pass the data from the DetailsPageVieModel.cs to the DetailsPage.xaml.cs code behind and do the work there. Here is what that veiw model portion looks like.
public override void Initialize(IDictionary<string, string> parameters)
{
DetailsPage dp = new DetailsPage();
//DetailsPage dp = Application.Current.RootVisual as DetailsPage;
base.Initialize(parameters);
parameters.TryGetValue("url", out vidUrl);
dp.LoadVideoData(vidUrl);
}
In my DetailsPage.xaml.cs I have the following:
public void LoadVideoData(string url)
{
HtmlWeb doc = new HtmlWeb();
doc.LoadAsync("http://mydomain.com/video.php?url=" + url);
doc.LoadCompleted += doc_LoadCompleted;
}
private void doc_LoadCompleted(object sender, HtmlDocumentLoadCompleted e)
{
this.vidTitle.Text = e.Document.GetElementbyId("title").InnerText;
vidId = e.Document.GetElementbyId("youtubeId").InnerText;
this.vidUrl.Source = new Uri("http://mydomain.com/video.php?url=" + vidUrl, UriKind.Absolute);
BitmapImage bi = new BitmapImage();
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile("temp.jpg", FileMode.Open, FileAccess.Read))
{
bi.SetSource(fileStream);
this.vidImg.Height = bi.PixelHeight;
this.vidImg.Width = bi.PixelWidth;
}
}
this.vidImg.Source = bi;
}
And here is the relevant DetailsPage.xaml code
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel>
<TextBlock x:Name="vidTitle" Canvas.ZIndex="99" />
<TextBlock Canvas.ZIndex="99" Text="Tap on the image to view the video." FontSize="14" Margin="0"/>
<Button Margin="0 -50" Padding="0" BorderThickness="0">
<Image x:Name="vidImg" Height="225" />
</Button>
<StackPanel Canvas.ZIndex="99" Height="516">
<phone:WebBrowser x:Name="vidUrl" IsScriptEnabled="True" Height="516" Margin="0"/>
</StackPanel>
</StackPanel>
</Grid>
I am guessing the problem lies with the following
DetailsPage dp = new DetailsPage();
//DetailsPage dp = Application.Current.RootVisual as DetailsPage;
Neither of these lines of code works. The first line executes properly but the page doesn't get updated with the proper data. And the second line gives me a runtime error message when it gets to the dp.LoadVideoData(vidUrl); line.
This is my first Windows Phone app and I would appreciate any help anyone can provide.
Kamal
After digging around some more, I found the following solution.
DetailsPage currentPage = (App.Current as App).RootFrame.Content as DetailsPage;
I put this code in DetailsPageViewModel.cs. But for other newbies like me, there is nothing special about the name of the file. It could have very well been Monkey.cs. The above code just gives you access to the code behind of the current page being displayed.

Resources