Compare commits

..
4 Commits
9 changed files with 194 additions and 354 deletions
-31
View File
@@ -175,34 +175,3 @@
* 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`
+2 -5
View File
@@ -1,9 +1,9 @@
{
"name": "cordova-plugin-camera",
"version": "1.1.0",
"version": "0.3.7-dev",
"description": "Cordova Camera Plugin",
"cordova": {
"id": "cordova-plugin-camera",
"id": "org.apache.cordova.camera",
"platforms": [
"firefoxos",
"android",
@@ -38,9 +38,6 @@
"cordova-browser",
"cordova-windows"
],
"peerDependencies": {
"cordova-plugin-file": ">=2.0.0"
},
"author": "Apache Software Foundation",
"license": "Apache 2.0"
}
+2 -2
View File
@@ -21,8 +21,8 @@
<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="cordova-plugin-camera"
version="1.1.0">
id="org.apache.cordova.camera"
version="0.3.7-dev">
<name>Camera</name>
<description>Cordova Camera Plugin</description>
<license>Apache 2.0</license>
+13 -68
View File
@@ -24,7 +24,6 @@ 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;
@@ -34,6 +33,7 @@ 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,33 +762,16 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
*/
private void writeUncompressedImage(Uri uri) throws FileNotFoundException,
IOException {
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.");
}
}
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);
}
os.flush();
os.close();
fis.close();
}
/**
@@ -824,39 +807,13 @@ 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) {
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;
return BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova));
}
// figure out the original width and height of the image
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
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.");
}
}
}
BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options);
//CB-2292: WTF? Why is the width null?
if(options.outWidth == 0 || options.outHeight == 0)
@@ -870,19 +827,7 @@ 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 = 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.");
}
}
}
Bitmap unscaledBitmap = BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options);
if (unscaledBitmap == null) {
return null;
}
+1 -1
View File
@@ -60,7 +60,7 @@ function showCameraDialog (done, cancel, fail) {
});
wv.on('JavaScriptCallback', function (evt, data) {
var args = JSON.parse(data).args;
if (args[0] === 'cordova-plugin-camera') {
if (args[0] === 'org.apache.cordova.camera') {
if (args[1] === 'cancel') {
cancel('User canceled');
} else if (args[1] === 'error') {
+18 -18
View File
@@ -130,8 +130,8 @@ static NSString* toBase64(NSData* data) {
[self.commandDelegate runInBackground:^{
CDVPictureOptions* pictureOptions = [CDVPictureOptions createFromTakePictureArguments:command];
pictureOptions.popoverSupported = [weakSelf popoverSupported];
pictureOptions.usesGeolocation = [weakSelf usesGeolocation];
pictureOptions.popoverSupported = [self popoverSupported];
pictureOptions.usesGeolocation = [self usesGeolocation];
pictureOptions.cropToSize = NO;
BOOL hasCamera = [UIImagePickerController isSourceTypeAvailable:pictureOptions.sourceType];
@@ -142,6 +142,13 @@ 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;
@@ -150,27 +157,20 @@ static NSString* toBase64(NSData* data) {
// we need to capture this state for memory warnings that dealloc this object
cameraPicker.webView = weakSelf.webView;
// 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];
if ([weakSelf popoverSupported] && (pictureOptions.sourceType != UIImagePickerControllerSourceTypeCamera)) {
if (cameraPicker.pickerPopoverController == nil) {
cameraPicker.pickerPopoverController = [[NSClassFromString(@"UIPopoverController") alloc] initWithContentViewController:cameraPicker];
}
[weakSelf displayPopover:pictureOptions.popoverOptions];
weakSelf.hasPendingOperation = NO;
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 {
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.viewController presentViewController:cameraPicker animated:YES completion:^{
weakSelf.hasPendingOperation = NO;
}];
}
});
});
}
}];
}
+152 -223
View File
@@ -53,9 +53,6 @@ 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) {
@@ -137,99 +134,27 @@ function resizeImageBase64(successCallback, errorCallback, file, targetWidth, ta
}, function(err) { errorCallback(err); });
}
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 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 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(windowsPhoneVideoContainers);
fileOpenPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.videosLibrary;
fileOpenPicker.fileTypeFilter.replaceAll([".avi", ".flv", ".asx", ".asf", ".mov", ".mp4", ".mpg", ".rm", ".srt", ".swf", ".wmv", ".vob"]);
}
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) {
@@ -248,6 +173,7 @@ function takePictureFromFileWindows(successCallback, errorCallback, args) {
}, function () {
errorCallback("Can't access localStorage folder.");
});
}
}
else {
@@ -289,29 +215,18 @@ 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-index: 999";
capturePreview.style.cssText = "position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-order: 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-index: 1000";
captureCancelButton.style.cssText = "position: fixed; right: 0; bottom: 0; display: block; margin: 20px; z-order: 1000";
capture = new CaptureNS.MediaCapture();
@@ -338,6 +253,9 @@ 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);
@@ -348,7 +266,6 @@ 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();
@@ -362,7 +279,6 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
};
var destroyCameraPreview = function () {
window.removeEventListener('deviceorientation', cameraPreviewOrientation, false);
capturePreview.pause();
capturePreview.src = null;
[capturePreview, captureCancelButton].forEach(function(elem) {
@@ -381,7 +297,8 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
var encodingProperties,
fileName,
generateUniqueCollisionOption = Windows.Storage.CreationCollisionOption.generateUniqueName,
tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder;
tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder,
capturedFile;
if (encodingType == Camera.EncodingType.PNG) {
fileName = 'photo.png';
@@ -393,45 +310,84 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
tempFolder.createFileAsync(fileName, generateUniqueCollisionOption)
.then(function(tempCapturedFile) {
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.");
});
});
capturedFile = tempCapturedFile;
return capture.capturePhotoToStorageFileAsync(encodingProperties, capturedFile);
})
.done(function(capturedFile) {
.done(function() {
destroyCameraPreview();
savePhoto(capturedFile, {
destinationType: destinationType,
targetHeight: targetHeight,
targetWidth: targetWidth,
encodingType: encodingType,
saveToPhotoAlbum: saveToPhotoAlbum
}, successCallback, errorCallback);
// 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();
}, function(err) {
destroyCameraPreview();
errorCallback(err);
@@ -483,75 +439,44 @@ function takePictureFromCameraWindows(successCallback, errorCallback, args) {
return;
}
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 {
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.");
}
// 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);
}
} else {
errorCallback("Failed to select a file.");
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);
successCallback(strBase64);
}, errorCallback);
}
}
};
savePicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
if (options.encodingType === Camera.EncodingType.PNG) {
// 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) {
savePicker.fileTypeChoices.insert("PNG", [".png"]);
savePicker.suggestedFileName = "photo.png";
} else {
@@ -559,27 +484,31 @@ function savePhoto(picture, options, successCallback, errorCallback) {
savePicker.suggestedFileName = "photo.jpg";
}
// 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);
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();
}
};
Windows.UI.WebUI.WebUIApplication.addEventListener("activated", fileSaveHandler);
savePicker.pickSaveFileAndContinue();
} else {
savePicker.pickSaveFileAsync()
.done(saveFile, errorCallback);
}
}
}, fail);
}, function() {
errorCallback("Fail to capture a photo.");
});
}
require("cordova/exec/proxy").add("Camera",module.exports);
+3 -3
View File
@@ -21,12 +21,12 @@
<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="cordova-plugin-camera-tests"
version="1.1.0">
id="org.apache.cordova.camera.tests"
version="0.3.7-dev">
<name>Cordova Camera Plugin Tests</name>
<license>Apache 2.0</license>
<dependency id="cordova-plugin-file" version=">=2.0.0" />
<dependency id="org.apache.cordova.file" version=">=1.0.1" />
<js-module src="tests.js" name="tests">
</js-module>
+3 -3
View File
@@ -20,7 +20,7 @@
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('back').onclick = function () {
window.qnx.callExtensionMethod('cordova-plugin-camera', 'cancel');
window.qnx.callExtensionMethod('org.apache.cordova.camera', 'cancel');
};
window.navigator.webkitGetUserMedia(
{ video: true },
@@ -36,11 +36,11 @@ document.addEventListener('DOMContentLoaded', function () {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
window.qnx.callExtensionMethod('cordova-plugin-camera', canvas.toDataURL('img/png'));
window.qnx.callExtensionMethod('org.apache.cordova.camera', canvas.toDataURL('img/png'));
};
},
function () {
window.qnx.callExtensionMethod('cordova-plugin-camera', 'error', 'getUserMedia failed');
window.qnx.callExtensionMethod('org.apache.cordova.camera', 'error', 'getUserMedia failed');
}
);
});