forked from public/cordova-plugin-camera
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19feee9cb0 | ||
|
|
69c687e0cf | ||
|
|
b0ee9dd905 | ||
|
|
c2e0db2b86 | ||
|
|
8f07f562a2 | ||
|
|
1e8c836844 | ||
|
|
b131021303 | ||
|
|
0dabe94416 | ||
|
|
fb8ce21711 | ||
|
|
b67e4a09ed | ||
|
|
d10bf50c61 | ||
|
|
b7af490a3e | ||
|
|
c2e4d1f36d | ||
|
|
d0fe66e1d5 | ||
|
|
af36e74d05 | ||
|
|
629dbcb712 | ||
|
|
bc7c4278ef | ||
|
|
302aacb214 |
@@ -175,3 +175,34 @@
|
||||
* CB-8559 Integrate TravisCI
|
||||
* CB-8438 cordova-plugin-camera documentation translation: cordova-plugin-camera
|
||||
* CB-8538 Added package.json file
|
||||
|
||||
### 1.0.0 (Apr 15, 2015)
|
||||
* CB-8780 - Display popover using main thread. Fixes popover slowness (closes #81)
|
||||
* CB-8746 bumped version of file dependency
|
||||
* CB-8746 gave plugin major version bump
|
||||
* CB-8707 refactoring windows code to improve readability
|
||||
* CB-8706 use filePicker if saveToPhotoAlbum is true
|
||||
* CB-8706 remove unnecessary capabilities from xml
|
||||
* CB-8747 updated dependency, added peer dependency
|
||||
* CB-8683 updated blackberry specific references of org.apache.cordova.camera to cordova-plugin-camera
|
||||
* CB-8782: Updated the docs to talk about the allowEdit quirks, it's not 100% working, but better than it was
|
||||
* CB-8782: Fixed the flow so that we save the cropped image and use it, not the original non-cropped. Crop only supports G+ Photos Crop, other crops may not work, depending on the OEM
|
||||
* CB-8740: Removing FileHelper call that was failing on Samsung Galaxy S3, now that we have a real path, we only need to update the MediaStore, not pull from it in this case
|
||||
* CB-8740: Partial fix for Save Image to Gallery error found in MobileSpec
|
||||
* CB-8683 changed plugin-id to pacakge-name
|
||||
* CB-8653 properly updated translated docs to use new id
|
||||
* CB-8653 updated translated docs to use new id
|
||||
* CB-8351 Fix custom implementation of integerValueForKey (close #79)
|
||||
* Fix cordova-paramedic path change, build with TRAVIS_BUILD_DIR, use npm to install paramedic
|
||||
* docs: added 'Windows' to supported platforms
|
||||
* CB-8653 Updated Readme
|
||||
* CB-8659: ios: 4.0.x Compatibility: Remove use of deprecated headers
|
||||
|
||||
### 1.1.0 (May 06, 2015)
|
||||
* CB-8943 fix `PickAndContinue` issue on *Win10Phone*
|
||||
* CB-8253 Fix potential unreleased resources
|
||||
* CB-8909: Remove unused import from File
|
||||
* CB-8404 typo fix `cameraproxy.js`
|
||||
* CB-8404 Rotate camera feed with device orientation
|
||||
* CB-8054 Support taking pictures from file for *WP8*
|
||||
* CB-8405 Use `z-index` instead of `z-order`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cordova-plugin-camera",
|
||||
"version": "0.3.7-dev",
|
||||
"version": "1.1.0",
|
||||
"description": "Cordova Camera Plugin",
|
||||
"cordova": {
|
||||
"id": "cordova-plugin-camera",
|
||||
@@ -39,7 +39,7 @@
|
||||
"cordova-windows"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"cordova-plugin-file": ">=1.0.1"
|
||||
"cordova-plugin-file": ">=2.0.0"
|
||||
},
|
||||
"author": "Apache Software Foundation",
|
||||
"license": "Apache 2.0"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:rim="http://www.blackberry.com/ns/widgets"
|
||||
id="cordova-plugin-camera"
|
||||
version="0.3.7-dev">
|
||||
version="1.1.0">
|
||||
<name>Camera</name>
|
||||
<description>Cordova Camera Plugin</description>
|
||||
<license>Apache 2.0</license>
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.text.SimpleDateFormat;
|
||||
@@ -33,7 +34,6 @@ import org.apache.cordova.CallbackContext;
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
import org.apache.cordova.LOG;
|
||||
import org.apache.cordova.PluginResult;
|
||||
import org.apache.cordova.file.FileUtils;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
@@ -762,16 +762,33 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
|
||||
*/
|
||||
private void writeUncompressedImage(Uri uri) throws FileNotFoundException,
|
||||
IOException {
|
||||
FileInputStream fis = new FileInputStream(FileHelper.stripFileProtocol(imageUri.toString()));
|
||||
OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
|
||||
byte[] buffer = new byte[4096];
|
||||
int len;
|
||||
while ((len = fis.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, len);
|
||||
FileInputStream fis = null;
|
||||
OutputStream os = null;
|
||||
try {
|
||||
fis = new FileInputStream(FileHelper.stripFileProtocol(imageUri.toString()));
|
||||
os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
|
||||
byte[] buffer = new byte[4096];
|
||||
int len;
|
||||
while ((len = fis.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, len);
|
||||
}
|
||||
os.flush();
|
||||
} finally {
|
||||
if (os != null) {
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
LOG.d(LOG_TAG,"Exception while closing output stream.");
|
||||
}
|
||||
}
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
LOG.d(LOG_TAG,"Exception while closing file input stream.");
|
||||
}
|
||||
}
|
||||
}
|
||||
os.flush();
|
||||
os.close();
|
||||
fis.close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -807,13 +824,39 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
|
||||
private Bitmap getScaledBitmap(String imageUrl) throws IOException {
|
||||
// If no new width or height were specified return the original bitmap
|
||||
if (this.targetWidth <= 0 && this.targetHeight <= 0) {
|
||||
return BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova));
|
||||
InputStream fileStream = null;
|
||||
Bitmap image = null;
|
||||
try {
|
||||
fileStream = FileHelper.getInputStreamFromUriString(imageUrl, cordova);
|
||||
image = BitmapFactory.decodeStream(fileStream);
|
||||
} finally {
|
||||
if (fileStream != null) {
|
||||
try {
|
||||
fileStream.close();
|
||||
} catch (IOException e) {
|
||||
LOG.d(LOG_TAG,"Exception while closing file input stream.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
// figure out the original width and height of the image
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options);
|
||||
InputStream fileStream = null;
|
||||
try {
|
||||
fileStream = FileHelper.getInputStreamFromUriString(imageUrl, cordova);
|
||||
BitmapFactory.decodeStream(fileStream, null, options);
|
||||
} finally {
|
||||
if (fileStream != null) {
|
||||
try {
|
||||
fileStream.close();
|
||||
} catch (IOException e) {
|
||||
LOG.d(LOG_TAG,"Exception while closing file input stream.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//CB-2292: WTF? Why is the width null?
|
||||
if(options.outWidth == 0 || options.outHeight == 0)
|
||||
@@ -827,7 +870,19 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
|
||||
// Load in the smallest bitmap possible that is closest to the size we want
|
||||
options.inJustDecodeBounds = false;
|
||||
options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight);
|
||||
Bitmap unscaledBitmap = BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options);
|
||||
Bitmap unscaledBitmap = null;
|
||||
try {
|
||||
fileStream = FileHelper.getInputStreamFromUriString(imageUrl, cordova);
|
||||
unscaledBitmap = BitmapFactory.decodeStream(fileStream, null, options);
|
||||
} finally {
|
||||
if (fileStream != null) {
|
||||
try {
|
||||
fileStream.close();
|
||||
} catch (IOException e) {
|
||||
LOG.d(LOG_TAG,"Exception while closing file input stream.");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unscaledBitmap == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -130,8 +130,8 @@ static NSString* toBase64(NSData* data) {
|
||||
[self.commandDelegate runInBackground:^{
|
||||
|
||||
CDVPictureOptions* pictureOptions = [CDVPictureOptions createFromTakePictureArguments:command];
|
||||
pictureOptions.popoverSupported = [self popoverSupported];
|
||||
pictureOptions.usesGeolocation = [self usesGeolocation];
|
||||
pictureOptions.popoverSupported = [weakSelf popoverSupported];
|
||||
pictureOptions.usesGeolocation = [weakSelf usesGeolocation];
|
||||
pictureOptions.cropToSize = NO;
|
||||
|
||||
BOOL hasCamera = [UIImagePickerController isSourceTypeAvailable:pictureOptions.sourceType];
|
||||
@@ -142,13 +142,6 @@ static NSString* toBase64(NSData* data) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If a popover is already open, close it; we only want one at a time.
|
||||
if (([[weakSelf pickerController] pickerPopoverController] != nil) && [[[weakSelf pickerController] pickerPopoverController] isPopoverVisible]) {
|
||||
[[[weakSelf pickerController] pickerPopoverController] dismissPopoverAnimated:YES];
|
||||
[[[weakSelf pickerController] pickerPopoverController] setDelegate:nil];
|
||||
[[weakSelf pickerController] setPickerPopoverController:nil];
|
||||
}
|
||||
|
||||
CDVCameraPicker* cameraPicker = [CDVCameraPicker createFromPictureOptions:pictureOptions];
|
||||
weakSelf.pickerController = cameraPicker;
|
||||
|
||||
@@ -157,20 +150,27 @@ static NSString* toBase64(NSData* data) {
|
||||
// we need to capture this state for memory warnings that dealloc this object
|
||||
cameraPicker.webView = weakSelf.webView;
|
||||
|
||||
if ([weakSelf popoverSupported] && (pictureOptions.sourceType != UIImagePickerControllerSourceTypeCamera)) {
|
||||
if (cameraPicker.pickerPopoverController == nil) {
|
||||
cameraPicker.pickerPopoverController = [[NSClassFromString(@"UIPopoverController") alloc] initWithContentViewController:cameraPicker];
|
||||
// Perform UI operations on the main thread
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// If a popover is already open, close it; we only want one at a time.
|
||||
if (([[weakSelf pickerController] pickerPopoverController] != nil) && [[[weakSelf pickerController] pickerPopoverController] isPopoverVisible]) {
|
||||
[[[weakSelf pickerController] pickerPopoverController] dismissPopoverAnimated:YES];
|
||||
[[[weakSelf pickerController] pickerPopoverController] setDelegate:nil];
|
||||
[[weakSelf pickerController] setPickerPopoverController:nil];
|
||||
}
|
||||
[weakSelf displayPopover:pictureOptions.popoverOptions];
|
||||
weakSelf.hasPendingOperation = NO;
|
||||
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if ([weakSelf popoverSupported] && (pictureOptions.sourceType != UIImagePickerControllerSourceTypeCamera)) {
|
||||
if (cameraPicker.pickerPopoverController == nil) {
|
||||
cameraPicker.pickerPopoverController = [[NSClassFromString(@"UIPopoverController") alloc] initWithContentViewController:cameraPicker];
|
||||
}
|
||||
[weakSelf displayPopover:pictureOptions.popoverOptions];
|
||||
weakSelf.hasPendingOperation = NO;
|
||||
} else {
|
||||
[weakSelf.viewController presentViewController:cameraPicker animated:YES completion:^{
|
||||
weakSelf.hasPendingOperation = NO;
|
||||
}];
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,9 @@ module.exports = {
|
||||
}
|
||||
};
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/windows/apps/ff462087(v=vs.105).aspx
|
||||
var windowsVideoContainers = [".avi", ".flv", ".asx", ".asf", ".mov", ".mp4", ".mpg", ".rm", ".srt", ".swf", ".wmv", ".vob"];
|
||||
var windowsPhoneVideoContainers = [".avi", ".3gp", ".3g2", ".wmv", ".3gp", ".3g2", ".mp4", ".m4v"];
|
||||
|
||||
// Resize method
|
||||
function resizeImage(successCallback, errorCallback, file, targetWidth, targetHeight, encodingType) {
|
||||
@@ -134,27 +137,99 @@ function resizeImageBase64(successCallback, errorCallback, file, targetWidth, ta
|
||||
}, function(err) { errorCallback(err); });
|
||||
}
|
||||
|
||||
function takePictureFromFile(successCallback, errorCallback, mediaType, destinationType, targetWidth, targetHeight, encodingType) {
|
||||
// TODO: Add WP8.1 support
|
||||
// WP8.1 doesn't allow to use of pickSingleFileAsync method
|
||||
// see http://msdn.microsoft.com/en-us/library/windows/apps/br207852.aspx for details
|
||||
// replacement of pickSingleFileAsync - pickSingleFileAndContinue method
|
||||
// will take application to suspended state and this require additional logic to wake application up
|
||||
if (navigator.appVersion.indexOf('Windows Phone 8.1') >= 0 ) {
|
||||
errorCallback('Not supported');
|
||||
return;
|
||||
function takePictureFromFile(successCallback, errorCallback, args) {
|
||||
// Detect Windows Phone
|
||||
if (navigator.appVersion.indexOf('Windows Phone 8.1') >= 0) {
|
||||
takePictureFromFileWP(successCallback, errorCallback, args);
|
||||
} else {
|
||||
takePictureFromFileWindows(successCallback, errorCallback, args);
|
||||
}
|
||||
}
|
||||
|
||||
function takePictureFromFileWP(successCallback, errorCallback, args) {
|
||||
var mediaType = args[6],
|
||||
destinationType = args[1],
|
||||
targetWidth = args[3],
|
||||
targetHeight = args[4],
|
||||
encodingType = args[5];
|
||||
|
||||
/*
|
||||
Need to add and remove an event listener to catch activation state
|
||||
Using FileOpenPicker will suspend the app and it's required to catch the PickSingleFileAndContinue
|
||||
https://msdn.microsoft.com/en-us/library/windows/apps/xaml/dn631755.aspx
|
||||
*/
|
||||
var filePickerActivationHandler = function(eventArgs) {
|
||||
if (eventArgs.kind === Windows.ApplicationModel.Activation.ActivationKind.pickFileContinuation) {
|
||||
var file = eventArgs.files[0];
|
||||
if (!file) {
|
||||
errorCallback("User didn't choose a file.");
|
||||
Windows.UI.WebUI.WebUIApplication.removeEventListener("activated", filePickerActivationHandler);
|
||||
return;
|
||||
}
|
||||
if (destinationType == Camera.DestinationType.FILE_URI || destinationType == Camera.DestinationType.NATIVE_URI) {
|
||||
if (targetHeight > 0 && targetWidth > 0) {
|
||||
resizeImage(successCallback, errorCallback, file, targetWidth, targetHeight, encodingType);
|
||||
}
|
||||
else {
|
||||
var storageFolder = Windows.Storage.ApplicationData.current.localFolder;
|
||||
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).done(function (storageFile) {
|
||||
successCallback(URL.createObjectURL(storageFile));
|
||||
}, function () {
|
||||
errorCallback("Can't access localStorage folder.");
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (targetHeight > 0 && targetWidth > 0) {
|
||||
resizeImageBase64(successCallback, errorCallback, file, targetWidth, targetHeight);
|
||||
} else {
|
||||
Windows.Storage.FileIO.readBufferAsync(file).done(function (buffer) {
|
||||
var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
|
||||
successCallback(strBase64);
|
||||
}, errorCallback);
|
||||
}
|
||||
}
|
||||
Windows.UI.WebUI.WebUIApplication.removeEventListener("activated", filePickerActivationHandler);
|
||||
}
|
||||
};
|
||||
|
||||
var fileOpenPicker = new Windows.Storage.Pickers.FileOpenPicker();
|
||||
fileOpenPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
|
||||
if (mediaType == Camera.MediaType.PICTURE) {
|
||||
fileOpenPicker.fileTypeFilter.replaceAll([".png", ".jpg", ".jpeg"]);
|
||||
fileOpenPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
|
||||
}
|
||||
else if (mediaType == Camera.MediaType.VIDEO) {
|
||||
fileOpenPicker.fileTypeFilter.replaceAll([".avi", ".flv", ".asx", ".asf", ".mov", ".mp4", ".mpg", ".rm", ".srt", ".swf", ".wmv", ".vob"]);
|
||||
fileOpenPicker.fileTypeFilter.replaceAll(windowsPhoneVideoContainers);
|
||||
fileOpenPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.videosLibrary;
|
||||
}
|
||||
else {
|
||||
fileOpenPicker.fileTypeFilter.replaceAll(["*"]);
|
||||
fileOpenPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.documentsLibrary;
|
||||
}
|
||||
|
||||
Windows.UI.WebUI.WebUIApplication.addEventListener("activated", filePickerActivationHandler);
|
||||
fileOpenPicker.pickSingleFileAndContinue();
|
||||
}
|
||||
|
||||
function takePictureFromFileWindows(successCallback, errorCallback, args) {
|
||||
var mediaType = args[6],
|
||||
destinationType = args[1],
|
||||
targetWidth = args[3],
|
||||
targetHeight = args[4],
|
||||
encodingType = args[5];
|
||||
|
||||
var fileOpenPicker = new Windows.Storage.Pickers.FileOpenPicker();
|
||||
if (mediaType == Camera.MediaType.PICTURE) {
|
||||
fileOpenPicker.fileTypeFilter.replaceAll([".png", ".jpg", ".jpeg"]);
|
||||
fileOpenPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
|
||||
}
|
||||
else if (mediaType == Camera.MediaType.VIDEO) {
|
||||
fileOpenPicker.fileTypeFilter.replaceAll(windowsVideoContainers);
|
||||
fileOpenPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.videosLibrary;
|
||||
}
|
||||
else {
|
||||
fileOpenPicker.fileTypeFilter.replaceAll(["*"]);
|
||||
fileOpenPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.documentsLibrary;
|
||||
}
|
||||
|
||||
fileOpenPicker.pickSingleFileAsync().done(function (file) {
|
||||
@@ -173,7 +248,6 @@ function takePictureFromFile(successCallback, errorCallback, mediaType, destinat
|
||||
}, function () {
|
||||
errorCallback("Can't access localStorage folder.");
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -215,18 +289,29 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
|
||||
captureSettings = null,
|
||||
CaptureNS = Windows.Media.Capture;
|
||||
|
||||
function cameraPreviewOrientation() {
|
||||
// Rotate the cam since WP8.1 MediaCapture outputs video stream rotated 90° CCW
|
||||
if (screen.msOrientation === "portrait-primary" || screen.msOrientation === "portrait-secondary") {
|
||||
capture.setPreviewRotation(Windows.Media.Capture.VideoRotation.clockwise90Degrees);
|
||||
} else if (screen.msOrientation === "landscape-secondary") {
|
||||
capture.setPreviewRotation(Windows.Media.Capture.VideoRotation.clockwise180Degrees);
|
||||
} else {
|
||||
capture.setPreviewRotation(Windows.Media.Capture.VideoRotation.none);
|
||||
}
|
||||
}
|
||||
|
||||
var createCameraUI = function () {
|
||||
// Create fullscreen preview
|
||||
capturePreview = document.createElement("video");
|
||||
|
||||
// z-order style element for capturePreview and captureCancelButton elts
|
||||
// is necessary to avoid overriding by another page elements, -1 sometimes is not enough
|
||||
capturePreview.style.cssText = "position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-order: 999";
|
||||
capturePreview.style.cssText = "position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 999";
|
||||
|
||||
// Create cancel button
|
||||
captureCancelButton = document.createElement("button");
|
||||
captureCancelButton.innerText = "Cancel";
|
||||
captureCancelButton.style.cssText = "position: fixed; right: 0; bottom: 0; display: block; margin: 20px; z-order: 1000";
|
||||
captureCancelButton.style.cssText = "position: fixed; right: 0; bottom: 0; display: block; margin: 20px; z-index: 1000";
|
||||
|
||||
capture = new CaptureNS.MediaCapture();
|
||||
|
||||
@@ -253,9 +338,6 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
|
||||
});
|
||||
|
||||
capture.initializeAsync(captureSettings).done(function () {
|
||||
// This is necessary since WP8.1 MediaCapture outputs video stream rotated 90 degrees CCW
|
||||
// TODO: This can be not consistent across devices, need additional testing on various devices
|
||||
capture.setPreviewRotation(Windows.Media.Capture.VideoRotation.clockwise90Degrees);
|
||||
// msdn.microsoft.com/en-us/library/windows/apps/hh452807.aspx
|
||||
capturePreview.msZoom = true;
|
||||
capturePreview.src = URL.createObjectURL(capture);
|
||||
@@ -266,6 +348,7 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
|
||||
document.body.appendChild(captureCancelButton);
|
||||
|
||||
// Bind events to controls
|
||||
window.addEventListener('deviceorientation', cameraPreviewOrientation, false);
|
||||
capturePreview.addEventListener('click', captureAction);
|
||||
captureCancelButton.addEventListener('click', function () {
|
||||
destroyCameraPreview();
|
||||
@@ -279,6 +362,7 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
|
||||
};
|
||||
|
||||
var destroyCameraPreview = function () {
|
||||
window.removeEventListener('deviceorientation', cameraPreviewOrientation, false);
|
||||
capturePreview.pause();
|
||||
capturePreview.src = null;
|
||||
[capturePreview, captureCancelButton].forEach(function(elem) {
|
||||
@@ -297,8 +381,7 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
|
||||
var encodingProperties,
|
||||
fileName,
|
||||
generateUniqueCollisionOption = Windows.Storage.CreationCollisionOption.generateUniqueName,
|
||||
tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder,
|
||||
capturedFile;
|
||||
tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder;
|
||||
|
||||
if (encodingType == Camera.EncodingType.PNG) {
|
||||
fileName = 'photo.png';
|
||||
@@ -310,84 +393,45 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
|
||||
|
||||
tempFolder.createFileAsync(fileName, generateUniqueCollisionOption)
|
||||
.then(function(tempCapturedFile) {
|
||||
capturedFile = tempCapturedFile;
|
||||
return capture.capturePhotoToStorageFileAsync(encodingProperties, capturedFile);
|
||||
return new WinJS.Promise(function (complete) {
|
||||
var imgStream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
|
||||
capture.capturePhotoToStreamAsync(encodingProperties, imgStream)
|
||||
.then(function() {
|
||||
return Windows.Graphics.Imaging.BitmapDecoder.createAsync(imgStream);
|
||||
})
|
||||
.then(function(dec) {
|
||||
return Windows.Graphics.Imaging.BitmapEncoder.createForTranscodingAsync(imgStream, dec);
|
||||
})
|
||||
.then(function(enc) {
|
||||
// We need to rotate the photo 90° CW because by default wp8.1 takes 90° CCW rotated photos.
|
||||
enc.bitmapTransform.rotation = Windows.Graphics.Imaging.BitmapRotation.clockwise90Degrees;
|
||||
return enc.flushAsync();
|
||||
})
|
||||
.then(function() {
|
||||
return tempCapturedFile.openAsync(Windows.Storage.FileAccessMode.readWrite);
|
||||
})
|
||||
.then(function(fileStream) {
|
||||
imgStream.seek(0); // required for win8.1 emulator
|
||||
return Windows.Storage.Streams.RandomAccessStream.copyAsync(imgStream, fileStream);
|
||||
})
|
||||
.done(function() {
|
||||
imgStream.close();
|
||||
complete(tempCapturedFile);
|
||||
}, function() {
|
||||
imgStream.close();
|
||||
throw new Error("An error has occured while capturing the photo.");
|
||||
});
|
||||
});
|
||||
})
|
||||
.done(function() {
|
||||
.done(function(capturedFile) {
|
||||
destroyCameraPreview();
|
||||
|
||||
// success callback for capture operation
|
||||
var success = function(capturedfile) {
|
||||
if (destinationType == Camera.DestinationType.FILE_URI || destinationType == Camera.DestinationType.NATIVE_URI) {
|
||||
if (targetHeight > 0 && targetWidth > 0) {
|
||||
resizeImage(successCallback, errorCallback, capturedFile, targetWidth, targetHeight, encodingType);
|
||||
} else {
|
||||
capturedfile.copyAsync(Windows.Storage.ApplicationData.current.localFolder, capturedfile.name, generateUniqueCollisionOption).done(function(copiedfile) {
|
||||
successCallback("ms-appdata:///local/" + copiedfile.name);
|
||||
}, errorCallback);
|
||||
}
|
||||
} else {
|
||||
if (targetHeight > 0 && targetWidth > 0) {
|
||||
resizeImageBase64(successCallback, errorCallback, capturedfile, targetWidth, targetHeight);
|
||||
} else {
|
||||
Windows.Storage.FileIO.readBufferAsync(capturedfile).done(function(buffer) {
|
||||
var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
|
||||
capturedfile.deleteAsync().done(function() {
|
||||
successCallback(strBase64);
|
||||
}, function(err) {
|
||||
errorCallback(err);
|
||||
});
|
||||
}, errorCallback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!saveToPhotoAlbum) {
|
||||
success(capturedFile);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Need to add and remove an event listener to catch activation state
|
||||
Using FileSavePicker will suspend the app and it's required to catch the pickSaveFileContinuation
|
||||
https://msdn.microsoft.com/en-us/library/windows/apps/xaml/dn631755.aspx
|
||||
*/
|
||||
var cameraActivationHandler = function(eventArgs) {
|
||||
if (eventArgs.kind === Windows.ApplicationModel.Activation.ActivationKind.pickSaveFileContinuation) {
|
||||
var file = eventArgs.file;
|
||||
if (file) {
|
||||
// Prevent updates to the remote version of the file until we're done
|
||||
Windows.Storage.CachedFileManager.deferUpdates(file);
|
||||
capturedFile.moveAndReplaceAsync(file)
|
||||
.then(function() {
|
||||
// Let Windows know that we're finished changing the file so
|
||||
// the other app can update the remote version of the file.
|
||||
return Windows.Storage.CachedFileManager.completeUpdatesAsync(file);
|
||||
})
|
||||
.done(function(updateStatus) {
|
||||
if (updateStatus === Windows.Storage.Provider.FileUpdateStatus.complete) {
|
||||
success(capturedFile);
|
||||
} else {
|
||||
errorCallback();
|
||||
}
|
||||
}, errorCallback);
|
||||
} else {
|
||||
errorCallback();
|
||||
}
|
||||
Windows.UI.WebUI.WebUIApplication.removeEventListener("activated", cameraActivationHandler);
|
||||
}
|
||||
};
|
||||
|
||||
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
|
||||
savePicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.documentsLibrary;
|
||||
if (encodingType === Camera.EncodingType.PNG) {
|
||||
savePicker.fileTypeChoices.insert("PNG", [".png"]);
|
||||
} else {
|
||||
savePicker.fileTypeChoices.insert("JPEG", [".jpg"]);
|
||||
}
|
||||
savePicker.suggestedFileName = fileName;
|
||||
Windows.UI.WebUI.WebUIApplication.addEventListener("activated", cameraActivationHandler);
|
||||
savePicker.pickSaveFileAndContinue();
|
||||
savePhoto(capturedFile, {
|
||||
destinationType: destinationType,
|
||||
targetHeight: targetHeight,
|
||||
targetWidth: targetWidth,
|
||||
encodingType: encodingType,
|
||||
saveToPhotoAlbum: saveToPhotoAlbum
|
||||
}, successCallback, errorCallback);
|
||||
}, function(err) {
|
||||
destroyCameraPreview();
|
||||
errorCallback(err);
|
||||
@@ -439,44 +483,75 @@ function takePictureFromCameraWindows(successCallback, errorCallback, args) {
|
||||
return;
|
||||
}
|
||||
|
||||
// save to photo album successCallback
|
||||
var success = function() {
|
||||
if (destinationType == Camera.DestinationType.FILE_URI) {
|
||||
if (targetHeight > 0 && targetWidth > 0) {
|
||||
resizeImage(successCallback, errorCallback, picture, targetWidth, targetHeight, encodingType);
|
||||
} else {
|
||||
var storageFolder = Windows.Storage.ApplicationData.current.localFolder;
|
||||
picture.copyAsync(storageFolder, picture.name, Windows.Storage.NameCollisionOption.replaceExisting).done(function(storageFile) {
|
||||
successCallback("ms-appdata:///local/" + storageFile.name);
|
||||
}, errorCallback);
|
||||
}
|
||||
savePhoto(picture, {
|
||||
destinationType: destinationType,
|
||||
targetHeight: targetHeight,
|
||||
targetWidth: targetWidth,
|
||||
encodingType: encodingType,
|
||||
saveToPhotoAlbum: saveToPhotoAlbum
|
||||
}, successCallback, errorCallback);
|
||||
}, function() {
|
||||
errorCallback("Fail to capture a photo.");
|
||||
});
|
||||
}
|
||||
|
||||
function savePhoto(picture, options, successCallback, errorCallback) {
|
||||
// success callback for capture operation
|
||||
var success = function(picture) {
|
||||
var generateUniqueCollisionOption = Windows.Storage.CreationCollisionOption.generateUniqueName;
|
||||
if (options.destinationType == Camera.DestinationType.FILE_URI || options.destinationType == Camera.DestinationType.NATIVE_URI) {
|
||||
if (options.targetHeight > 0 && options.targetWidth > 0) {
|
||||
resizeImage(successCallback, errorCallback, picture, options.targetWidth, options.targetHeight, options.encodingType);
|
||||
} else {
|
||||
if (targetHeight > 0 && targetWidth > 0) {
|
||||
resizeImageBase64(successCallback, errorCallback, picture, targetWidth, targetHeight);
|
||||
} else {
|
||||
Windows.Storage.FileIO.readBufferAsync(picture).done(function(buffer) {
|
||||
var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
|
||||
picture.copyAsync(Windows.Storage.ApplicationData.current.localFolder, picture.name, generateUniqueCollisionOption).done(function(copiedFile) {
|
||||
successCallback("ms-appdata:///local/" + copiedFile.name);
|
||||
},errorCallback);
|
||||
}
|
||||
} else {
|
||||
if (options.targetHeight > 0 && options.targetWidth > 0) {
|
||||
resizeImageBase64(successCallback, errorCallback, picture, options.targetWidth, options.targetHeight);
|
||||
} else {
|
||||
Windows.Storage.FileIO.readBufferAsync(picture).done(function(buffer) {
|
||||
var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
|
||||
picture.deleteAsync().done(function() {
|
||||
successCallback(strBase64);
|
||||
}, function(err) {
|
||||
errorCallback(err);
|
||||
});
|
||||
}, errorCallback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!options.saveToPhotoAlbum) {
|
||||
success(picture);
|
||||
return;
|
||||
} else {
|
||||
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
|
||||
var saveFile = function(file) {
|
||||
if (file) {
|
||||
// Prevent updates to the remote version of the file until we're done
|
||||
Windows.Storage.CachedFileManager.deferUpdates(file);
|
||||
picture.moveAndReplaceAsync(file)
|
||||
.then(function() {
|
||||
// Let Windows know that we're finished changing the file so
|
||||
// the other app can update the remote version of the file.
|
||||
return Windows.Storage.CachedFileManager.completeUpdatesAsync(file);
|
||||
})
|
||||
.done(function(updateStatus) {
|
||||
if (updateStatus === Windows.Storage.Provider.FileUpdateStatus.complete) {
|
||||
success(picture);
|
||||
} else {
|
||||
errorCallback("File update status is not complete.");
|
||||
}
|
||||
}, errorCallback);
|
||||
}
|
||||
} else {
|
||||
errorCallback("Failed to select a file.");
|
||||
}
|
||||
};
|
||||
savePicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
|
||||
|
||||
// save to photo album errorCallback
|
||||
var fail = function() {
|
||||
//errorCallback("FileError, code:" + fileError.code);
|
||||
errorCallback("Save fail.");
|
||||
};
|
||||
|
||||
if (!saveToPhotoAlbum) {
|
||||
success();
|
||||
return;
|
||||
}
|
||||
|
||||
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
|
||||
|
||||
savePicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.documentsLibrary;
|
||||
if (encodingType === Camera.EncodingType.PNG) {
|
||||
if (options.encodingType === Camera.EncodingType.PNG) {
|
||||
savePicker.fileTypeChoices.insert("PNG", [".png"]);
|
||||
savePicker.suggestedFileName = "photo.png";
|
||||
} else {
|
||||
@@ -484,31 +559,27 @@ function takePictureFromCameraWindows(successCallback, errorCallback, args) {
|
||||
savePicker.suggestedFileName = "photo.jpg";
|
||||
}
|
||||
|
||||
savePicker.pickSaveFileAsync()
|
||||
.done(function(file) {
|
||||
if (file) {
|
||||
// Prevent updates to the remote version of the file until we're done
|
||||
Windows.Storage.CachedFileManager.deferUpdates(file);
|
||||
picture.moveAndReplaceAsync(file)
|
||||
.then(function() {
|
||||
// Let Windows know that we're finished changing the file so
|
||||
// the other app can update the remote version of the file.
|
||||
return Windows.Storage.CachedFileManager.completeUpdatesAsync(file);
|
||||
})
|
||||
.done(function(updateStatus) {
|
||||
if (updateStatus === Windows.Storage.Provider.FileUpdateStatus.complete) {
|
||||
success();
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}, fail);
|
||||
} else {
|
||||
fail();
|
||||
// If Windows Phone 8.1 use pickSaveFileAndContinue()
|
||||
if (navigator.appVersion.indexOf('Windows Phone 8.1') >= 0) {
|
||||
/*
|
||||
Need to add and remove an event listener to catch activation state
|
||||
Using FileSavePicker will suspend the app and it's required to catch the pickSaveFileContinuation
|
||||
https://msdn.microsoft.com/en-us/library/windows/apps/xaml/dn631755.aspx
|
||||
*/
|
||||
var fileSaveHandler = function(eventArgs) {
|
||||
if (eventArgs.kind === Windows.ApplicationModel.Activation.ActivationKind.pickSaveFileContinuation) {
|
||||
var file = eventArgs.file;
|
||||
saveFile(file);
|
||||
Windows.UI.WebUI.WebUIApplication.removeEventListener("activated", fileSaveHandler);
|
||||
}
|
||||
}, fail);
|
||||
}, function() {
|
||||
errorCallback("Fail to capture a photo.");
|
||||
});
|
||||
};
|
||||
Windows.UI.WebUI.WebUIApplication.addEventListener("activated", fileSaveHandler);
|
||||
savePicker.pickSaveFileAndContinue();
|
||||
} else {
|
||||
savePicker.pickSaveFileAsync()
|
||||
.done(saveFile, errorCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
require("cordova/exec/proxy").add("Camera",module.exports);
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:rim="http://www.blackberry.com/ns/widgets"
|
||||
id="cordova-plugin-camera-tests"
|
||||
version="0.3.7-dev">
|
||||
version="1.1.0">
|
||||
<name>Cordova Camera Plugin Tests</name>
|
||||
<license>Apache 2.0</license>
|
||||
|
||||
<dependency id="cordova-plugin-file" version=">=1.0.1" />
|
||||
<dependency id="cordova-plugin-file" version=">=2.0.0" />
|
||||
|
||||
<js-module src="tests.js" name="tests">
|
||||
</js-module>
|
||||
|
||||
Reference in New Issue
Block a user