You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by pu...@apache.org on 2014/04/08 20:52:18 UTC

[1/3] git commit: Fix camera issues, cropping, memory leaks CB-4027, CB-5102, CB-2737, CB-2387

Repository: cordova-plugin-camera
Updated Branches:
  refs/heads/dev 91d6e10b2 -> ae2acd9ab


Fix camera issues, cropping, memory leaks CB-4027, CB-5102, CB-2737, CB-2387


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/commit/e7a3d70f
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/tree/e7a3d70f
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/diff/e7a3d70f

Branch: refs/heads/dev
Commit: e7a3d70fe969f75b795ca216dd9173f8df1635ee
Parents: 91d6e10
Author: Jesse MacFadyen <pu...@gmail.com>
Authored: Mon Apr 7 15:00:12 2014 -0700
Committer: Jesse MacFadyen <pu...@gmail.com>
Committed: Mon Apr 7 15:00:12 2014 -0700

----------------------------------------------------------------------
 src/wp/Camera.cs | 228 ++++++++++++++++++++++++++++++++------------------
 1 file changed, 145 insertions(+), 83 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/e7a3d70f/src/wp/Camera.cs
----------------------------------------------------------------------
diff --git a/src/wp/Camera.cs b/src/wp/Camera.cs
index 5ff8045..53ae61a 100644
--- a/src/wp/Camera.cs
+++ b/src/wp/Camera.cs
@@ -113,8 +113,6 @@ namespace WPCordovaClassLib.Cordova.Commands
             [DataMember(IsRequired = false, Name = "correctOrientation")]
             public bool CorrectOrientation { get; set; }
 
-            
-
             /// <summary>
             /// Ignored
             /// </summary>
@@ -177,16 +175,6 @@ namespace WPCordovaClassLib.Cordova.Commands
         }
 
         /// <summary>
-        /// Used to open photo library
-        /// </summary>
-        PhotoChooserTask photoChooserTask;
-
-        /// <summary>
-        /// Used to open camera application
-        /// </summary>
-        CameraCaptureTask cameraTask;
-
-        /// <summary>
         /// Camera options
         /// </summary>
         CameraOptions cameraOptions;
@@ -198,20 +186,17 @@ namespace WPCordovaClassLib.Cordova.Commands
                 string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
                 // ["quality", "destinationType", "sourceType", "targetWidth", "targetHeight", "encodingType",
                 //     "mediaType", "allowEdit", "correctOrientation", "saveToPhotoAlbum" ]
-                this.cameraOptions = new CameraOptions();
-                this.cameraOptions.Quality = int.Parse(args[0]);
-                this.cameraOptions.DestinationType = int.Parse(args[1]);
-                this.cameraOptions.PictureSourceType = int.Parse(args[2]);
-                this.cameraOptions.TargetWidth = int.Parse(args[3]);
-                this.cameraOptions.TargetHeight = int.Parse(args[4]);
-                this.cameraOptions.EncodingType = int.Parse(args[5]);
-                this.cameraOptions.MediaType = int.Parse(args[6]);
-                this.cameraOptions.AllowEdit = bool.Parse(args[7]);
-                this.cameraOptions.CorrectOrientation = bool.Parse(args[8]);
-                this.cameraOptions.SaveToPhotoAlbum = bool.Parse(args[9]);
-                
-                //this.cameraOptions = String.IsNullOrEmpty(options) ?
-                //        new CameraOptions() : JSON.JsonHelper.Deserialize<CameraOptions>(options);
+                cameraOptions = new CameraOptions();
+                cameraOptions.Quality = int.Parse(args[0]);
+                cameraOptions.DestinationType = int.Parse(args[1]);
+                cameraOptions.PictureSourceType = int.Parse(args[2]);
+                cameraOptions.TargetWidth = int.Parse(args[3]);
+                cameraOptions.TargetHeight = int.Parse(args[4]);
+                cameraOptions.EncodingType = int.Parse(args[5]);
+                cameraOptions.MediaType = int.Parse(args[6]);
+                cameraOptions.AllowEdit = bool.Parse(args[7]);
+                cameraOptions.CorrectOrientation = bool.Parse(args[8]);
+                cameraOptions.SaveToPhotoAlbum = bool.Parse(args[9]);
             }
             catch (Exception ex)
             {
@@ -224,28 +209,32 @@ namespace WPCordovaClassLib.Cordova.Commands
 
             if (cameraOptions.PictureSourceType == CAMERA)
             {
-                cameraTask = new CameraCaptureTask();
+                CameraCaptureTask cameraTask = new CameraCaptureTask();
                 cameraTask.Completed += onCameraTaskCompleted;
                 cameraTask.Show();
             }
+            else if ((cameraOptions.PictureSourceType == PHOTOLIBRARY) || (cameraOptions.PictureSourceType == SAVEDPHOTOALBUM))
+            {
+                PhotoChooserTask photoChooserTask = new PhotoChooserTask();
+                photoChooserTask.Completed += onPickerTaskCompleted;
+                photoChooserTask.Show();
+            }
             else
             {
-                if ((cameraOptions.PictureSourceType == PHOTOLIBRARY) || (cameraOptions.PictureSourceType == SAVEDPHOTOALBUM))
-                {
-                    photoChooserTask = new PhotoChooserTask();
-                    photoChooserTask.Completed += onPickerTaskCompleted;
-                    photoChooserTask.Show();
-                }
-                else
-                {
-                    DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT));
-                }
+                DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT));
             }
 
