diff --git a/plugin.xml b/plugin.xml index 80e4c34..ec14190 100644 --- a/plugin.xml +++ b/plugin.xml @@ -71,7 +71,7 @@ id="org.apache.cordova.core.CameraLauncher" - + @@ -86,7 +86,7 @@ id="org.apache.cordova.core.CameraLauncher" - + diff --git a/src/wp7/Camera.cs b/src/wp/Camera.cs similarity index 100% rename from src/wp7/Camera.cs rename to src/wp/Camera.cs diff --git a/src/wp8/Camera.cs b/src/wp8/Camera.cs deleted file mode 100644 index 5ff8045..0000000 --- a/src/wp8/Camera.cs +++ /dev/null @@ -1,490 +0,0 @@ -/* - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -using System; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Collections.Generic; -using Microsoft.Phone.Tasks; -using System.Runtime.Serialization; -using System.IO; -using System.IO.IsolatedStorage; -using System.Windows.Media.Imaging; -using Microsoft.Phone; -using Microsoft.Xna.Framework.Media; -using System.Diagnostics; - -namespace WPCordovaClassLib.Cordova.Commands -{ - public class Camera : BaseCommand - { - - /// - /// Return base64 encoded string - /// - private const int DATA_URL = 0; - - /// - /// Return file uri - /// - private const int FILE_URI = 1; - - /// - /// Choose image from picture library - /// - private const int PHOTOLIBRARY = 0; - - /// - /// Take picture from camera - /// - - private const int CAMERA = 1; - - /// - /// Choose image from picture library - /// - private const int SAVEDPHOTOALBUM = 2; - - /// - /// Take a picture of type JPEG - /// - private const int JPEG = 0; - - /// - /// Take a picture of type PNG - /// - private const int PNG = 1; - - /// - /// Folder to store captured images - /// - private const string isoFolder = "CapturedImagesCache"; - - /// - /// Represents captureImage action options. - /// - [DataContract] - public class CameraOptions - { - /// - /// Source to getPicture from. - /// - [DataMember(IsRequired = false, Name = "sourceType")] - public int PictureSourceType { get; set; } - - /// - /// Format of image that returned from getPicture. - /// - [DataMember(IsRequired = false, Name = "destinationType")] - public int DestinationType { get; set; } - - /// - /// Quality of saved image - /// - [DataMember(IsRequired = false, Name = "quality")] - public int Quality { get; set; } - - /// - /// Controls whether or not the image is also added to the device photo album. - /// - [DataMember(IsRequired = false, Name = "saveToPhotoAlbum")] - public bool SaveToPhotoAlbum { get; set; } - - /// - /// Ignored - /// - [DataMember(IsRequired = false, Name = "correctOrientation")] - public bool CorrectOrientation { get; set; } - - - - /// - /// Ignored - /// - [DataMember(IsRequired = false, Name = "allowEdit")] - public bool AllowEdit { get; set; } - - /// - /// Height in pixels to scale image - /// - [DataMember(IsRequired = false, Name = "encodingType")] - public int EncodingType { get; set; } - - /// - /// Height in pixels to scale image - /// - [DataMember(IsRequired = false, Name = "mediaType")] - public int MediaType { get; set; } - - - /// - /// Height in pixels to scale image - /// - [DataMember(IsRequired = false, Name = "targetHeight")] - public int TargetHeight { get; set; } - - - /// - /// Width in pixels to scale image - /// - [DataMember(IsRequired = false, Name = "targetWidth")] - public int TargetWidth { get; set; } - - /// - /// Creates options object with default parameters - /// - public CameraOptions() - { - this.SetDefaultValues(new StreamingContext()); - } - - /// - /// Initializes default values for class fields. - /// Implemented in separate method because default constructor is not invoked during deserialization. - /// - /// - [OnDeserializing()] - public void SetDefaultValues(StreamingContext context) - { - PictureSourceType = CAMERA; - DestinationType = FILE_URI; - Quality = 80; - TargetHeight = -1; - TargetWidth = -1; - SaveToPhotoAlbum = false; - CorrectOrientation = true; - AllowEdit = false; - MediaType = -1; - EncodingType = -1; - } - } - - /// - /// Used to open photo library - /// - PhotoChooserTask photoChooserTask; - - /// - /// Used to open camera application - /// - CameraCaptureTask cameraTask; - - /// - /// Camera options - /// - CameraOptions cameraOptions; - - public void takePicture(string options) - { - try - { - string[] args = JSON.JsonHelper.Deserialize(options); - // ["quality", "destinationType", "sourceType", "targetWidth", "targetHeight", "encodingType", - // "mediaType", "allowEdit", "correctOrientation", "saveToPhotoAlbum" ] - this.cameraOptions = new CameraOptions(); - this.cameraOptions.Quality = int.Parse(args[0]); - this.cameraOptions.DestinationType = int.Parse(args[1]); - this.cameraOptions.PictureSourceType = int.Parse(args[2]); - this.cameraOptions.TargetWidth = int.Parse(args[3]); - this.cameraOptions.TargetHeight = int.Parse(args[4]); - this.cameraOptions.EncodingType = int.Parse(args[5]); - this.cameraOptions.MediaType = int.Parse(args[6]); - this.cameraOptions.AllowEdit = bool.Parse(args[7]); - this.cameraOptions.CorrectOrientation = bool.Parse(args[8]); - this.cameraOptions.SaveToPhotoAlbum = bool.Parse(args[9]); - - //this.cameraOptions = String.IsNullOrEmpty(options) ? - // new CameraOptions() : JSON.JsonHelper.Deserialize(options); - } - catch (Exception ex) - { - this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message)); - return; - } - - //TODO Check if all the options are acceptable - - - if (cameraOptions.PictureSourceType == CAMERA) - { - cameraTask = new CameraCaptureTask(); - cameraTask.Completed += onCameraTaskCompleted; - cameraTask.Show(); - } - else - { - if ((cameraOptions.PictureSourceType == PHOTOLIBRARY) || (cameraOptions.PictureSourceType == SAVEDPHOTOALBUM)) - { - photoChooserTask = new PhotoChooserTask(); - photoChooserTask.Completed += onPickerTaskCompleted; - photoChooserTask.Show(); - } - else - { - DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT)); - } - } - - } - - public void onCameraTaskCompleted(object sender, PhotoResult e) - { - if (e.Error != null) - { - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR)); - return; - } - - switch (e.TaskResult) - { - case TaskResult.OK: - try - { - string imagePathOrContent = string.Empty; - - if (cameraOptions.DestinationType == FILE_URI) - { - // Save image in media library - if (cameraOptions.SaveToPhotoAlbum) - { - MediaLibrary library = new MediaLibrary(); - Picture pict = library.SavePicture(e.OriginalFileName, e.ChosenPhoto); // to save to photo-roll ... - } - - int orient = ImageExifHelper.getImageOrientationFromStream(e.ChosenPhoto); - int newAngle = 0; - switch (orient) - { - case ImageExifOrientation.LandscapeLeft: - newAngle = 90; - break; - case ImageExifOrientation.PortraitUpsideDown: - newAngle = 180; - break; - case ImageExifOrientation.LandscapeRight: - newAngle = 270; - break; - case ImageExifOrientation.Portrait: - default: break; // 0 default already set - } - - Stream rotImageStream = ImageExifHelper.RotateStream(e.ChosenPhoto, newAngle); - - // we should return stream position back after saving stream to media library - rotImageStream.Seek(0, SeekOrigin.Begin); - - WriteableBitmap image = PictureDecoder.DecodeJpeg(rotImageStream); - - imagePathOrContent = this.SaveImageToLocalStorage(image, Path.GetFileName(e.OriginalFileName)); - - - } - else if (cameraOptions.DestinationType == DATA_URL) - { - imagePathOrContent = this.GetImageContent(e.ChosenPhoto); - } - else - { - // TODO: shouldn't this happen before we launch the camera-picker? - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType")); - return; - } - - DispatchCommandResult(new PluginResult(PluginResult.Status.OK, imagePathOrContent)); - - } - catch (Exception) - { - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error retrieving image.")); - } - break; - - case TaskResult.Cancel: - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection cancelled.")); - break; - - default: - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection did not complete!")); - break; - } - - } - - public void onPickerTaskCompleted(object sender, PhotoResult e) - { - if (e.Error != null) - { - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR)); - return; - } - - switch (e.TaskResult) - { - case TaskResult.OK: - try - { - string imagePathOrContent = string.Empty; - - if (cameraOptions.DestinationType == FILE_URI) - { - WriteableBitmap image = PictureDecoder.DecodeJpeg(e.ChosenPhoto); - imagePathOrContent = this.SaveImageToLocalStorage(image, Path.GetFileName(e.OriginalFileName)); - } - else if (cameraOptions.DestinationType == DATA_URL) - { - imagePathOrContent = this.GetImageContent(e.ChosenPhoto); - - } - else - { - // TODO: shouldn't this happen before we launch the camera-picker? - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType")); - return; - } - - DispatchCommandResult(new PluginResult(PluginResult.Status.OK, imagePathOrContent)); - - } - catch (Exception) - { - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error retrieving image.")); - } - break; - - case TaskResult.Cancel: - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection cancelled.")); - break; - - default: - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection did not complete!")); - break; - } - } - - /// - /// Returns image content in a form of base64 string - /// - /// Image stream - /// Base64 representation of the image - private string GetImageContent(Stream stream) - { - int streamLength = (int)stream.Length; - byte[] fileData = new byte[streamLength + 1]; - stream.Read(fileData, 0, streamLength); - - //use photo's actual width & height if user doesn't provide width & height - if (cameraOptions.TargetWidth < 0 && cameraOptions.TargetHeight < 0) - { - stream.Close(); - return Convert.ToBase64String(fileData); - } - else - { - // resize photo - byte[] resizedFile = ResizePhoto(stream, fileData); - stream.Close(); - return Convert.ToBase64String(resizedFile); - } - } - - /// - /// Resize image - /// - /// Image stream - /// File data - /// resized image - private byte[] ResizePhoto(Stream stream, byte[] fileData) - { - int streamLength = (int)stream.Length; - int intResult = 0; - - byte[] resizedFile; - - stream.Read(fileData, 0, streamLength); - - BitmapImage objBitmap = new BitmapImage(); - MemoryStream objBitmapStream = new MemoryStream(fileData); - MemoryStream objBitmapStreamResized = new MemoryStream(); - WriteableBitmap objWB; - objBitmap.SetSource(stream); - objWB = new WriteableBitmap(objBitmap); - - // resize the photo with user defined TargetWidth & TargetHeight - Extensions.SaveJpeg(objWB, objBitmapStreamResized, cameraOptions.TargetWidth, cameraOptions.TargetHeight, 0, cameraOptions.Quality); - - //Convert the resized stream to a byte array. - streamLength = (int)objBitmapStreamResized.Length; - resizedFile = new Byte[streamLength]; //-1 - objBitmapStreamResized.Position = 0; - //for some reason we have to set Position to zero, but we don't have to earlier when we get the bytes from the chosen photo... - intResult = objBitmapStreamResized.Read(resizedFile, 0, streamLength); - - return resizedFile; - } - - /// - /// Saves captured image in isolated storage - /// - /// image file name - /// Image path - private string SaveImageToLocalStorage(WriteableBitmap image, string imageFileName) - { - - if (image == null) - { - throw new ArgumentNullException("imageBytes"); - } - try - { - - - var isoFile = IsolatedStorageFile.GetUserStoreForApplication(); - - if (!isoFile.DirectoryExists(isoFolder)) - { - isoFile.CreateDirectory(isoFolder); - } - - string filePath = System.IO.Path.Combine("///" + isoFolder + "/", imageFileName); - - using (var stream = isoFile.CreateFile(filePath)) - { - // resize image if Height and Width defined via options - if (cameraOptions.TargetHeight > 0 && cameraOptions.TargetWidth > 0) - { - image.SaveJpeg(stream, cameraOptions.TargetWidth, cameraOptions.TargetHeight, 0, cameraOptions.Quality); - } - else - { - image.SaveJpeg(stream, image.PixelWidth, image.PixelHeight, 0, cameraOptions.Quality); - } - } - - return new Uri(filePath, UriKind.Relative).ToString(); - } - catch (Exception) - { - //TODO: log or do something else - throw; - } - } - - } -}