From b8a700215af0f5b217c91c6d5380da716d09dabd Mon Sep 17 00:00:00 2001 From: Murat Sutunc Date: Mon, 16 Feb 2015 15:32:10 -0800 Subject: [PATCH 1/4] CB-8706 remove unnecessary capabilities from xml --- plugin.xml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/plugin.xml b/plugin.xml index 8a2cf78..637b48d 100644 --- a/plugin.xml +++ b/plugin.xml @@ -241,16 +241,7 @@ - - - - - - - - - - + From 5ef04e552c1b1ca3914fe56c83cc6956c11a81b8 Mon Sep 17 00:00:00 2001 From: Murat Sutunc Date: Tue, 17 Feb 2015 15:09:33 -0800 Subject: [PATCH 2/4] CB-8706 use filePicker if saveToPhotoAlbum is true --- src/windows/CameraProxy.js | 90 +++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 11 deletions(-) diff --git a/src/windows/CameraProxy.js b/src/windows/CameraProxy.js index 0924e5c..d8b8e9e 100644 --- a/src/windows/CameraProxy.js +++ b/src/windows/CameraProxy.js @@ -190,7 +190,6 @@ module.exports = { }, function () { errorCallback("User didn't choose a file."); }); - } else { var CaptureNS = Windows.Media.Capture; @@ -331,10 +330,49 @@ module.exports = { }; if (saveToPhotoAlbum) { - capturedFile.copyAsync(Windows.Storage.KnownFolders.picturesLibrary, capturedFile.name, generateUniqueCollisionOption) - .done(function() { - success(capturedFile); - }, errorCallback); + /* + 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 + */ + function cameraActivationHandler(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(); } else { success(capturedFile); } @@ -417,13 +455,43 @@ module.exports = { }; 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(); + 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() + .then(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(); + } + }, function() { + fail(); + } + ); + } else { + fail(); + } }); - }); } else { success(); } From 29c9ea387d24c2a4d5558a3af8f9de219c98bb9f Mon Sep 17 00:00:00 2001 From: Murat Sutunc Date: Tue, 17 Mar 2015 17:16:38 -0700 Subject: [PATCH 3/4] CB-8707 refactoring windows code to improve readability --- src/windows/CameraProxy.js | 917 +++++++++++++++++++------------------ 1 file changed, 459 insertions(+), 458 deletions(-) diff --git a/src/windows/CameraProxy.js b/src/windows/CameraProxy.js index d8b8e9e..aa2e391 100644 --- a/src/windows/CameraProxy.js +++ b/src/windows/CameraProxy.js @@ -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,467 +43,468 @@ 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) { - /* - 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 - */ - function cameraActivationHandler(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(); - } 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) { - 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() - .then(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(); - } - }, function() { - fail(); - } - ); - } else { - 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) { + 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); + } + } + } else { + errorCallback("User didn't choose a file."); + } + }, 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) { + 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'); + } + }, 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) { + /* + 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(); + } else { + success(capturedFile); + } + }, 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) { + // 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) { + 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); + } else { + success(); + } + } else { + errorCallback("User didn't capture a photo."); + } + }, function() { + errorCallback("Fail to capture a photo."); + }); +} + require("cordova/exec/proxy").add("Camera",module.exports); From 9e11ab4dfb03222b3da57632c6ae9fb6fee9f826 Mon Sep 17 00:00:00 2001 From: Murat Sutunc Date: Fri, 3 Apr 2015 11:08:00 -0700 Subject: [PATCH 4/4] CR fixes --- src/windows/CameraProxy.js | 336 +++++++++++++++++++------------------ 1 file changed, 170 insertions(+), 166 deletions(-) diff --git a/src/windows/CameraProxy.js b/src/windows/CameraProxy.js index aa2e391..3d4d24b 100644 --- a/src/windows/CameraProxy.js +++ b/src/windows/CameraProxy.js @@ -158,33 +158,33 @@ function takePictureFromFile(successCallback, errorCallback, mediaType, destinat } fileOpenPicker.pickSingleFileAsync().done(function (file) { - if (file) { - 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."); - }); - - } + 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 { - 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); - } + 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); } - } else { - errorCallback("User didn't choose a file."); } }, function () { errorCallback("User didn't choose a file."); @@ -240,40 +240,41 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) { 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 { + 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); }; @@ -341,51 +342,52 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) { } }; - if (saveToPhotoAlbum) { - /* - 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(); - } else { + 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); @@ -432,76 +434,78 @@ function takePictureFromCameraWindows(successCallback, errorCallback, args) { } cameraCaptureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo).done(function(picture) { - if (picture) { - // 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) { - 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); - } else { - success(); - } - } else { + 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."); });