+
         }
 
         public void onCameraTaskCompleted(object sender, PhotoResult e)
         {
+            var task = sender as ChooserBase<PhotoResult>;
+            if (task != null)
+            {
+                task.Completed -= onCameraTaskCompleted;
+            }
+
             if (e.Error != null)
             {
                 DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
@@ -289,10 +278,7 @@ namespace WPCordovaClassLib.Cordova.Commands
 
                             // we should return stream position back after saving stream to media library
                             rotImageStream.Seek(0, SeekOrigin.Begin);
-
-                            WriteableBitmap image = PictureDecoder.DecodeJpeg(rotImageStream);
-
-                            imagePathOrContent = this.SaveImageToLocalStorage(image, Path.GetFileName(e.OriginalFileName));
+                            imagePathOrContent = this.SaveImageToLocalStorage(rotImageStream, Path.GetFileName(e.OriginalFileName));
 
 
                         }
@@ -329,6 +315,12 @@ namespace WPCordovaClassLib.Cordova.Commands
 
         public void onPickerTaskCompleted(object sender, PhotoResult e)
         {
+            var task = sender as ChooserBase<PhotoResult>;
+            if (task != null)
+            {
+                task.Completed -= onCameraTaskCompleted;
+            }
+
             if (e.Error != null)
             {
                 DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
@@ -344,8 +336,7 @@ namespace WPCordovaClassLib.Cordova.Commands
 
                         if (cameraOptions.DestinationType == FILE_URI)
                         {
-                            WriteableBitmap image = PictureDecoder.DecodeJpeg(e.ChosenPhoto);
-                            imagePathOrContent = this.SaveImageToLocalStorage(image, Path.GetFileName(e.OriginalFileName));
+                            imagePathOrContent = this.SaveImageToLocalStorage(e.ChosenPhoto, Path.GetFileName(e.OriginalFileName));
                         }
                         else if (cameraOptions.DestinationType == DATA_URL)
                         {
@@ -385,23 +376,29 @@ namespace WPCordovaClassLib.Cordova.Commands
         /// <returns>Base64 representation of the image</returns>
         private string GetImageContent(Stream stream)
         {
-            int streamLength = (int)stream.Length;
-            byte[] fileData = new byte[streamLength + 1];
-            stream.Read(fileData, 0, streamLength);
+            byte[] imageContent = null;
 
-            //use photo's actual width & height if user doesn't provide width & height
-            if (cameraOptions.TargetWidth < 0 && cameraOptions.TargetHeight < 0)
+            try
             {
-                stream.Close();
-                return Convert.ToBase64String(fileData);
+                //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);
+                }
             }
-            else
+            finally
             {
-                // resize photo
-                byte[] resizedFile = ResizePhoto(stream, fileData);
-                stream.Close();
-                return Convert.ToBase64String(resizedFile);
+                stream.Dispose();
             }
+
+            return Convert.ToBase64String(imageContent);
         }
 
         /// <summary>
@@ -410,51 +407,87 @@ namespace WPCordovaClassLib.Cordova.Commands
         /// <param name="stream">Image stream</param>
         /// <param name="fileData">File data</param>
         /// <returns>resized image</returns>
-        private byte[] ResizePhoto(Stream stream, byte[] fileData)
+        private byte[] ResizePhoto(Stream stream)
         {
-            int streamLength = (int)stream.Length;
-            int intResult = 0;
-
+            //output
             byte[] resizedFile;
 
-            stream.Read(fileData, 0, streamLength);
-
             BitmapImage objBitmap = new BitmapImage();
-            MemoryStream objBitmapStream = new MemoryStream(fileData);
-            MemoryStream objBitmapStreamResized = new MemoryStream();
-            WriteableBitmap objWB;
             objBitmap.SetSource(stream);
-            objWB = new WriteableBitmap(objBitmap);
+            objBitmap.CreateOptions = BitmapCreateOptions.None;
 
-            // resize the photo with user defined TargetWidth & TargetHeight
-            Extensions.SaveJpeg(objWB, objBitmapStreamResized, cameraOptions.TargetWidth, cameraOptions.TargetHeight, 0, cameraOptions.Quality);
+            WriteableBitmap objWB = new WriteableBitmap(objBitmap);
+            objBitmap.UriSource = null;
 
-            //Convert the resized stream to a byte array. 
-            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... 
-            intResult = objBitmapStreamResized.Read(resizedFile, 0, streamLength);
+            //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)
+                {
+                }
+            }
+        }
+
+        /// <summary>
         /// Saves captured image in isolated storage
         /// </summary>
         /// <param name="imageFileName">image file name</param>
         /// <returns>Image path</returns>
-        private string SaveImageToLocalStorage(WriteableBitmap image, string imageFileName)
+        private string SaveImageToLocalStorage(Stream stream, string imageFileName)
         {
 
-            if (image == null)
+            if (stream == null)
             {
                 throw new ArgumentNullException("imageBytes");
             }
             try
             {
-
-
                 var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
 
                 if (!isoFile.DirectoryExists(isoFolder))
@@ -464,16 +497,41 @@ namespace WPCordovaClassLib.Cordova.Commands
 
                 string filePath = System.IO.Path.Combine("///" + isoFolder + "/", imageFileName);
 
-                using (var stream = isoFile.CreateFile(filePath))
+                using (IsolatedStorageFileStream outputStream = isoFile.CreateFile(filePath))
                 {
-                    // resize image if Height and Width defined via options 
-                    if (cameraOptions.TargetHeight > 0 && cameraOptions.TargetWidth > 0)
+                    BitmapImage objBitmap = new BitmapImage();
+                    objBitmap.SetSource(stream);
+                    objBitmap.CreateOptions = BitmapCreateOptions.None;
+
+                    WriteableBitmap objWB = new WriteableBitmap(objBitmap);
+                    objBitmap.UriSource = null;
+
+                    try
                     {
-                        image.SaveJpeg(stream, cameraOptions.TargetWidth, cameraOptions.TargetHeight, 0, cameraOptions.Quality);
+
+                        //use photo's actual width & height if user doesn't provide width & height
+                        if (cameraOptions.TargetWidth < 0 && cameraOptions.TargetHeight < 0)
+                        {
+                            objWB.SaveJpeg(outputStream, objWB.PixelWidth, objWB.PixelHeight, 0, cameraOptions.Quality);
+                        }
+                        else
+                        {
+                            //Resize
+                            //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);
+
+                            // resize the photo with user defined TargetWidth & TargetHeight
+                            objWB.SaveJpeg(outputStream, width, height, 0, cameraOptions.Quality);
+                        }
                     }
-                    else
+                    finally
                     {
-                        image.SaveJpeg(stream, image.PixelWidth, image.PixelHeight, 0, cameraOptions.Quality);
+                        //Dispose bitmaps immediately, they are memory expensive
+                        DisposeImage(objBitmap);
+                        DisposeImage(objWB);
+                        GC.Collect();
                     }
                 }
 
@@ -484,6 +542,10 @@ namespace WPCordovaClassLib.Cordova.Commands
                 //TODO: log or do something else
                 throw;
             }
+            finally
+            {
+                stream.Dispose();
+            }
         }
 
     }


[2/3] git commit: combining callbacks, removing lots of dupe code

Posted by pu...@apache.org.
combining callbacks, removing lots of dupe code


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/commit/f6e85483
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/tree/f6e85483
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/diff/f6e85483

Branch: refs/heads/dev
Commit: f6e8548381db0e7e4b7d6e095c6718313a001edf
Parents: e7a3d70
Author: Jesse MacFadyen <pu...@gmail.com>
Authored: Mon Apr 7 16:32:21 2014 -0700
Committer: Jesse MacFadyen <pu...@gmail.com>
Committed: Mon Apr 7 16:32:21 2014 -0700

----------------------------------------------------------------------
 src/wp/Camera.cs | 99 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/f6e85483/src/wp/Camera.cs
----------------------------------------------------------------------
diff --git a/src/wp/Camera.cs b/src/wp/Camera.cs
index 53ae61a..c9f6f78 100644
--- a/src/wp/Camera.cs
+++ b/src/wp/Camera.cs
@@ -200,7 +200,7 @@ namespace WPCordovaClassLib.Cordova.Commands
             }
             catch (Exception ex)
             {
-                this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
                 return;
             }
 
