[
https://issues.apache.org/jira/browse/CB-570?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Jesse MacFadyen reassigned CB-570:
----------------------------------
Assignee: Herm Wong (was: Jesse MacFadyen)
> WP7 takePicture DATA_URL Not Resizing Image
> -------------------------------------------
>
> Key: CB-570
> URL: https://issues.apache.org/jira/browse/CB-570
> Project: Apache Cordova
> Issue Type: Bug
> Components: WP7
> Affects Versions: 1.6.1
> Environment: Cordova 1.6.1, VS.NET 2010, WP7.5 emulators
> Reporter: Alan Neveu
> Assignee: Herm Wong
> Fix For: 1.8.0
>
> Original Estimate: 1h
> Remaining Estimate: 1h
>
> The code in Camera.cs that should resize the picture file before returning
> the base64 encoded string has not been completed as of 1.6.1. The result is
> that the full 5 megapixel or 8 megapixel file gets base64 encoded and
> returned. Das ist vady badst yah! I wrote some code that uses a solid
> approach to resizing the image and I'll share it here so that Jesse can
> restructure it a bit using forms that match the rest of the project. This
> code works great and it was used in basically this same format on another
> Silverlight app that has been in the WP7 Marketplace for over a year with
> 8,000 installs and no errors with this code. Enjoy!
> /*
> 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;
> namespace WP7CordovaClassLib.Cordova.Commands
> {
> public class Camera : BaseCommand
> {
> /// <summary>
> /// Return base64 encoded string
> /// </summary>
> private const int DATA_URL = 0;
> /// <summary>
> /// Return file uri
> /// </summary>
> private const int FILE_URI = 1;
> /// <summary>
> /// Choose image from picture library
> /// </summary>
> private const int PHOTOLIBRARY = 0;
> /// <summary>
> /// Take picture from camera
> /// </summary>
> private const int CAMERA = 1;
> /// <summary>
> /// Choose image from picture library
> /// </summary>
> private const int SAVEDPHOTOALBUM = 2;
> /// <summary>
> /// Take a picture of type JPEG
> /// </summary>
> private const int JPEG = 0;
> /// <summary>
> /// Take a picture of type PNG
> /// </summary>
> private const int PNG = 1;
> /// <summary>
> /// Folder to store captured images
> /// </summary>
> private const string isoFolder = "CapturedImagesCache";
> /// <summary>
> /// Represents captureImage action options.
> /// </summary>
> [DataContract]
> public class CameraOptions
> {
> /// <summary>
> /// Source to getPicture from.
> /// </summary>
> [DataMember(IsRequired = false, Name = "sourceType")]
> public int PictureSourceType { get; set; }
> /// <summary>
> /// Format of image that returned from getPicture.
> /// </summary>
> [DataMember(IsRequired = false, Name = "destinationType")]
> public int DestinationType { get; set; }
> /// <summary>
> /// Quality of saved image
> /// </summary>
> [DataMember(IsRequired = false, Name = "quality")]
> public int Quality { get; set; }
> /// <summary>
> /// Height in pixels to scale image
> /// </summary>
> [DataMember(IsRequired = false, Name = "targetHeight")]
> public int TargetHeight { get; set; }
> /// <summary>
> /// Width in pixels to scale image
> /// </summary>
> [DataMember(IsRequired = false, Name = "targetWidth")]
> public int TargetWidth { get; set; }
> /// <summary>
> /// Creates options object with default parameters
> /// </summary>
> public CameraOptions()
> {
> this.SetDefaultValues(new StreamingContext());
> }
> /// <summary>
> /// Initializes default values for class fields.
> /// Implemented in separate method because default constructor is
> not invoked during deserialization.
> /// </summary>
> /// <param name="context"></param>
> [OnDeserializing()]
> public void SetDefaultValues(StreamingContext context)
> {
> PictureSourceType = CAMERA;
> DestinationType = FILE_URI;
> Quality = 80;
> TargetHeight = -1;
> TargetWidth = -1;
> }
> }
> /// <summary>
> /// Used to open photo library
> /// </summary>
> PhotoChooserTask photoChooserTask;
> /// <summary>
> /// Used to open camera application
> /// </summary>
> CameraCaptureTask cameraTask;
> /// <summary>
> /// Camera options
> /// </summary>
> CameraOptions cameraOptions;
> public void takePicture(string options)
> {
> try
> {
> this.cameraOptions = String.IsNullOrEmpty(options) ?
> new CameraOptions() :
> JSON.JsonHelper.Deserialize<CameraOptions>(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 += onTaskCompleted;
> cameraTask.Show();
> }
> else
> {
> if ((cameraOptions.PictureSourceType == PHOTOLIBRARY) ||
> (cameraOptions.PictureSourceType == SAVEDPHOTOALBUM))
> {
> photoChooserTask = new PhotoChooserTask();
> photoChooserTask.Completed += onTaskCompleted;
> photoChooserTask.Show();
> }
> else
> {
> DispatchCommandResult(new
> PluginResult(PluginResult.Status.NO_RESULT));
> }
> }
> }
> public void onTaskCompleted(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)
> {
> Byte[] bytFile;
> Byte[] bytFileResized;
> int intResult = 0;
> long lngLength;
> BitmapImage objBitmap;
> System.IO.MemoryStream objBitmapStream;
> System.IO.MemoryStream objBitmapStreamResized =
> new System.IO.MemoryStream();
> WriteableBitmap objWB;
> //Get the JPEG bytes from the source chosen
> photo, probably 5 megapixel!
> lngLength = e.ChosenPhoto.Length;
> bytFile = new Byte[lngLength];
> intResult = e.ChosenPhoto.Read(bytFile, 0,
> (int)lngLength);
> //Convert the bytes to a WriteableBitmap
> objBitmap = new BitmapImage();
> objBitmapStream = new
> System.IO.MemoryStream(bytFile);
> objBitmap.SetSource(objBitmapStream);
> objWB = new WriteableBitmap(objBitmap);
> //Resize the image
>
> System.Windows.Media.Imaging.Extensions.SaveJpeg(objWB,
> objBitmapStreamResized, cameraOptions.TargetWidth,
> cameraOptions.TargetHeight, 0, cameraOptions.Quality);
> //Convert the resized stream to a byte array.
> lngLength = objBitmapStreamResized.Length;
> bytFileResized = new Byte[lngLength]; //-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(bytFileResized, 0, (int)lngLength);
> //Convert the byte array to base64 string.
> imagePathOrContent =
> Convert.ToBase64String(bytFileResized);
> }
> else
> {
> 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;
> }
> }
> /// <summary>
> /// Returns image content in a form of base64 string
> /// </summary>
> /// <param name="stream">Image stream</param>
> /// <returns>Base64 representation of the image</returns>
> private string GetImageContent(Stream stream)
> {
> int streamLength = (int)stream.Length;
> byte[] fileData = new byte[streamLength + 1];
> stream.Read(fileData, 0, streamLength);
> stream.Close();
> return Convert.ToBase64String(fileData);
> }
> /// <summary>
> /// Saves captured image in isolated storage
> /// </summary>
> /// <param name="imageFileName">image file name</param>
> /// <returns>Image path</returns>
> 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;
> }
> }
> }
> }
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators:
https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira