Google Windows Phone 8 Listbox Images out of memory exception c# - Part1 | SubramanyamRaju Xamarin & Windows App Dev Tutorials

Monday 27 January 2014

Windows Phone 8 Listbox Images out of memory exception c# - Part1

Introduction

Images are the best attraction for every mobile app.But Users have high expectations when it comes to using applications on their mobile devices. It is important to have good performance and quality in your applications and there are a number of things you can do to deliver great performance.So as s developer it is more quit difficult to overcome out of memory exception,however I’ll list a few that apply to memory, images, data binding and more.and i hope i will definately helpful for who are having same problem.
Source File at :WP8ImageFree

Building the Sample

We need ad namespaces " Microsoft.Phone.Tasks" for camera task and "System.IO.IsolatedStorage,System.Runtime.Serialization" for isolated storage ,and no need for any other external dll's
Description
However  I had taken for the requirements of "Saving Camera captured Images to Isolated Storage" ,"Read the camera captured images from the isolated storage to listbox" and also "How to resize captured images in wp8 c#
Let's start few steps to meet above requirements

1)Saving Camera captured Images to Isolated Storage:

Before going to start this section, we must need to know about "isolated storage",so that in previously i had posted about this one at"http://bsubramanyamraju.blogspot.com/2014/01/how-to-store-listbox-items-into.html"
and now we are going to cature the image from camera like this way,
C#
private void CarImage_tap(object sender, System.Windows.Input.GestureEventArgs e) 
        { 
 
            CameraCaptureTask ccTask = new CameraCaptureTask(); 
            ccTask.Completed += ccTaskCompleted; 
            ccTask.Show(); 
        } 
 
        private void ccTaskCompleted(object sender, PhotoResult pr) 
        { 
            try 
            { 
                byte[] ImageBytes; 
 
                if (pr.ChosenPhoto != null) 
                { 
                    ImageBytes = new byte[(int)pr.ChosenPhoto.Length]; 
                    pr.ChosenPhoto.Read(ImageBytes, 0, ImageBytes.Length); 
                    pr.ChosenPhoto.Seek(0, System.IO.SeekOrigin.Begin); 
                    var bitmapImage = PictureDecoder.DecodeJpeg(pr.ChosenPhoto, 480856); 
                    if (bitmapImage.PixelHeight > bitmapImage.PixelWidth) 
                    { 
                        CarImage.MaxHeight = 450; 
                        CarImage.MaxWidth = 252; 
                    } 
                    else 
                    { 
                        CarImage.MaxHeight = 252; 
                        CarImage.MaxWidth = 450; 
                    } 
                    this.CarImage.Source = bitmapImage; 
                    prkdata.CarImageBytes = ImageBytes; 
 
                     
                } 
 
            } 
            catch 
            { 
            } 
         
        }
after capturing the image ,we need to store imagebytes in isolated storage like this way,

C#
SavedData prkdata = new SavedData(); 
        SavedDataList parkinglistobj = new SavedDataList(); 
        IsolatedStorageFile Settings = IsolatedStorageFile.GetUserStoreForApplication(); 
prkdata.CarImageBytes = ImageBytes; 
parkinglistobj.Add(new SavedData { ID = count + 1, Address = "Image" + count.ToString(), CarImageBytes = prkdata.CarImageBytes }); 
 
            if (Settings.FileExists("ParkignItemList")) 
            { 
                Settings.DeleteFile("ParkignItemList"); 
            } 
            using (IsolatedStorageFileStream fileStream = Settings.OpenFile("ParkignItemList", FileMode.Create)) 
            { 
                DataContractSerializer serializer = new DataContractSerializer(typeof(SavedDataList)); 
                serializer.WriteObject(fileStream, parkinglistobj); 
 
            }

2)Resizing Camera captured Images in windows phone 8 c#:
In above code i had resize captured image to max height 450 and width to 252,How ever to resize image the without loss image quality we need to adjust width and height with equal proprotions,here i had taken with help of paint applicaiton in windows 8 os to calculate apect pixel ratio's image to fixed height of 450. 
C#
var bitmapImage = PictureDecoder.DecodeJpeg(pr.ChosenPhoto, 480856); 
                    if (bitmapImage.PixelHeight > bitmapImage.PixelWidth) 
                    { 
                        CarImage.MaxHeight = 450; 
                        CarImage.MaxWidth = 252; 
                    } 
                    else 
                    { 
                        CarImage.MaxHeight = 252; 
                        CarImage.MaxWidth = 450; 
                    }
3)Reading Camera captured Images from isolatedstorage to listbox:
In this step we need to helper classes 
3.1)For storing capture image bytes i.e(SavedData.cs):

C#
public class SavedData 
    { 
        public int ID { getset; } 
        public String Address { getset; } 
        public byte[] CarImageBytes { getset; } 
    } 
    public class SavedDataList : List<SavedData> 
    { 
    }
3.2)IValueConverter class for converting imagebytes to bitmapimage:
C#