@@ -227,6 +227,95 @@ namespace WPCordovaClassLib.Cordova.Commands
 
         }
 
+        public void onTaskCompleted(object sender, PhotoResult e)
+        {
+            var task = sender as ChooserBase<PhotoResult>;
+            if (task != null)
+            {
+                task.Completed -= onCameraTaskCompleted;
+            }
+
+            if (e.Error != null)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+                return;
+            }
+
+            switch (e.TaskResult)
+            {
+                case TaskResult.OK:
+                    try
+                    {
+                        string imagePathOrContent = string.Empty;
+                        if (cameraOptions.DestinationType == FILE_URI)
+                        {
+                            // Save image in media library
+                            if (cameraOptions.SaveToPhotoAlbum)
+                            {
+                                MediaLibrary library = new MediaLibrary();
+                                Picture pict = library.SavePicture(e.OriginalFileName, e.ChosenPhoto); // to save to photo-roll ...
+                            }
+
+                            /*
+                                                 int orient = ImageExifHelper.getImageOrientationFromStream(e.ChosenPhoto);
+                    int newAngle = 0;
+                    switch (orient)
+                    {
+                        case ImageExifOrientation.LandscapeLeft:
+                            newAngle = 90;
+                            break;
+                        case ImageExifOrientation.PortraitUpsideDown:
+                            newAngle = 180;
+                            break;
+                        case ImageExifOrientation.LandscapeRight:
+                            newAngle = 270;
+                            break;
+                        case ImageExifOrientation.Portrait:
+                        default: break; // 0 default already set
+                    }
+
+                    Stream rotImageStream = ImageExifHelper.RotateStream(e.ChosenPhoto, newAngle);
+
+                    // we should reset stream position after saving stream to media library
+                    rotImageStream.Seek(0, SeekOrigin.Begin);
+                    imagePathOrContent = SaveImageToLocalStorage(rotImageStream, Path.GetFileName(e.OriginalFileName));
+
+                             */
+                              
+                             
+                            imagePathOrContent = SaveImageToLocalStorage(e.ChosenPhoto, Path.GetFileName(e.OriginalFileName));
+                        }
+                        else if (cameraOptions.DestinationType == DATA_URL)
+                        {
+                            imagePathOrContent = GetImageContent(e.ChosenPhoto);
+                        }
+                        else
+                        {
+                            // TODO: shouldn't this happen before we launch the camera-picker?
+                            DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType"));
+                            return;
+                        }
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK, imagePathOrContent));
+
+                    }
+                    catch (Exception)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error retrieving image."));
+                    }
+                    break;
+
+                case TaskResult.Cancel:
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection cancelled."));
+                    break;
+
+                default:
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection did not complete!"));
+                    break;
+            }
+
+
+        }
+
         public void onCameraTaskCompleted(object sender, PhotoResult e)
         {
             var task = sender as ChooserBase<PhotoResult>;
@@ -278,13 +367,13 @@ namespace WPCordovaClassLib.Cordova.Commands
 
                             // we should return stream position back after saving stream to media library
                             rotImageStream.Seek(0, SeekOrigin.Begin);
-                            imagePathOrContent = this.SaveImageToLocalStorage(rotImageStream, Path.GetFileName(e.OriginalFileName));
+                            imagePathOrContent = SaveImageToLocalStorage(rotImageStream, Path.GetFileName(e.OriginalFileName));
 
 
                         }
                         else if (cameraOptions.DestinationType == DATA_URL)
                         {
-                            imagePathOrContent = this.GetImageContent(e.ChosenPhoto);
+                            imagePathOrContent = GetImageContent(e.ChosenPhoto);
                         }
                         else
                         {
@@ -336,11 +425,11 @@ namespace WPCordovaClassLib.Cordova.Commands
 
                         if (cameraOptions.DestinationType == FILE_URI)
                         {
-                            imagePathOrContent = this.SaveImageToLocalStorage(e.ChosenPhoto, Path.GetFileName(e.OriginalFileName));
+                            imagePathOrContent = SaveImageToLocalStorage(e.ChosenPhoto, Path.GetFileName(e.OriginalFileName));
                         }
                         else if (cameraOptions.DestinationType == DATA_URL)
                         {
-                            imagePathOrContent = this.GetImageContent(e.ChosenPhoto);
+                            imagePathOrContent = GetImageContent(e.ChosenPhoto);
 
                         }
                         else


[3/3] git commit: cleanup, finalize implementations/consolidations

Posted by pu...@apache.org.
cleanup, finalize implementations/consolidations


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/commit/ae2acd9a
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/tree/ae2acd9a
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/diff/ae2acd9a

Branch: refs/heads/dev
Commit: ae2acd9ab237df976bd90c3da2fcf0498b027935
Parents: f6e8548
Author: Jesse MacFadyen <pu...@gmail.com>
Authored: Mon Apr 7 18:13:57 2014 -0700
Committer: Jesse MacFadyen <pu...@gmail.com>
Committed: Mon Apr 7 18:13:57 2014 -0700

----------------------------------------------------------------------
 src/wp/Camera.cs | 252 ++++++++++++--------------------------------------
 1 file changed, 58 insertions(+), 194 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/ae2acd9a/src/wp/Camera.cs
----------------------------------------------------------------------
diff --git a/src/wp/Camera.cs b/src/wp/Camera.cs
index c9f6f78..977634b 100644
--- a/src/wp/Camera.cs
+++ b/src/wp/Camera.cs
@@ -204,27 +204,32 @@ namespace WPCordovaClassLib.Cordova.Commands
                 return;
             }
 
