You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@cordova.apache.org by "Jonathan Naguin (JIRA)" <ji...@apache.org> on 2013/10/16 14:13:46 UTC
[jira] [Created] (CB-5102) Memory leaks when resizing the photo on
WP8
Jonathan Naguin created CB-5102:
-----------------------------------
Summary: Memory leaks when resizing the photo on WP8
Key: CB-5102
URL: https://issues.apache.org/jira/browse/CB-5102
Project: Apache Cordova
Issue Type: Bug
Components: WP7, WP8
Affects Versions: 3.1.0
Environment: Nokia Lumia 925 running WP8
Reporter: Jonathan Naguin
Assignee: Jesse MacFadyen
Priority: Critical
I was testing the Camera on WP8 and I found memory problems using this code several times (5 to 10):
{code}
var _options = {
quality: 50,
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.CAMERA,
allowEdit: false,
encodingType: Camera.EncodingType.PNG,
saveToPhotoAlbum: false,
correctOrientation: true,
targetWidth: 1024,
targetHeight: 768
};
navigator.camera.getPicture(cameraSuccess, cameraError, _options);
{code}
I realized the problem is on "GetImageContent" and "ResizePhoto". It contains several problems disposing Streams and Bitmaps.
This is my re-implementation, which I tested and it works fine so far:
{code}
/// <summary>
/// Returns image content in a form of base64 string
/// </summary>
/// <param name="stream">Image stream</param>
/// <returns>Base64 representation of the image</returns>
private string GetImageContent(Stream stream)
{
byte[] imageContent = null;
try
{
//use photo's actual width & height if user doesn't provide width & height
if (cameraOptions.TargetWidth < 0 && cameraOptions.TargetHeight < 0)
{
int streamLength = (int)stream.Length;
imageContent = new byte[streamLength + 1];
stream.Read(imageContent, 0, streamLength);
}
else
{
// resize photo
imageContent = ResizePhoto(stream);
}
}
finally
{
stream.Dispose();
}
return Convert.ToBase64String(imageContent);
}
/// <summary>
/// Resize image
/// </summary>
/// <param name="stream">Image stream</param>
/// <returns>resized image</returns>
private byte[] ResizePhoto(Stream stream)
{
//output
byte[] resizedFile;
BitmapImage objBitmap = new BitmapImage();
objBitmap.SetSource(stream);
objBitmap.CreateOptions = BitmapCreateOptions.None;
WriteableBitmap objWB = new WriteableBitmap(objBitmap);
objBitmap.UriSource = null;
//Keep proportionally
double ratio = Math.Min((double)cameraOptions.TargetWidth / objWB.PixelWidth, (double)cameraOptions.TargetHeight / objWB.PixelHeight);
int width = Convert.ToInt32( ratio * objWB.PixelWidth );
int height = Convert.ToInt32( ratio * objWB.PixelHeight );
//Hold the result stream
using (MemoryStream objBitmapStreamResized = new MemoryStream())
{
try
{
// resize the photo with user defined TargetWidth & TargetHeight
Extensions.SaveJpeg(objWB, objBitmapStreamResized, width, height, 0, cameraOptions.Quality);
}
finally
{
//Dispose bitmaps immediately, they are memory expensive
DisposeImage(objBitmap);
DisposeImage(objWB);
GC.Collect();
}
//Convert the resized stream to a byte array.
int streamLength = (int)objBitmapStreamResized.Length;
resizedFile = new Byte[streamLength]; //-1
objBitmapStreamResized.Position = 0;
//for some reason we have to set Position to zero, but we don't have to earlier when we get the bytes from the chosen photo...
objBitmapStreamResized.Read(resizedFile, 0, streamLength);
}
return resizedFile;
}
/// <summary>
/// Util: Dispose a bitmap resource
/// </summary>
/// <param name="image">BitmapSource subclass to dispose</param>
private void DisposeImage(BitmapSource image)
{
if (image != null)
{
try
{
using (var ms = new MemoryStream(new byte[] { 0x0 }))
{
image.SetSource(ms);
}
}
catch (Exception)
{
}
}
}
{code}
NOTE:
- It contains a solution for: https://issues.apache.org/jira/browse/CB-2737
--
This message was sent by Atlassian JIRA
(v6.1#6144)