System.OutOfMemory BitmapImage WP8 - windows-phone-8

I got a OutOfmemory error when i create a list of bitmapimage...
What am i supposed to do...?
Thanks for your help ;)
Here is my code :
foreach (var bytearray in imageDataBlocksPresta)
{
if (bytearray != null)
{
MemoryStream ms;
using (ms = new MemoryStream(bytearray, 0, bytearray.Length))
{
BitmapImage photo = new BitmapImage();
photo.DecodePixelHeight = 800;
photo.DecodePixelWidth = 624;
photo.SetSource(ms);//ERROR
listphotoPresta.Add(photo);
}
}
else//si photo null
{
BitmapImage photo = new BitmapImage();
photo.DecodePixelHeight = 800;
photo.DecodePixelWidth = 624;
photo.UriSource = new Uri("/Images/NoImageIcon.jpg", UriKind.RelativeOrAbsolute);
listphotoPresta.Add(photo);
}

Try setting photo to null and calling GC.Collect() once you've added it. Like this:
listphotoPresta.Add(photo);
photo = null;
GC.Collect();

Don't create NoImageIcon all the time. Use only one reference
Don't try to store all images in memory. It's a mobile.
Limit your app for devices with at least 512MB RAM
Store lower resuolution pictures. 800*600 is full screen on many devices
Load images on demand
Call GC right after you release an image

Related

windows phone 8.1 dispaly PreviewFrame and calculate mean value of red pixels for every frame

Currently I'm using Lumia.Imaging to get preview frame and display it.
I create new method "GetPreview()" to go though pixels, find red pixel and than I would like to calculate mean value of red pixels for every frame.
My problem is that when I'm going through pixel there are lags in app :(
What is the proper solution to calculate mean of red pixels for every frame without performance loss?
Additional how to turn on Flash light when preview starts ?
private async Task startCameraPreview()
{
// Create a camera preview image source (from the Lumia Imaging SDK)
_cameraPreviewImageSource = new CameraPreviewImageSource();
// Checking id of back camera
DeviceInformationCollection devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(Windows.Devices.Enumeration.DeviceClass.VideoCapture);
String backCameraId = devices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back).Id;
await _cameraPreviewImageSource.InitializeAsync(backCameraId); // use the back camera
var previewProperties = await _cameraPreviewImageSource.StartPreviewAsync();
fps = previewProperties.FrameRate.Numerator/previewProperties.FrameRate.Denominator;
_cameraPreviewImageSource.PreviewFrameAvailable += drawPreview; // call the drawPreview method every time a new frame is available
// Create a preview bitmap with the correct aspect ratio using the properties object returned when the preview started.
var width = 640.0;
var height = (width / previewProperties.Width) * previewProperties.Height;
var bitmap = new WriteableBitmap((int)width, (int)height);
_writeableBitmap = bitmap;
// Create a BitmapRenderer to turn the preview Image Source into a bitmap we hold in the PreviewBitmap object
_effect = new FilterEffect(_cameraPreviewImageSource);
_effect.Filters = new IFilter[0]; // null filter for now
_writeableBitmapRenderer = new WriteableBitmapRenderer(_effect, _writeableBitmap);
}
private async void drawPreview(IImageSize args)
{
// Prevent multiple rendering attempts at once
if (_isRendering == false)
{
_isRendering = true;
await _writeableBitmapRenderer.RenderAsync(); // Render the image (with no filter)
// Draw the image onto the previewImage XAML element
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.High,
() =>
{
getPreview();
previewImage.Source = _writeableBitmap; // previewImage is an image element in MainPage.xaml
_writeableBitmap.Invalidate(); // force the PreviewBitmap to redraw
});
_isRendering = false;
}
}
private void getPreview()
{
var pixelBuffer = _writeableBitmap.PixelBuffer;
for (uint i = 0; i + 4 < pixelBuffer.Length; i += 4)
{
var red = pixelBuffer.GetByte(i + 2);
}
}
Instead of inspecting all pixels after the Lumia Imaging SDK has processed the image, but before you invalidate the bitmap you could:
Invalidate the writeable bitmap imidiatelly then do your analysis step in a seperate async Task. That means that the content will be displayed right away, and your analysis will be done seperatelly. Some pseudocode based on your sample would be:
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.High, () => {
var analysisTask = Task.Run(() => getPreview());
previewImage.Source = _writeableBitmap; // previewImage is an image element in MainPage.xaml
_writeableBitmap.Invalidate(); // force the PreviewBitmap to redraw
await analysisTask;
});
This way the task of analysing the image doesn't block the update on the screen. Of course this option might not be viable if you need the result of the analysis in the rendering chain itself.
Create a custom filter for the analysis, this way you will be able to take advantage of the optimized Lumia Imaging SDK processing.
To get started on writing custom filters look at the documentation.

WriteableBitmapRenderer.RenderAsync() ArgumentException "Value does not fall within the expected range"

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."

Load a PNG from isolated storage on Windows Phone

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();
}

Image not getting replaced in IsolatedStorage in Windows Phone 8

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 :)

MemoryStream used to save image data in CameraCaptureSequence is 0 even though image data is present in the CameraCaptureSequence

I'm using the PhotoCaptureDevice class and I can capture the camera frame, but when I am getting an error while copying the image data in the CameraCaptureFrame.CaptureSequence of the CameraCaptureSequence into a MemoryStream and then save it in the Camera Roll. This is the code snippet of what I'm trying to do.
PhotoCaptureDevice cam;
cam = await PhotoCaptureDevice.OpenAsync(<front/rear depending on user input>,<resolution depends on user input>);
CameraCaptureSequence seq;
seq = cam.CreateCaptureSequence(1);
cam.SetProperty(KnownCameraGeneralProperties.PlayShutterSoundOnCapture, true);
MemoryStream captureStream1 = new MemoryStream();
seq.Frames[0].CaptureStream = captureStream1.AsOutputStream();//This stream is for saving the image data to camera roll
await cam.PrepareCaptureSequenceAsync(seq);
await seq.StartCaptureAsync();
bool a = seq.Frames[0].CaptureStream.Equals(0);//This value is false during debugging
if(capturestream1.Length>0)//This condition evaluates to false
{
MediaLibrary library = new MediaLibrary();
Picture picture1 = library.SavePictureToCameraRoll("image1", captureStream1);
}
else
{
//Logic to handle condition
}
As I've added in the comments, the variable bool a evaluates to false which I checked by debugging the code. But for some reason the capturestream1.Length property is 0.
Here's a code snippet on how to capture a sequence with a single image and saving that image to the MediaLibrary. Obviously this is a bit of a trivial example for this API since sequence are really good for capturing multiple images and meshing them up together with post-processing.
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
using (MemoryStream stream = new MemoryStream())
using (var camera = await PhotoCaptureDevice.OpenAsync(CameraSensorLocation.Back,
PhotoCaptureDevice.GetAvailableCaptureResolutions(CameraSensorLocation.Back).First()))
{
var sequence = camera.CreateCaptureSequence(1);
sequence.Frames[0].CaptureStream = stream.AsOutputStream();
camera.PrepareCaptureSequenceAsync(sequence);
await sequence.StartCaptureAsync();
stream.Seek(0, SeekOrigin.Begin);
using (var library = new MediaLibrary())
{
library.SavePictureToCameraRoll("currentImage.jpg", stream);
}
}
}
When you run this code snippet you can see the image stored on the device:
You can find a full working sample as part of Nokia's Camera Explorer app that demos end-to-end usecases for the WP8 camera APIs: http://projects.developer.nokia.com/cameraexplorer