Compare commits

..

16 Commits
0.2.8 ... 0.2.9

Author SHA1 Message Date
Ian Clelland
b76b5ae670 CB-6452 Updated version and RELEASENOTES.md for release 0.2.9 2014-04-17 10:53:20 -04:00
Ian Clelland
f2a41e4b5e CB-6460: Update license headers 2014-04-16 16:15:25 -04:00
Jesse MacFadyen
85a986f589 CB-6422 [windows8] use cordova/exec/proxy 2014-04-08 15:53:51 -07:00
Jesse MacFadyen
4c2c567fd8 WP8 When only targetWidth or targetHeight is provided, use it as the only bound 2014-04-08 12:19:44 -07:00
Jesse MacFadyen
fe6dc72a75 Remove rotation test value 2014-04-08 12:03:22 -07:00
Jesse MacFadyen
ae2acd9ab2 cleanup, finalize implementations/consolidations 2014-04-07 18:13:57 -07:00
Jesse MacFadyen
f6e8548381 combining callbacks, removing lots of dupe code 2014-04-07 16:32:21 -07:00
Jesse MacFadyen
e7a3d70fe9 Fix camera issues, cropping, memory leaks CB-4027, CB-5102, CB-2737, CB-2387 2014-04-07 15:00:12 -07:00
James Jong
91d6e10b29 CB-6212 iOS: fix warnings compiled under arm64 64-bit
-one update to CDVCamera.m
2014-03-13 10:16:30 -04:00
Long Nguyen
6fb63fede5 Fix typo error in docs
from libarary to library

github: close #18
2014-03-13 09:59:53 -04:00
James Jong
c9bab1f94c CB-6212 iOS: fix warnings compiled under arm64 64-bit 2014-03-13 09:51:47 -04:00
Ryan Willoughby
5393a28191 Add rim xml namespaces declaration 2014-03-12 12:47:24 -04:00
Andrew Grieve
2a7520112e Merge branch 'master' into dev
Conflicts:
	plugin.xml
2014-02-27 16:03:32 -05:00
Andrew Grieve
61a963d6fb Add NOTICE file 2014-02-27 15:36:55 -05:00
Andrew Grieve
3be1802c9e CB-6114 Incremented plugin version on dev branch. 2014-02-27 15:36:55 -05:00
Andrew Grieve
19a44608b8 CB-6114 Updated version and RELEASENOTES.md for release 0.2.8 2014-02-27 15:36:55 -05:00
7 changed files with 249 additions and 196 deletions

View File

@@ -71,3 +71,12 @@
### 0.2.8 (Feb 26, 2014)
* CB-1826 Catch OOM on gallery image resize
### 0.2.9 (Apr 17, 2014)
* CB-6460: Update license headers
* CB-6422: [windows8] use cordova/exec/proxy
* [WP8] When only targetWidth or targetHeight is provided, use it as the only bound
* CB-4027, CB-5102, CB-2737, CB-2387: [WP] Fix camera issues, cropping, memory leaks
* CB-6212: [iOS] fix warnings compiled under arm64 64-bit
* [BlackBerry10] Add rim xml namespaces declaration
* Add NOTICE file

View File

@@ -20,7 +20,7 @@
# org.apache.cordova.camera
This plugin provides an API for taking pictures and for choosing images from
the system's image libarary.
the system's image library.
cordova plugin add org.apache.cordova.camera

View File

@@ -1,9 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:rim="http://www.blackberry.com/ns/widgets"
id="org.apache.cordova.camera"
version="0.2.8">
version="0.2.9">
<name>Camera</name>
<description>Cordova Camera Plugin</description>
<license>Apache 2.0</license>

View File