public class BytesToImageConverter : IValueConverter 
    { 
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
        { 
            if (value != null && value is byte[]) 
            { 
                byte[] bytes = value as byte[]; 
                MemoryStream stream = new MemoryStream(bytes); 
                BitmapImage image = new BitmapImage(); 
                image.DecodePixelType = DecodePixelType.Logical; 
                image.CreateOptions = BitmapCreateOptions.BackgroundCreation; 
                image.CreateOptions = BitmapCreateOptions.DelayCreation; 
                var bitmapImage = PictureDecoder.DecodeJpeg(stream, 480856); 
                if (bitmapImage.PixelHeight > bitmapImage.PixelWidth) 
                { 
                    image.DecodePixelWidth = 56; 
                    image.DecodePixelHeight = 100; 
                } 
                else 
                { 
                    image.DecodePixelWidth = 100; 
                    image.DecodePixelHeight = 56; 
                } 
                image.SetSource(stream); 
                return image; 
            } 
 
            return null; 
 
        } 
 
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
        { 
            throw new NotImplementedException(); 
        }

Notes:
1)in ivalueconverter class it is most important thing, i had mention is BitmapImage properties are"DecodePixelHeight,DecodePixelWidth,CreateOptions" to know more about this ones http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.media.imaging.bitmapimage(v=vs.105).aspx

And is is very important to set 
bitimage.DecodePixelWidth = 56; 
bitimage.DecodePixelHeight = 100;

For additional performance benefit, if you are planning to only have the image displayed as a 100 x 100 frame across all devices, you can encode your images to that size. In general, the resolution of the image should be no greater than the frame it will be displayed in.  If your image is larger, resize it, especially if the frame is going to be drawn multiple times.

C#
BitmapImage image = new BitmapImage(); 
                image.DecodePixelType = DecodePixelType.Logical; 
                image.CreateOptions = BitmapCreateOptions.BackgroundCreation; 
                image.CreateOptions = BitmapCreateOptions.DelayCreation; 
               image.DecodePixelWidth = 56; 
                    image.DecodePixelHeight = 100;

 2)bitimage.DecodePixelWidth and bitimage.DecodePixelHeight are only supported in windowsphone 8 os


3.2)Binding listbox with bitmapimage from captured imagebytes :

We can bind listbox items with imagebytes in xaml using above ivalueconverter class i.e "BytesToImageConverter.cs" .so that we need to reference above ivalueconverter class
like this way 
XAML
xmlns:n="clr-namespace:ImageFreewp8" 
<phone:PhoneApplicationPage.Resources        <n:BytesToImageConverter x:Name="ByteToImage" /> 
    </phone:PhoneApplicationPage.Resources>

 and bind listbox image with ivaluecoverter like this way,

XAML
 <Image Source="{Binding CarImageBytes, Converter={StaticResource ByteToImage}}"  Stretch="None" VerticalAlignment="Center"   HorizontalAlignment="Center"  />

finally assign the list of captured isolated storage images to listbox like this way,

C#
 if (Settings.FileExists("ParkignItemList")) 
                { 
                    using (IsolatedStorageFileStream fileStream = Settings.OpenFile("ParkignItemList", FileMode.Open)) 
                    { 
                        DataContractSerializer serializer = new DataContractSerializer(typeof(SavedDataList)); 
                        parkinglistobj = (SavedDataList)serializer.ReadObject(fileStream); 
 
                    } 
                } 
                
               
                ParkListBox.ItemsSource = parkinglistobj.OrderByDescending(i => i.ID).ToList();
 4)ScreenShots :

Note: screens are taken from the emulator
   

3 comments:

  1. Hi, Subbu. Awesome blog you have written, i need your help in my case, in my case, i need to load more than 1000 thumbnails of a book from the isolatedStorage into my ListBox as well as i need to show the status as red button for new thumbnails, i have written a code and its executing successfully, it gives exception when i navigate thumbnail page twice, it generate "out of memory exception ". I tried a lot but failed to solve, Can you please help me how can i reduce the Memory consumption on again and again visit that thumbnail page. ?

    ReplyDelete
  2. i really re commend this blog to programmers ... im now a real programmer, making several dollars , kidnapped programming techniques from this blog , thanks sir for your good job

    ReplyDelete
  3. Hi Subbu sir, Tq for your Samples their were awesome. I am new developer I need a small help from you regarding same sample.(In my app same functionality.) when the user taps on particular item it will navigate to new page(There using another list Box I displayed only that Item using ID). My problem is when the user see the full details in new page he can delete that item. How can I do this. I tried many ways:

    ParkListBox.SelectedItem = parkinglistobj.Select(i => i.ID == index);

    //SavedData item = ParkListBox.DataContext as SavedData;
    SavedData item = parkinglistobj.Select(i => i.ID == index) as SavedData;

    parkinglistobj.Remove(item);
    MessageBox.Show("Deleted Successfully");

    But it was not deleting from the list. Please help this.

    2nd problem is When the user taps on the image he can save/share that image to phone/Others. How can I do this?

    Tq in advance... :) Have a nice day sir.

    ReplyDelete

Search Engine Submission - AddMe