-            //TODO Check if all the options are acceptable
-
+            if(cameraOptions.DestinationType != Camera.FILE_URI && cameraOptions.DestinationType != Camera.DATA_URL )
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType"));
+                return;
+            }
 
+            ChooserBase<PhotoResult> chooserTask = null;
             if (cameraOptions.PictureSourceType == CAMERA)
             {
-                CameraCaptureTask cameraTask = new CameraCaptureTask();
-                cameraTask.Completed += onCameraTaskCompleted;
-                cameraTask.Show();
+                chooserTask = new CameraCaptureTask();
             }
             else if ((cameraOptions.PictureSourceType == PHOTOLIBRARY) || (cameraOptions.PictureSourceType == SAVEDPHOTOALBUM))
             {
-                PhotoChooserTask photoChooserTask = new PhotoChooserTask();
-                photoChooserTask.Completed += onPickerTaskCompleted;
-                photoChooserTask.Show();
+                chooserTask = new PhotoChooserTask();
+            }
+            // if chooserTask is still null, then PictureSourceType was invalid
+            if (chooserTask != null)
+            {
+                chooserTask.Completed += onTaskCompleted;
+                chooserTask.Show();
             }
             else
             {
+                Debug.WriteLine("Unrecognized PictureSourceType :: " + cameraOptions.PictureSourceType.ToString());
                 DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT));
             }