@@ -84,7 +84,7 @@ static NSSet* org_apache_cordova_validArrowDirections;
bool hasCamera = [UIImagePickerController isSourceTypeAvailable:sourceType];
if (!hasCamera) {
NSLog(@"Camera.getPicture: source type %d not available.", sourceType);
NSLog(@"Camera.getPicture: source type %lu not available.", (unsigned long)sourceType);
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no camera available"];
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
return;
@@ -170,10 +170,10 @@ static NSSet* org_apache_cordova_validArrowDirections;
- (void)displayPopover:(NSDictionary*)options
{
int x = 0;
int y = 32;
int width = 320;
int height = 480;
NSInteger x = 0;
NSInteger y = 32;
NSInteger width = 320;
NSInteger height = 480;
UIPopoverArrowDirection arrowDirection = UIPopoverArrowDirectionAny;
if (options) {
@@ -182,7 +182,7 @@ static NSSet* org_apache_cordova_validArrowDirections;
width = [options integerValueForKey:@"width" defaultValue:320];
height = [options integerValueForKey:@"height" defaultValue:480];
arrowDirection = [options integerValueForKey:@"arrowDir" defaultValue:UIPopoverArrowDirectionAny];
if (![org_apache_cordova_validArrowDirections containsObject:[NSNumber numberWithInt:arrowDirection]]) {
if (![org_apache_cordova_validArrowDirections containsObject:[NSNumber numberWithUnsignedInteger:arrowDirection]]) {
arrowDirection = UIPopoverArrowDirectionAny;
}
}

View File

@@ -190,7 +190,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
// construct the complete app1 data block
app1 = [[NSMutableString alloc] initWithFormat: @"%@%04x%@%@%@%@%@",
app1marker,
16 + ([exifIFD length]/2) + ([subExifIFD length]/2) /*16+[exifIFD length]/2*/,
(unsigned int)(16 + ([exifIFD length]/2) + ([subExifIFD length]/2)) /*16+[exifIFD length]/2*/,
exifmarker,
tiffheader,
ifd0offset,
@@ -268,10 +268,10 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
}
// calculate IFD0 terminal offset tags, currently ExifSubIFD
int entrycount = [ifdblock count];
unsigned int entrycount = (unsigned int)[ifdblock count];
if (ifd0flag) {
// 18 accounts for 8769's width + offset to next ifd, 8 accounts for start of header
NSNumber * offset = [NSNumber numberWithInt:[exifstr length] / 2 + [dbstr length] / 2 + 18+8];
NSNumber * offset = [NSNumber numberWithUnsignedInteger:[exifstr length] / 2 + [dbstr length] / 2 + 18+8];
[self appendExifOffsetTagTo: exifstr
withOffset : offset];
@@ -293,7 +293,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
NSNumber * dataformat = [formtemplate objectAtIndex:1];
NSNumber * components = [formtemplate objectAtIndex:2];
if([components intValue] == 0) {
components = [NSNumber numberWithInt: [data length] * DataTypeToWidth[[dataformat intValue]-1]];
components = [NSNumber numberWithUnsignedInteger:[data length] * DataTypeToWidth[[dataformat intValue]-1]];
}
return [[NSString alloc] initWithFormat: @"%@%@%08x",
@@ -344,7 +344,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
[datastr appendString:[dataformat objectAtIndex:3]];
}
if ([datastr length] < 8) {
NSString * format = [NSString stringWithFormat:@"%%0%dd", 8 - [datastr length]];
NSString * format = [NSString stringWithFormat:@"%%0%dd", (int)(8 - [datastr length])];
[datastr appendFormat:format,0];
}
return datastr;
@@ -464,7 +464,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
-(void) expandContinuedFraction: (NSArray*) fractionlist
withResultNumerator: (NSNumber**) numerator
withResultDenominator: (NSNumber**) denominator {
int i = 0;
NSUInteger i = 0;
int den = 0;
int num = 0;
if ([fractionlist count] == 1) {

View File

@@ -351,4 +351,4 @@ module.exports = {
}
};
require("cordova/windows8/commandProxy").add("Camera",module.exports);
require("cordova/exec/proxy").add("Camera",module.exports);

View File

@@ -113,8 +113,6 @@ namespace WPCordovaClassLib.Cordova.Commands
[DataMember(IsRequired = false, Name = "correctOrientation")]
public bool CorrectOrientation { get; set; }
/// <summary>
/// Ignored
/// </summary>
@@ -176,16 +174,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>
@@ -198,54 +186,70 @@ 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]);
// a very large number will force the other value to be the bound
if (cameraOptions.TargetWidth > -1 && cameraOptions.TargetHeight == -1)
{
cameraOptions.TargetHeight = 100000;
}
else if (cameraOptions.TargetHeight > -1 && cameraOptions.TargetWidth == -1)
{
cameraOptions.TargetWidth = 100000;
}
}
catch (Exception ex)
{
this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
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)
{
cameraTask = new CameraCaptureTask();
cameraTask.Completed += onCameraTaskCompleted;
cameraTask.Show();
chooserTask = new CameraCaptureTask();
}
else if ((cameraOptions.PictureSourceType == PHOTOLIBRARY) || (cameraOptions.PictureSourceType == SAVEDPHOTOALBUM))
{
chooserTask = new PhotoChooserTask();
}
// if chooserTask is still null, then PictureSourceType was invalid
if (chooserTask != null)
{
chooserTask.Completed += onTaskCompleted;
chooserTask.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));
}
Debug.WriteLine("Unrecognized PictureSourceType :: " + cameraOptions.PictureSourceType.ToString());
DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT));
}
}
public void onCameraTaskCompleted(object sender, PhotoResult e)
public void onTaskCompleted(object sender, PhotoResult e)
{
var task = sender as ChooserBase<PhotoResult>;
if (task != null)
{
task.Completed -= onTaskCompleted;
}
if (e.Error != null)
{
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
@@ -259,125 +263,75 @@ namespace WPCordovaClassLib.Cordova.Commands
{
string imagePathOrContent = string.Empty;
if (cameraOptions.DestinationType == FILE_URI)
// Save image back to media library
// only save to photoalbum if it didn't come from there ...
if (cameraOptions.PictureSourceType == CAMERA && cameraOptions.SaveToPhotoAlbum)
{
// 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 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));
MediaLibrary library = new MediaLibrary();
Picture pict = library.SavePicture(e.OriginalFileName, e.ChosenPhoto); // to save to photo-roll ...
}
else if (cameraOptions.DestinationType == DATA_URL)
int orient = ImageExifHelper.getImageOrientationFromStream(e.ChosenPhoto);
int newAngle = 0;
switch (orient)
{
imagePathOrContent = this.GetImageContent(e.ChosenPhoto);
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
}
else
if (newAngle != 0)
{
// TODO: shouldn't this happen before we launch the camera-picker?
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType"));
return;
using (Stream rotImageStream = ImageExifHelper.RotateStream(e.ChosenPhoto, newAngle))
{
// 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));
}
}
}
else // no need to reorient
{
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;
}
}
public void onPickerTaskCompleted(object sender, PhotoResult e)
{
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)
{
WriteableBitmap image = PictureDecoder.DecodeJpeg(e.ChosenPhoto);
imagePathOrContent = this.SaveImageToLocalStorage(image, Path.GetFileName(e.OriginalFileName));
}
else if (cameraOptions.DestinationType == DATA_URL)
{
imagePathOrContent = this.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;
}
}
/// <summary>
/// Returns image content in a form of base64 string
/// </summary>
@@ -385,23 +339,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 +370,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 +460,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 +505,10 @@ namespace WPCordovaClassLib.Cordova.Commands
//TODO: log or do something else
throw;
}
finally
{
stream.Dispose();
}
}
}