You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@cordova.apache.org by "Jesse MacFadyen (JIRA)" <ji...@apache.org> on 2013/11/09 02:43:17 UTC

[jira] [Updated] (CB-5102) Memory leaks when resizing the photo on WP8

     [ https://issues.apache.org/jira/browse/CB-5102?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Jesse MacFadyen updated CB-5102:
--------------------------------

    Fix Version/s: 3.3.0

> 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: Plugin Camera, WP7, WP8
>    Affects Versions: 3.1.0
>         Environment: Nokia Lumia 925 running WP8
>            Reporter: Jonathan Naguin
>            Assignee: Jesse MacFadyen
>            Priority: Critical
>              Labels: camera, memory-leak, wp7, wp8
>             Fix For: 3.3.0
>
>
> 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)