[ https://issues.apache.org/jira/browse/CB-8706?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14386471#comment-14386471 ]
ASF GitHub Bot commented on CB-8706: ------------------------------------ Github user vladimir-kotikov commented on a diff in the pull request: https://github.com/apache/cordova-plugin-camera/pull/78#discussion_r27377337 --- Diff: src/windows/CameraProxy.js --- @@ -43,399 +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; + if (sourceType != Camera.PictureSourceType.CAMERA) { + takePictureFromFile(successCallback, errorCallback, args); + } else { + takePictureFromCamera(successCallback, errorCallback, args); + } + } +}; - 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"); - }); - }; +// 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"; + } - // because of asynchronous method, so let the successCallback be called in it. - var resizeImageBase64 = function (file) { + 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); + } + ); +} - Windows.Storage.FileIO.readBufferAsync(file).done( function(buffer) { - var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer); - var imageData = "data:" + file.contentType + ";base64," + strBase64; +// 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; + var image = new Image(); + image.src = imageData; - image.onload = function() { - var imageWidth = targetWidth, - imageHeight = targetHeight; - var canvas = document.createElement('canvas'); + image.onload = function() { + var imageWidth = targetWidth, + imageHeight = targetHeight; + var canvas = document.createElement('canvas'); - canvas.width = imageWidth; - canvas.height = imageHeight; + canvas.width = imageWidth; + canvas.height = imageHeight; - var ctx = canvas.getContext("2d"); - ctx.drawImage(this, 0, 0, imageWidth, 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); + // 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); - }; - }); + // 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; + } - if (sourceType != Camera.PictureSourceType.CAMERA) { + 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(["*"]); + } - // 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; - } + 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."); + }); - 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); - }); - } - - } - + if (targetHeight > 0 && targetWidth > 0) { + resizeImageBase64(successCallback, errorCallback, file, targetWidth, targetHeight); } else { - errorCallback("User didn't choose a file."); + 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."); - }); - + } } 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; + } + }); - 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"); + 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; + } + }; - // 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"; + var captureAction = function () { - // 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"; + var encodingProperties, + fileName, + generateUniqueCollisionOption = Windows.Storage.CreationCollisionOption.generateUniqueName, + tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder, + capturedFile; - capture = new CaptureNS.MediaCapture(); + if (encodingType == Camera.EncodingType.PNG) { + fileName = 'photo.png'; + encodingProperties = Windows.Media.MediaProperties.ImageEncodingProperties.createPng(); + } else { + fileName = 'photo.jpg'; + encodingProperties = Windows.Media.MediaProperties.ImageEncodingProperties.createJpeg(); + } - captureSettings = new CaptureNS.MediaCaptureInitializationSettings(); - captureSettings.streamingCaptureMode = CaptureNS.StreamingCaptureMode.video; - }; + tempFolder.createFileAsync(fileName, generateUniqueCollisionOption) + .then(function(tempCapturedFile) { + capturedFile = tempCapturedFile; + return capture.capturePhotoToStorageFileAsync(encodingProperties, capturedFile); + }) + .done(function() { + destroyCameraPreview(); - 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); - }); + // 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 { - destroyCameraPreview(); - errorCallback('Camera not found'); + capturedfile.copyAsync(Windows.Storage.ApplicationData.current.localFolder, capturedfile.name, generateUniqueCollisionOption).done(function(copiedfile) { + successCallback("ms-appdata:///local/" + copiedfile.name); + }, 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); + } 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 (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); + if (saveToPhotoAlbum) { --- End diff -- Consider invert `if` statement to remove extra nesting. > Camera should use filepicker if saveToPhotoAlbum is true > -------------------------------------------------------- > > Key: CB-8706 > URL: https://issues.apache.org/jira/browse/CB-8706 > Project: Apache Cordova > Issue Type: Bug > Components: Plugin Camera > Reporter: Murat Sutunc > Assignee: Murat Sutunc > Priority: Minor > > Currently camera plugin is saving pictures programmatically to pictures > library. It should use filePicker to not require unnecessary capabilities. -- This message was sent by Atlassian JIRA (v6.3.4#6332) --------------------------------------------------------------------- To unsubscribe, e-mail: issues-unsubscr...@cordova.apache.org For additional commands, e-mail: issues-h...@cordova.apache.org