-
-
         }
 
         public void onTaskCompleted(object sender, PhotoResult e)
@@ -232,7 +237,7 @@ namespace WPCordovaClassLib.Cordova.Commands
             var task = sender as ChooserBase<PhotoResult>;
             if (task != null)
             {
-                task.Completed -= onCameraTaskCompleted;
+                task.Completed -= onTaskCompleted;
             }
 
             if (e.Error != null)
@@ -247,217 +252,76 @@ namespace WPCordovaClassLib.Cordova.Commands
                     try
                     {
                         string imagePathOrContent = string.Empty;
-                        if (cameraOptions.DestinationType == FILE_URI)
-                        {
-                            // Save image in media library
-                            if (cameraOptions.SaveToPhotoAlbum)
-                            {
-                                MediaLibrary library = new MediaLibrary();
-                                Picture pict = library.SavePicture(e.OriginalFileName, e.ChosenPhoto); // to save to photo-roll ...
-                            }
-
-                            /*
-                                                 int orient = ImageExifHelper.getImageOrientationFromStream(e.ChosenPhoto);
-                    int newAngle = 0;
-                    switch (orient)
-                    {
-                        case ImageExifOrientation.LandscapeLeft:
-                            newAngle = 90;
-                            break;
-                        case ImageExifOrientation.PortraitUpsideDown:
-                            newAngle = 180;
-                            break;
-                        case ImageExifOrientation.LandscapeRight:
-                            newAngle = 270;
-                            break;
-                        case ImageExifOrientation.Portrait:
-                        default: break; // 0 default already set
-                    }
-
-                    Stream rotImageStream = ImageExifHelper.RotateStream(e.ChosenPhoto, newAngle);
-
-                    // we should reset stream position after saving stream to media library
-                    rotImageStream.Seek(0, SeekOrigin.Begin);
-                    imagePathOrContent = SaveImageToLocalStorage(rotImageStream, Path.GetFileName(e.OriginalFileName));
 
-                             */
-                              
-                             
-                            imagePathOrContent = SaveImageToLocalStorage(e.ChosenPhoto, Path.GetFileName(e.OriginalFileName));
-                        }
-                        else if (cameraOptions.DestinationType == DATA_URL)
+                        // Save image back to media library
+                        // only save to photoalbum if it didn't come from there ...
+                        if (cameraOptions.PictureSourceType == CAMERA && cameraOptions.SaveToPhotoAlbum)
                         {
-                            imagePathOrContent = GetImageContent(e.ChosenPhoto);
+                            MediaLibrary library = new MediaLibrary();
+                            Picture pict = library.SavePicture(e.OriginalFileName, e.ChosenPhoto); // to save to photo-roll ...
                         }
-                        else
+
+                        int orient = ImageExifHelper.getImageOrientationFromStream(e.ChosenPhoto);
+                        int newAngle = 270;
+                        switch (orient)
                         {
-                            // TODO: shouldn't this happen before we launch the camera-picker?
-                            DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType"));
-                            return;
+                            case ImageExifOrientation.LandscapeLeft:
+                                newAngle = 90;
+                                break;
+                            case ImageExifOrientation.PortraitUpsideDown:
+                                newAngle = 180;
+                                break;
+                            case ImageExifOrientation.LandscapeRight:
+                                newAngle = 270;
+                                break;
+                            case ImageExifOrientation.Portrait:
+                            default: break; // 0 default already set
                         }
-                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK, imagePathOrContent));
-
-                    }
-                    catch (Exception)
-                    {
-                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error retrieving image."));
-                    }
-                    break;
-
-                case TaskResult.Cancel:
-                    DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection cancelled."));
-                    break;
 
