mirror of
https://github.com/apache/cordova-plugin-camera.git
synced 2026-02-14 00:04:54 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b76b5ae670 | ||
|
|
f2a41e4b5e | ||
|
|
85a986f589 | ||
|
|
4c2c567fd8 | ||
|
|
fe6dc72a75 | ||
|
|
ae2acd9ab2 | ||
|
|
f6e8548381 | ||
|
|
e7a3d70fe9 | ||
|
|
91d6e10b29 | ||
|
|
6fb63fede5 | ||
|
|
c9bab1f94c | ||
|
|
5393a28191 | ||
|
|
2a7520112e | ||
|
|
61a963d6fb | ||
|
|
3be1802c9e | ||
|
|
19a44608b8 |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
21
plugin.xml
21
plugin.xml
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -351,4 +351,4 @@ module.exports = {
|
||||
}
|
||||
};
|
||||
|
||||
require("cordova/windows8/commandProxy").add("Camera",module.exports);
|
||||
require("cordova/exec/proxy").add("Camera",module.exports);
|
||||
|
||||
387
src/wp/Camera.cs
387
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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user