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; }
-
-
///
/// Ignored
///
@@ -176,16 +174,6 @@ namespace WPCordovaClassLib.Cordova.Commands
}
}
- ///
- /// Used to open photo library
- ///
- PhotoChooserTask photoChooserTask;
-
- ///
- /// Used to open camera application
- ///
- CameraCaptureTask cameraTask;
-
///
/// Camera options
///
@@ -198,20 +186,17 @@ namespace WPCordovaClassLib.Cordova.Commands
string[] args = JSON.JsonHelper.Deserialize(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(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;
+ 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;
+ 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
/// Base64 representation of the image
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);
}
///
@@ -410,51 +407,87 @@ namespace WPCordovaClassLib.Cordova.Commands
/// Image stream
/// File data
/// resized image
- 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;
}
+ ///
+ /// Util: Dispose a bitmap resource
+ ///
+ /// BitmapSource subclass to dispose
+ private void DisposeImage(BitmapSource image)
+ {
+ if (image != null)
+ {
+ try
+ {
+ using (var ms = new MemoryStream(new byte[] { 0x0 }))
+ {
+ image.SetSource(ms);
+ }
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
///
/// Saves captured image in isolated storage
///
/// image file name
/// Image path
- 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();
+ }
}
}