-                default:
-                    DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection did not complete!"));
-                    break;
-            }
-
-
-        }
-
-        public void onCameraTaskCompleted(object sender, PhotoResult e)
-        {
-            var task = sender as ChooserBase<PhotoResult>;
-            if (task != null)
-            {
-                task.Completed -= onCameraTaskCompleted;
-            }
-
-            if (e.Error != null)
-            {
-                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
-                return;
-            }
-
-            switch (e.TaskResult)
-            {
-                case TaskResult.OK:
-                    try
-                    {
-                        string imagePathOrContent = string.Empty;
-
-                        if (cameraOptions.DestinationType == FILE_URI)
+                        if (newAngle != 0)
                         {
-                            // Save image in media library
-                            if (cameraOptions.SaveToPhotoAlbum)
+                            using (Stream rotImageStream = ImageExifHelper.RotateStream(e.ChosenPhoto, newAngle))
                             {
-                                MediaLibrary library = new MediaLibrary();
-                                Picture pict = library.SavePicture(e.OriginalFileName, e.ChosenPhoto); // to save to photo-roll ...
+                                // we should reset stream position after saving stream to media library
+                                rotImageStream.Seek(0, SeekOrigin.Begin);
+                                if (cameraOptions.DestinationType == DATA_URL)
+                                {
+                                    imagePathOrContent = GetImageContent(rotImageStream);
+                                }
+                                else   // FILE_URL
+                                {
+                                    imagePathOrContent = SaveImageToLocalStorage(rotImageStream, Path.GetFileName(e.OriginalFileName));
+                                }
                             }
-
-                            int orient = ImageExifHelper.getImageOrientationFromStream(e.ChosenPhoto);
-                            int newAngle = 0;
-                            switch (orient)
-                            {
-                                case ImageExifOrientation.LandscapeLeft:
-                                    newAngle = 90;
-                                    break;
-                                case ImageExifOrientation.PortraitUpsideDown:
-                                    newAngle = 180;
-                                    break;
-                                case ImageExifOrientation.LandscapeRight:
-                                    newAngle = 270;
-                                    break;
-                                case ImageExifOrientation.Portrait:
-                                default: break; // 0 default already set
-                            }
-
-                            Stream rotImageStream = ImageExifHelper.RotateStream(e.ChosenPhoto, newAngle);
-
-                            // we should return stream position back after saving stream to media library
-                            rotImageStream.Seek(0, SeekOrigin.Begin);
-                            imagePathOrContent = SaveImageToLocalStorage(rotImageStream, Path.GetFileName(e.OriginalFileName));
-
-
-                        }
-                        else if (cameraOptions.DestinationType == DATA_URL)
-                        {
-                            imagePathOrContent = GetImageContent(e.ChosenPhoto);
-                        }
-                        else
-                        {
-                            // TODO: shouldn't this happen before we launch the camera-picker?
-                            DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType"));
-                            return;
-                        }
-
-                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK, imagePathOrContent));
-
-                    }
-                    catch (Exception)
-                    {
-                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error retrieving image."));
-                    }
-                    break;
-
-                case TaskResult.Cancel:
-                    DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection cancelled."));
-                    break;
-
-                default:
-                    DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection did not complete!"));
-                    break;
-            }
-
-        }
-
-        public void onPickerTaskCompleted(object sender, PhotoResult e)
-        {
-            var task = sender as ChooserBase<PhotoResult>;
-            if (task != null)
-            {
-                task.Completed -= onCameraTaskCompleted;
-            }
-
-            if (e.Error != null)
-            {
-                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
-                return;
-            }
-
-            switch (e.TaskResult)
-            {
-                case TaskResult.OK:
-                    try
-                    {
-                        string imagePathOrContent = string.Empty;
-
-                        if (cameraOptions.DestinationType == FILE_URI)
-                        {
-                            imagePathOrContent = SaveImageToLocalStorage(e.ChosenPhoto, Path.GetFileName(e.OriginalFileName));
-                        }
-                        else if (cameraOptions.DestinationType == DATA_URL)
-                        {
-                            imagePathOrContent = GetImageContent(e.ChosenPhoto);
-
                         }
-                        else
+                        else   // no need to reorient
                         {
-                            // TODO: shouldn't this happen before we launch the camera-picker?
-                            DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType"));
-                            return;
+                            if (cameraOptions.DestinationType == DATA_URL)
+                            {
+                                imagePathOrContent = GetImageContent(e.ChosenPhoto);
+                            }
+                            else  // FILE_URL
+                            {
+                                imagePathOrContent = SaveImageToLocalStorage(e.ChosenPhoto, Path.GetFileName(e.OriginalFileName));
+                            }
                         }
 
                         DispatchCommandResult(new PluginResult(PluginResult.Status.OK, imagePathOrContent));
-
                     }
                     catch (Exception)
                     {
                         DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error retrieving image."));
                     }
                     break;
-
                 case TaskResult.Cancel:
                     DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection cancelled."));
                     break;
-
                 default:
                     DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection did not complete!"));
                     break;
             }
         }
-
+     
         /// <summary>
         /// Returns image content in a form of base64 string
         /// </summary>