Compare commits

...
Author SHA1 Message Date
Steve Gill 304599d809 Revert "CB-8747 updated dependency, added peer dependency"
This reverts commit d1dfc1e8ee.
2015-04-09 16:39:42 -07:00
Steve Gill d82bad305b Merge branch 'master' into old-ID 2015-04-09 14:39:47 -07:00
Vladimir Kotikov 3927735d09 CB-8706, CB-8707 saveToPhotoAlbum improvements and some refactoring
- On Windows we should use filePicker instead of programmatically
accessing user libs. This way the app doesnt have to depend on extra
capabilities.

- Some refactoring to help on navigating code easier

This closes #78
2015-04-07 21:48:00 +03:00
Murat Sutunc 9e11ab4dfb CR fixes 2015-04-03 11:08:00 -07:00
Steve Gill d1dfc1e8ee CB-8747 updated dependency, added peer dependency 2015-04-01 23:01:47 -07:00
Steve Gill 03a720808b Revert "CB-8683 updated blackberry specific references of org.apache.cordova.camera to cordova-plugin-camera"
This reverts commit ee4ac0d7b2.
2015-04-01 11:41:42 -07:00
Steve Gill 52a9d39855 Revert "CB-8683 changed plugin-id to pacakge-name"
This reverts commit f1ae0e9ccf.
2015-04-01 11:41:26 -07:00
Steve Gill ee4ac0d7b2 CB-8683 updated blackberry specific references of org.apache.cordova.camera to cordova-plugin-camera 2015-04-01 11:40:30 -07:00
Joe Bowser d52b936bd8 CB-8782: Updated the docs to talk about the allowEdit quirks, it's not 100% working, but better than it was 2015-04-01 11:22:56 -07:00
Joe Bowser 9fe5b430aa 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 2015-04-01 11:04:06 -07:00
Joe Bowser 23dbb8889a 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 2015-04-01 11:04:06 -07:00
Joe Bowser ac4af88f55 CB-8740: Partial fix for Save Image to Gallery error found in MobileSpec 2015-04-01 11:04:06 -07:00
Steve Gill f1ae0e9ccf CB-8683 changed plugin-id to pacakge-name 2015-03-31 16:39:18 -07:00
Steve Gill 563f0038fd CB-8653 properly updated translated docs to use new id 2015-03-31 16:05:59 -07:00
Steve Gill ccbbdccc4c CB-8653 updated translated docs to use new id 2015-03-31 10:53:30 -07:00
Gene ConnollyandAndrew Grieve 04ed502d92 CB-8351 Fix custom implementation of integerValueForKey (close #79)
https://github.com/apache/cordova-plugin-camera/commit/2ead6335c92deb117cc3ef84d0a15db296de8dc5#diff-3cfd0e1f93894bd4e501e8e0e4634850
2015-03-30 20:10:24 -04:00
Jesse MacFadyen 7209d38fa2 Fix cordova-paramedic path change, build with TRAVIS_BUILD_DIR, use npm to install paramedic 2015-03-24 23:16:57 -07:00
Murat Sutunc 29c9ea387d CB-8707 refactoring windows code to improve readability 2015-03-18 11:03:01 -07:00
Murat Sutunc 5ef04e552c CB-8706 use filePicker if saveToPhotoAlbum is true 2015-03-18 10:59:18 -07:00
Murat Sutunc b8a700215a CB-8706 remove unnecessary capabilities from xml 2015-03-18 10:58:37 -07:00
15 changed files with 615 additions and 486 deletions
+2 -2
View File
@@ -6,8 +6,8 @@ node_js:
install:
- echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
- cd ..
- npm install -g purplecabbage/cordova-paramedic
- npm install -g cordova-paramedic
- npm install -g cordova
- npm install -g ios-sim
script:
- cordova-paramedic --platform ios --plugin ../cordova-plugin-camera
- cordova-paramedic --platform ios --plugin ${TRAVIS_BUILD_DIR}
+2 -1
View File
@@ -256,7 +256,8 @@ Optional parameters to customize the camera settings.
- Any `cameraDirection` value results in a back-facing photo.
- Ignores the `allowEdit` parameter.
- Android also uses the Crop Activity for allowEdit, even though crop should work and actually pass the cropped image back to Cordova, the only one that works consistently is the one bundled
with the Google Plus Photos application. Other crops may not work.
- `Camera.PictureSourceType.PHOTOLIBRARY` and `Camera.PictureSourceType.SAVEDPHOTOALBUM` both display the same photo album.
+3 -3
View File
@@ -17,7 +17,7 @@
under the License.
-->
# org.apache.cordova.camera
# cordova-plugin-camera
Dieses Plugin definiert eine globale `navigator.camera`-Objekt, das eine API für Aufnahmen und für die Auswahl der Bilder aus dem System-Image-Library bietet.
@@ -31,7 +31,7 @@ Obwohl das Objekt mit der globalen Gültigkeitsbereich `navigator` verbunden ist
## Installation
cordova plugin add org.apache.cordova.camera
cordova plugin add cordova-plugin-camera
## navigator.camera.getPicture
@@ -431,4 +431,4 @@ Fortgeschrittene Image-Dateien, die in vorübergehender Verwahrung gehalten werd
function onFail(message) {
alert('Failed because: ' + message);
}
}
+3 -3
View File
@@ -17,7 +17,7 @@
under the License.
-->
# org.apache.cordova.camera
# cordova-plugin-camera
Este plugin define un global `navigator.camera` objeto que proporciona una API para tomar fotografías y por elegir imágenes de biblioteca de imágenes del sistema.
@@ -29,7 +29,7 @@ Aunque el objeto está unido al ámbito global `navigator` , no estará disponib
## Instalación
Cordova plugin agregar org.apache.cordova.camera
Cordova plugin agregar cordova-plugin-camera
## navigator.camera.getPicture
@@ -388,4 +388,4 @@ Elimina intermedio archivos de imagen que se mantienen en depósito temporal des
function onSuccess() {console.log ("cámara limpieza éxito.")}
function onFail(message) {alert (' falló porque: ' + mensaje);}
function onFail(message) {alert (' falló porque: ' + mensaje);}
+3 -3
View File
@@ -17,7 +17,7 @@
under the License.
-->
# org.apache.cordova.camera
# cordova-plugin-camera
Ce plugin définit un global `navigator.camera` objet qui fournit une API pour la prise de photos et de choisir des images de la bibliothèque d'images du système.
@@ -29,7 +29,7 @@ Bien que l'objet est attaché à la portée globale `navigator` , il n'est pas d
## Installation
Cordova plugin ajouter org.apache.cordova.camera
Cordova plugin ajouter cordova-plugin-camera
## navigator.camera.getPicture
@@ -388,4 +388,4 @@ Supprime les intermédiaires les fichiers image qui sont gardées en dépôt tem
fonction onSuccess() {console.log ("succès de caméra nettoyage.")}
function onFail(message) {alert (' a échoué car: "+ message);}
function onFail(message) {alert (' a échoué car: "+ message);}
+3 -3
View File
@@ -17,7 +17,7 @@
under the License.
-->
# org.apache.cordova.camera
# cordova-plugin-camera
Questo plugin definisce un oggetto globale `navigator.camera`, che fornisce un'API per scattare foto e per aver scelto immagini dalla libreria di immagini del sistema.
@@ -31,7 +31,7 @@ Anche se l'oggetto è associato con ambito globale del `navigator`, non è dispo
## Installazione
cordova plugin add org.apache.cordova.camera
cordova plugin add cordova-plugin-camera
## navigator.camera.getPicture
@@ -431,4 +431,4 @@ Rimuove i file di immagine intermedia che vengono tenuti in custodia temporanea
function onFail(message) {
alert('Failed because: ' + message);
}
}
+3 -3
View File
@@ -17,7 +17,7 @@
under the License.
-->
# org.apache.cordova.camera
# cordova-plugin-camera
このプラグインは、写真を撮るため、システムのイメージ ライブラリからイメージを選択するために API を提供します、グローバル `navigator.camera` オブジェクトを定義します。
@@ -31,7 +31,7 @@
## インストール
cordova plugin add org.apache.cordova.camera
cordova plugin add cordova-plugin-camera
## navigator.camera.getPicture
@@ -431,4 +431,4 @@ iOS だけ指定パラメーターをポップ オーバーのアンカー要素
function onFail(message) {
alert('Failed because: ' + message);
}
}
+3 -3
View File
@@ -17,7 +17,7 @@
under the License.
-->
# org.apache.cordova.camera
# cordova-plugin-camera
이 플러그인 시스템의 이미지 라이브러리에서 이미지를 선택 및 사진 촬영을 위한 API를 제공 하는 글로벌 `navigator.camera` 개체를 정의 합니다.
@@ -31,7 +31,7 @@
## 설치
cordova plugin add org.apache.cordova.camera
cordova plugin add cordova-plugin-camera
## navigator.camera.getPicture
@@ -431,4 +431,4 @@ iOS 전용 매개 변수 iPad의 보관 함 또는 앨범에서 이미지를 선
function onFail(message) {
alert('Failed because: ' + message);
}
}
+3 -3
View File
@@ -17,7 +17,7 @@
under the License.
-->
# org.apache.cordova.camera
# cordova-plugin-camera
Ten plugin definiuje obiekt globalny `navigator.camera`, który dostarcza API do robienia zdjęć i wybór zdjęć z biblioteki obrazów systemu.
@@ -31,7 +31,7 @@ Mimo, że obiekt jest dołączony do globalnego zakresu `navigator`, to nie dost
## Instalacja
cordova plugin add org.apache.cordova.camera
cordova plugin add cordova-plugin-camera
## navigator.camera.getPicture
@@ -431,4 +431,4 @@ Usuwa pliki obrazów pośrednich, które są przechowywane w pamięci tymczasowe
function onFail(message) {
alert('Failed because: ' + message);
}
}
+3 -3
View File
@@ -17,11 +17,11 @@
under the License.
-->
# org.apache.cordova.camera
# cordova-plugin-camera
Этот плагин предоставляет API для съемки и для выбора изображения из библиотеки изображений системы.
cordova plugin add org.apache.cordova.camera
cordova plugin add cordova-plugin-camera
## navigator.camera.getPicture
@@ -414,4 +414,4 @@ Tizen поддерживает только значение `destinationType`
function onFail(message) {
alert('Failed because: ' + message);
}
}
+3 -3
View File
@@ -17,7 +17,7 @@
under the License.
-->
# org.apache.cordova.camera
# cordova-plugin-camera
這個外掛程式定義了一個全球 `navigator.camera` 物件,它提供了 API,拍照,從系統的圖像庫中選擇圖像。
@@ -31,7 +31,7 @@
## 安裝
cordova plugin add org.apache.cordova.camera
cordova plugin add cordova-plugin-camera
## navigator.camera.getPicture
@@ -432,4 +432,4 @@ iOS 僅指定氣泡框的錨元素的位置和箭頭方向,從 iPad 庫或專
function onFail(message) {
alert('Failed because: ' + message);
}
}
+1 -10
View File
@@ -241,16 +241,7 @@
<!-- windows -->
<platform name="windows">
<config-file target="package.windows.appxmanifest" parent="/Package/Capabilities">
<Capability Name="picturesLibrary" />
<DeviceCapability Name="webcam" />
</config-file>
<config-file target="package.windows80.appxmanifest" parent="/Package/Capabilities">
<Capability Name="picturesLibrary" />
<DeviceCapability Name="webcam" />
</config-file>
<config-file target="package.phone.appxmanifest" parent="/Package/Capabilities">
<Capability Name="picturesLibrary" />
<config-file target="package.appxmanifest" parent="/Package/Capabilities">
<DeviceCapability Name="webcam" />
</config-file>
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
+119 -55
View File
@@ -25,11 +25,15 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Date;
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;
@@ -50,7 +54,7 @@ import android.os.Environment;
import android.provider.MediaStore;
import android.util.Base64;
import android.util.Log;
import android.content.pm.PackageManager;
/**
* This class launches the camera view, allows the user to take a picture, closes the camera view,
* and returns the captured image. When the camera view is closed, the screen displayed before
@@ -77,6 +81,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
private static final String GET_All = "Get All";
private static final String LOG_TAG = "CameraLauncher";
//Where did this come from?
private static final int CROP_CAMERA = 100;
private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
@@ -203,8 +209,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// Save the number of images currently on disk for later
this.numPics = queryImgDB(whichContentStore()).getCount();
// Display camera
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
// Let's use the intent and see what happens
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Specify file so that large image is captured and returned
File photo = createCaptureFile(encodingType);
@@ -212,7 +218,17 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
this.imageUri = Uri.fromFile(photo);
if (this.cordova != null) {
this.cordova.startActivityForResult((CordovaPlugin) this, intent, (CAMERA + 1) * 16 + returnType + 1);
// Let's check to make sure the camera is actually installed. (Legacy Nexus 7 code)
PackageManager mPm = this.cordova.getActivity().getPackageManager();
if(intent.resolveActivity(mPm) != null)
{
this.cordova.startActivityForResult((CordovaPlugin) this, intent, (CAMERA + 1) * 16 + returnType + 1);
}
else
{
LOG.d(LOG_TAG, "Error: You don't have a default camera. Your device may not be CTS complaint.");
}
}
// else
// LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
@@ -236,6 +252,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
return photo;
}
/**
* Get image from photo library.
*
@@ -296,13 +314,14 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
*
* @param picUri
*/
private void performCrop(Uri picUri) {
private void performCrop(Uri picUri, int destType, Intent cameraIntent) {
try {
Intent cropIntent = new Intent("com.android.camera.action.CROP");
// indicate image type and Uri
cropIntent.setDataAndType(picUri, "image/*");
// set crop properties
cropIntent.putExtra("crop", "true");
// indicate output X and Y
if (targetWidth > 0) {
cropIntent.putExtra("outputX", targetWidth);
@@ -322,12 +341,18 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
if (this.cordova != null) {
this.cordova.startActivityForResult((CordovaPlugin) this,
cropIntent, CROP_CAMERA);
cropIntent, CROP_CAMERA + destType);
}
} catch (ActivityNotFoundException anfe) {
Log.e(LOG_TAG, "Crop operation not supported on this device");
// Send Uri back to JavaScript for viewing image
this.callbackContext.success(picUri.toString());
try {
processResultFromCamera(destType, cameraIntent);
}
catch (IOException e)
{
e.printStackTrace();
Log.e(LOG_TAG, "Unable to write to file");
}
}
}
@@ -342,16 +367,22 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// Create an ExifHelper to save the exif data that is lost during compression
ExifHelper exif = new ExifHelper();
String sourcePath;
try {
if (this.encodingType == JPEG) {
exif.createInFile(getTempDirectoryPath() + "/.Pic.jpg");
exif.readExifData();
rotate = exif.getOrientation();
} else if (this.encodingType == PNG) {
exif.createInFile(getTempDirectoryPath() + "/.Pic.png");
exif.readExifData();
rotate = exif.getOrientation();
if(allowEdit && croppedUri != null)
{
sourcePath = FileHelper.stripFileProtocol(croppedUri.toString());
}
else
{
sourcePath = getTempDirectoryPath() + "/.Pic.jpg";
}
//We don't support PNG, so let's not pretend we do
exif.createInFile(getTempDirectoryPath() + "/.Pic.jpg");
exif.readExifData();
rotate = exif.getOrientation();
} catch (IOException e) {
e.printStackTrace();
}
@@ -361,7 +392,13 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// If sending base64 image back
if (destType == DATA_URL) {
bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString()));
if(croppedUri != null) {
bitmap = getScaledBitmap(FileHelper.stripFileProtocol(croppedUri.toString()));
}
else
{
bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString()));
}
if (bitmap == null) {
// Try to get the bitmap from intent.
bitmap = (Bitmap)intent.getExtras().get("data");
@@ -384,14 +421,11 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// If sending filename back
else if (destType == FILE_URI || destType == NATIVE_URI) {
uri = Uri.fromFile(new File(getTempDirectoryPath(), System.currentTimeMillis() + ".jpg"));
if (this.saveToPhotoAlbum) {
Uri inputUri = getUriFromMediaStore();
try {
//Just because we have a media URI doesn't mean we have a real file, we need to make it
uri = Uri.fromFile(new File(FileHelper.getRealPath(inputUri, this.cordova)));
} catch (NullPointerException e) {
uri = null;
}
//Create a URI on the filesystem so that we can write the file.
uri = Uri.fromFile(new File(getPicutresPath()));
} else {
uri = Uri.fromFile(new File(getTempDirectoryPath(), System.currentTimeMillis() + ".jpg"));
}
@@ -422,20 +456,20 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// Restore exif data to file
if (this.encodingType == JPEG) {
String exifPath;
if (this.saveToPhotoAlbum) {
exifPath = FileHelper.getRealPath(uri, this.cordova);
} else {
exifPath = uri.getPath();
}
exifPath = uri.getPath();
exif.createOutFile(exifPath);
exif.writeExifData();
}
if (this.allowEdit) {
performCrop(uri);
} else {
// Send Uri back to JavaScript for viewing image
this.callbackContext.success(uri.toString());
//Broadcast change to File System on MediaStore
if(this.saveToPhotoAlbum) {
refreshGallery(uri);
}
// Send Uri back to JavaScript for viewing image
this.callbackContext.success(uri.toString());
}
} else {
throw new IllegalStateException();
@@ -445,6 +479,24 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
bitmap = null;
}
private String getPicutresPath()
{
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "IMG_" + timeStamp + ".jpg";
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
String galleryPath = storageDir.getAbsolutePath() + "/" + imageFileName;
return galleryPath;
}
private void refreshGallery(Uri contentUri)
{
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(contentUri);
this.cordova.getActivity().sendBroadcast(mediaScanIntent);
}
private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
// Create an ExifHelper to save the exif data that is lost during compression
String modifiedPath = getTempDirectoryPath() + "/modified.jpg";
@@ -580,34 +632,47 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
*/
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
// Get src and dest types from request code
// Get src and dest types from request code for a Camera Activity
int srcType = (requestCode / 16) - 1;
int destType = (requestCode % 16) - 1;
// if camera crop
if (requestCode == CROP_CAMERA) {
if (resultCode == Activity.RESULT_OK) {
// // Send Uri back to JavaScript for viewing image
this.callbackContext
.success(croppedUri.toString());
croppedUri = null;
}// If cancelled
else if (resultCode == Activity.RESULT_CANCELED) {
this.failPicture("Camera cancelled.");
}
// If something else
else {
this.failPicture("Did not complete!");
}
// If Camera Crop
if (requestCode >= CROP_CAMERA) {
if (resultCode == Activity.RESULT_OK) {
}
// Because of the inability to pass through multiple intents, this hack will allow us
// to pass arcane codes back.
destType = requestCode - CROP_CAMERA;
try {
processResultFromCamera(destType, intent);
} catch (IOException e) {
e.printStackTrace();
Log.e(LOG_TAG, "Unable to write to file");
}
}// If cancelled
else if (resultCode == Activity.RESULT_CANCELED) {
this.failPicture("Camera cancelled.");
}
// If something else
else {
this.failPicture("Did not complete!");
}
}
// If CAMERA
if (srcType == CAMERA) {
else if (srcType == CAMERA) {
// If image available
if (resultCode == Activity.RESULT_OK) {
try {
this.processResultFromCamera(destType, intent);
if(this.allowEdit)
{
Uri tmpFile = Uri.fromFile(new File(getTempDirectoryPath(), ".Pic.jpg"));
performCrop(tmpFile, destType, intent);
}
else {
this.processResultFromCamera(destType, intent);
}
} catch (IOException e) {
e.printStackTrace();
this.failPicture("Error capturing image.");
@@ -624,7 +689,6 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
this.failPicture("Did not complete!");
}
}
// If retrieving photo from library
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
if (resultCode == Activity.RESULT_OK && intent != null) {
+1 -1
View File
@@ -185,7 +185,7 @@ static NSString* toBase64(NSData* data) {
{
NSInteger value = defaultValue;
NSNumber* val = [self valueForKey:key]; // value is an NSNumber
NSNumber* val = [dict valueForKey:key]; // value is an NSNumber
if (val != nil) {
value = [val integerValue];
+463 -390
View File
@@ -19,11 +19,11 @@
*
*/
/*global Windows:true, URL:true */
/*jshint unused:true, undef:true, browser:true */
/*global Windows:true, URL:true, module:true, require:true */
var cordova = require('cordova'),
Camera = require('./Camera');
var Camera = require('./Camera');
module.exports = {
@@ -43,399 +43,472 @@ module.exports = {
// 11 cameraDirection:0
takePicture: function (successCallback, errorCallback, args) {
var encodingType = args[5];
var targetWidth = args[3];
var targetHeight = args[4];
var sourceType = args[2];
var destinationType = args[1];
var mediaType = args[6];
var allowCrop = !!args[7];
var saveToPhotoAlbum = args[9];
var cameraDirection = args[11];
// resize method :)
var resizeImage = function (file) {
var tempPhotoFileName = "";
if (encodingType == Camera.EncodingType.PNG) {
tempPhotoFileName = "camera_cordova_temp_return.png";
} else {
tempPhotoFileName = "camera_cordova_temp_return.jpg";
}
var storageFolder = Windows.Storage.ApplicationData.current.localFolder;
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).then(function (storageFile) {
Windows.Storage.FileIO.readBufferAsync(storageFile).then(function(buffer) {
var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
var imageData = "data:" + file.contentType + ";base64," + strBase64;
var image = new Image();
image.src = imageData;
image.onload = function() {
var imageWidth = targetWidth,
imageHeight = targetHeight;
var canvas = document.createElement('canvas');
canvas.width = imageWidth;
canvas.height = imageHeight;
canvas.getContext("2d").drawImage(this, 0, 0, imageWidth, imageHeight);
var fileContent = canvas.toDataURL(file.contentType).split(',')[1];
var storageFolder = Windows.Storage.ApplicationData.current.localFolder;
storageFolder.createFileAsync(tempPhotoFileName, Windows.Storage.CreationCollisionOption.generateUniqueName).done(function (storagefile) {
var content = Windows.Security.Cryptography.CryptographicBuffer.decodeFromBase64String(fileContent);
Windows.Storage.FileIO.writeBufferAsync(storagefile, content).then(function () {
successCallback("ms-appdata:///local/" + storagefile.name);
}, function () {
errorCallback("Resize picture error.");
});
});
};
});
}, function () {
errorCallback("Can't access localStorage folder");
});
};
// because of asynchronous method, so let the successCallback be called in it.
var resizeImageBase64 = function (file) {
Windows.Storage.FileIO.readBufferAsync(file).done( function(buffer) {
var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
var imageData = "data:" + file.contentType + ";base64," + strBase64;
var image = new Image();
image.src = imageData;
image.onload = function() {
var imageWidth = targetWidth,
imageHeight = targetHeight;
var canvas = document.createElement('canvas');
canvas.width = imageWidth;
canvas.height = imageHeight;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0, imageWidth, imageHeight);
// The resized file ready for upload
var finalFile = canvas.toDataURL(file.contentType);
// Remove the prefix such as "data:" + contentType + ";base64," , in order to meet the Cordova API.
var arr = finalFile.split(",");
var newStr = finalFile.substr(arr[0].length + 1);
successCallback(newStr);
};
});
};
if (sourceType != Camera.PictureSourceType.CAMERA) {
// 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;
}
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"]);
}
else if (mediaType == Camera.MediaType.VIDEO) {
fileOpenPicker.fileTypeFilter.replaceAll([".avi", ".flv", ".asx", ".asf", ".mov", ".mp4", ".mpg", ".rm", ".srt", ".swf", ".wmv", ".vob"]);
}
else {
fileOpenPicker.fileTypeFilter.replaceAll(["*"]);
}
fileOpenPicker.pickSingleFileAsync().done(function (file) {
if (file) {
if (destinationType == Camera.DestinationType.FILE_URI || destinationType == Camera.DestinationType.NATIVE_URI) {
if (targetHeight > 0 && targetWidth > 0) {
resizeImage(file);
}
else {
var storageFolder = Windows.Storage.ApplicationData.current.localFolder;
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).then(function (storageFile) {
successCallback(URL.createObjectURL(storageFile));
}, function () {
errorCallback("Can't access localStorage folder.");
});
}
}
else {
if (targetHeight > 0 && targetWidth > 0) {
resizeImageBase64(file);
} else {
Windows.Storage.FileIO.readBufferAsync(file).done(function (buffer) {
var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
successCallback(strBase64);
});
}
}
} else {
errorCallback("User didn't choose a file.");
}
}, function () {
errorCallback("User didn't choose a file.");
});
takePictureFromFile(successCallback, errorCallback, args);
} else {
var CaptureNS = Windows.Media.Capture;
// Check if necessary API available
if (!CaptureNS.CameraCaptureUI) {
// We are running on WP8.1 which lacks CameraCaptureUI class
// so we need to use MediaCapture class instead and implement custom UI for camera
var capturePreview = null,
captureCancelButton = null,
capture = null,
captureSettings = null;
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";
// 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";
capture = new CaptureNS.MediaCapture();
captureSettings = new CaptureNS.MediaCaptureInitializationSettings();
captureSettings.streamingCaptureMode = CaptureNS.StreamingCaptureMode.video;
};
var startCameraPreview = function () {
// Search for available camera devices
// This is necessary to detect which camera (front or back) we should use
var expectedPanel = cameraDirection === 1 ? Windows.Devices.Enumeration.Panel.front : Windows.Devices.Enumeration.Panel.back;
Windows.Devices.Enumeration.DeviceInformation.findAllAsync(Windows.Devices.Enumeration.DeviceClass.videoCapture)
.done(function (devices) {
if (devices.length > 0) {
devices.forEach(function(currDev) {
if (currDev.enclosureLocation.panel && currDev.enclosureLocation.panel == expectedPanel) {
captureSettings.videoDeviceId = currDev.id;
}
});
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);
capturePreview.play();
// Insert preview frame and controls into page
document.body.appendChild(capturePreview);
document.body.appendChild(captureCancelButton);
// Bind events to controls
capturePreview.addEventListener('click', captureAction);
captureCancelButton.addEventListener('click', function () {
destroyCameraPreview();
errorCallback('Cancelled');
}, false);
}, function (err) {
destroyCameraPreview();
errorCallback('Camera intitialization error ' + err);
});
} else {
destroyCameraPreview();
errorCallback('Camera not found');
}
});
};
var destroyCameraPreview = function () {
capturePreview.pause();
capturePreview.src = null;
[capturePreview, captureCancelButton].forEach(function(elem) {
if (elem /* && elem in document.body.childNodes */) {
document.body.removeChild(elem);
}
});
if (capture) {
capture.stopRecordAsync();
capture = null;
}
};
var captureAction = function () {
var encodingProperties,
fileName,
generateUniqueCollisionOption = Windows.Storage.CreationCollisionOption.generateUniqueName,
tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder;
if (encodingType == Camera.EncodingType.PNG) {
fileName = 'photo.png';
encodingProperties = Windows.Media.MediaProperties.ImageEncodingProperties.createPng();
} else {
fileName = 'photo.jpg';
encodingProperties = Windows.Media.MediaProperties.ImageEncodingProperties.createJpeg();
}
tempFolder.createFileAsync(fileName, generateUniqueCollisionOption).done(function(capturedFile) {
capture.capturePhotoToStorageFileAsync(encodingProperties, capturedFile).done(function() {
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(capturedfile);
} 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(capturedfile);
} 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) {
console.error(err);
successCallback(strBase64);
});
}, errorCallback);
}
}
};
if (saveToPhotoAlbum) {
capturedFile.copyAsync(Windows.Storage.KnownFolders.picturesLibrary, capturedFile.name, generateUniqueCollisionOption)
.done(function() {
success(capturedFile);
}, errorCallback);
} else {
success(capturedFile);
}
}, function(err) {
destroyCameraPreview();
errorCallback(err);
});
}, function(err) {
destroyCameraPreview();
errorCallback(err);
});
};
try {
createCameraUI();
startCameraPreview();
} catch (ex) {
errorCallback(ex);
}
} else {
var cameraCaptureUI = new Windows.Media.Capture.CameraCaptureUI();
cameraCaptureUI.photoSettings.allowCropping = allowCrop;
if (encodingType == Camera.EncodingType.PNG) {
cameraCaptureUI.photoSettings.format = Windows.Media.Capture.CameraCaptureUIPhotoFormat.png;
} else {
cameraCaptureUI.photoSettings.format = Windows.Media.Capture.CameraCaptureUIPhotoFormat.jpeg;
}
// decide which max pixels should be supported by targetWidth or targetHeight.
if (targetWidth >= 1280 || targetHeight >= 960) {
cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.large3M;
} else if (targetWidth >= 1024 || targetHeight >= 768) {
cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.mediumXga;
} else if (targetWidth >= 800 || targetHeight >= 600) {
cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.mediumXga;
} else if (targetWidth >= 640 || targetHeight >= 480) {
cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.smallVga;
} else if (targetWidth >= 320 || targetHeight >= 240) {
cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.verySmallQvga;
} else {
cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.highestAvailable;
}
cameraCaptureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo).then(function(picture) {
if (picture) {
// save to photo album successCallback
var success = function() {
if (destinationType == Camera.DestinationType.FILE_URI) {
if (targetHeight > 0 && targetWidth > 0) {
resizeImage(picture);
} else {
var storageFolder = Windows.Storage.ApplicationData.current.localFolder;
picture.copyAsync(storageFolder, picture.name, Windows.Storage.NameCollisionOption.replaceExisting).then(function(storageFile) {
successCallback("ms-appdata:///local/" + storageFile.name);
}, function() {
errorCallback("Can't access localStorage folder.");
});
}
} else {
if (targetHeight > 0 && targetWidth > 0) {
resizeImageBase64(picture);
} else {
Windows.Storage.FileIO.readBufferAsync(picture).done(function(buffer) {
var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
successCallback(strBase64);
});
}
}
};
// save to photo album errorCallback
var fail = function() {
//errorCallback("FileError, code:" + fileError.code);
errorCallback("Save fail.");
};
if (saveToPhotoAlbum) {
Windows.Storage.StorageFile.getFileFromPathAsync(picture.path).then(function(storageFile) {
storageFile.copyAsync(Windows.Storage.KnownFolders.picturesLibrary, picture.name, Windows.Storage.NameCollisionOption.generateUniqueName).then(function(storageFile) {
success();
}, function() {
fail();
});
});
} else {
success();
}
} else {
errorCallback("User didn't capture a photo.");
}
}, function() {
errorCallback("Fail to capture a photo.");
});
}
takePictureFromCamera(successCallback, errorCallback, args);
}
}
};
// Resize method
function resizeImage(successCallback, errorCallback, file, targetWidth, targetHeight, encodingType) {
var tempPhotoFileName = "";
if (encodingType == Camera.EncodingType.PNG) {
tempPhotoFileName = "camera_cordova_temp_return.png";
} else {
tempPhotoFileName = "camera_cordova_temp_return.jpg";
}
var storageFolder = Windows.Storage.ApplicationData.current.localFolder;
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting)
.then(function (storageFile) { return Windows.Storage.FileIO.readBufferAsync(storageFile); })
.then(function(buffer) {
var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
var imageData = "data:" + file.contentType + ";base64," + strBase64;
var image = new Image();
image.src = imageData;
image.onload = function() {
var imageWidth = targetWidth,
imageHeight = targetHeight;
var canvas = document.createElement('canvas');
var storageFileName;
canvas.width = imageWidth;
canvas.height = imageHeight;
canvas.getContext("2d").drawImage(this, 0, 0, imageWidth, imageHeight);
var fileContent = canvas.toDataURL(file.contentType).split(',')[1];
var storageFolder = Windows.Storage.ApplicationData.current.localFolder;
storageFolder.createFileAsync(tempPhotoFileName, Windows.Storage.CreationCollisionOption.generateUniqueName)
.then(function (storagefile) {
var content = Windows.Security.Cryptography.CryptographicBuffer.decodeFromBase64String(fileContent);
storageFileName = storagefile.name;
return Windows.Storage.FileIO.writeBufferAsync(storagefile, content);
})
.done(function () {
successCallback("ms-appdata:///local/" + storageFileName);
}, errorCallback);
};
})
.done(null, function(err) {
errorCallback(err);
}
);
}
// Because of asynchronous method, so let the successCallback be called in it.
function resizeImageBase64(successCallback, errorCallback, file, targetWidth, targetHeight) {
Windows.Storage.FileIO.readBufferAsync(file).done( function(buffer) {
var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
var imageData = "data:" + file.contentType + ";base64," + strBase64;
var image = new Image();
image.src = imageData;
image.onload = function() {
var imageWidth = targetWidth,
imageHeight = targetHeight;
var canvas = document.createElement('canvas');
canvas.width = imageWidth;
canvas.height = imageHeight;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0, imageWidth, imageHeight);
// The resized file ready for upload
var finalFile = canvas.toDataURL(file.contentType);
// Remove the prefix such as "data:" + contentType + ";base64," , in order to meet the Cordova API.
var arr = finalFile.split(",");
var newStr = finalFile.substr(arr[0].length + 1);
successCallback(newStr);
};
}, 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;
}
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"]);
}
else if (mediaType == Camera.MediaType.VIDEO) {
fileOpenPicker.fileTypeFilter.replaceAll([".avi", ".flv", ".asx", ".asf", ".mov", ".mp4", ".mpg", ".rm", ".srt", ".swf", ".wmv", ".vob"]);
}
else {
fileOpenPicker.fileTypeFilter.replaceAll(["*"]);
}
fileOpenPicker.pickSingleFileAsync().done(function (file) {
if (!file) {
errorCallback("User didn't choose a file.");
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);
}
}
}, function () {
errorCallback("User didn't choose a file.");
});
}
function takePictureFromCamera(successCallback, errorCallback, args) {
// Check if necessary API available
if (!Windows.Media.Capture.CameraCaptureUI) {
takePictureFromCameraWP(successCallback, errorCallback, args);
} else {
takePictureFromCameraWindows(successCallback, errorCallback, args);
}
}
function takePictureFromCameraWP(successCallback, errorCallback, args) {
// We are running on WP8.1 which lacks CameraCaptureUI class
// so we need to use MediaCapture class instead and implement custom UI for camera
var destinationType = args[1],
targetWidth = args[3],
targetHeight = args[4],
encodingType = args[5],
saveToPhotoAlbum = args[9],
cameraDirection = args[11],
capturePreview = null,
captureCancelButton = null,
capture = null,
captureSettings = null,
CaptureNS = Windows.Media.Capture;
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";
// 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";
capture = new CaptureNS.MediaCapture();
captureSettings = new CaptureNS.MediaCaptureInitializationSettings();
captureSettings.streamingCaptureMode = CaptureNS.StreamingCaptureMode.video;
};
var startCameraPreview = function () {
// Search for available camera devices
// This is necessary to detect which camera (front or back) we should use
var expectedPanel = cameraDirection === 1 ? Windows.Devices.Enumeration.Panel.front : Windows.Devices.Enumeration.Panel.back;
Windows.Devices.Enumeration.DeviceInformation.findAllAsync(Windows.Devices.Enumeration.DeviceClass.videoCapture)
.done(function (devices) {
if (devices.length <= 0) {
destroyCameraPreview();
errorCallback('Camera not found');
return;
}
devices.forEach(function(currDev) {
if (currDev.enclosureLocation.panel && currDev.enclosureLocation.panel == expectedPanel) {
captureSettings.videoDeviceId = currDev.id;
}
});
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);
capturePreview.play();
// Insert preview frame and controls into page
document.body.appendChild(capturePreview);
document.body.appendChild(captureCancelButton);
// Bind events to controls
capturePreview.addEventListener('click', captureAction);
captureCancelButton.addEventListener('click', function () {
destroyCameraPreview();
errorCallback('Cancelled');
}, false);
}, function (err) {
destroyCameraPreview();
errorCallback('Camera intitialization error ' + err);
});
}, errorCallback);
};
var destroyCameraPreview = function () {
capturePreview.pause();
capturePreview.src = null;
[capturePreview, captureCancelButton].forEach(function(elem) {
if (elem /* && elem in document.body.childNodes */) {
document.body.removeChild(elem);
}
});
if (capture) {
capture.stopRecordAsync();
capture = null;
}
};
var captureAction = function () {
var encodingProperties,
fileName,
generateUniqueCollisionOption = Windows.Storage.CreationCollisionOption.generateUniqueName,
tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder,
capturedFile;
if (encodingType == Camera.EncodingType.PNG) {
fileName = 'photo.png';
encodingProperties = Windows.Media.MediaProperties.ImageEncodingProperties.createPng();
} else {
fileName = 'photo.jpg';
encodingProperties = Windows.Media.MediaProperties.ImageEncodingProperties.createJpeg();
}
tempFolder.createFileAsync(fileName, generateUniqueCollisionOption)
.then(function(tempCapturedFile) {
capturedFile = tempCapturedFile;
return capture.capturePhotoToStorageFileAsync(encodingProperties, capturedFile);
})
.done(function() {
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();
}, function(err) {
destroyCameraPreview();
errorCallback(err);
});
};
try {
createCameraUI();
startCameraPreview();
} catch (ex) {
errorCallback(ex);
}
}
function takePictureFromCameraWindows(successCallback, errorCallback, args) {
var destinationType = args[1],
targetWidth = args[3],
targetHeight = args[4],
encodingType = args[5],
allowCrop = !!args[7],
saveToPhotoAlbum = args[9],
cameraCaptureUI = new Windows.Media.Capture.CameraCaptureUI();
cameraCaptureUI.photoSettings.allowCropping = allowCrop;
if (encodingType == Camera.EncodingType.PNG) {
cameraCaptureUI.photoSettings.format = Windows.Media.Capture.CameraCaptureUIPhotoFormat.png;
} else {
cameraCaptureUI.photoSettings.format = Windows.Media.Capture.CameraCaptureUIPhotoFormat.jpeg;
}
// decide which max pixels should be supported by targetWidth or targetHeight.
if (targetWidth >= 1280 || targetHeight >= 960) {
cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.large3M;
} else if (targetWidth >= 1024 || targetHeight >= 768) {
cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.mediumXga;
} else if (targetWidth >= 800 || targetHeight >= 600) {
cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.mediumXga;
} else if (targetWidth >= 640 || targetHeight >= 480) {
cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.smallVga;
} else if (targetWidth >= 320 || targetHeight >= 240) {
cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.verySmallQvga;
} else {
cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.highestAvailable;
}
cameraCaptureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo).done(function(picture) {
if (!picture) {
errorCallback("User didn't capture a photo.");
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);
}
} 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);
successCallback(strBase64);
}, errorCallback);
}
}
};
// 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 {
savePicker.fileTypeChoices.insert("JPEG", [".jpg"]);
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();
}
}, fail);
}, function() {
errorCallback("Fail to capture a photo.");
});
}
require("cordova/exec/proxy").add("Camera",module.exports);