Desarrollando con la cámara de Windows Phone
Silverlight para Windows Phone incluye varias herramientas de fácil uso para la cámara y el uso de fotos. Aquí vamos a mostrar cómo tomar y guardar fotos con la cámara de Windows Phone y seleccionar y mostrar fotos de la galería interna de Windows Phone.
Este artículo se divide en las siguientes secciones:
· Creando una interfaz de usuario para la cámara y visualización de fotos
· Tomando, seleccionando y visualizando imágenes
· Guardando imágenes en la Biblioteca de Imágenes
Creando una interfaz de usuario para la cámara y visualización de fotos
Inicia Visual Studio y comienza un proyecto de tipo "Silverlight para Windows Phone". A continuación, crea una interfaz de usuario (UI) que tiene los siguientes elementos:
· Dos campos TextBlock - uno con un nombre significativo que mostrará los mensajes de estado y una etiqueta TextBlock que dice simplemente: "Desconecte el teléfono delsoftware de Zune para ejecutar!".
· Un Image con un nombre significativo que tendrá su fuente dinámicamente actualizada para reflejar la nueva imagen que fue tomada o elegida.
· Tres botones con nombres significativos que se utilizarán para tomar una nueva foto,mostrar una foto existente, y guardar en el almacenamiento del teléfono la foto mostrada. En este artículo, estos botones se llaman takePhotoButton, choosePhotoButton ysavePhotoButton, respectivamente.
Una distribución propuesta de estos elementos se muestra a continuación:
XAML
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Button Content="Take Photo" Height="72" HorizontalAlignment="Left"
Margin="12,6,0,0" Name="button1" VerticalAlignment="Top"
idth="189" Click="button1_Click" />
<Image Height="308" HorizontalAlignment="Left" Margin="27,275,0,0"
Name="myImage" Stretch="Fill" VerticalAlignment="Top"
Width="406"/>
<Button Content="Choose Existing" Height="72" HorizontalAlignment="Left"
Margin="194,6,0,0" Name="button2" VerticalAlignment="Top"
Width="239" Click="button2_Click" />
<TextBlock Height="30" HorizontalAlignment="Left" Margin="27,162,0,0"
Name="textBlock1" Text="Disconnect phone from Zune software to run!"
VerticalAlignment="Top" Width="406" />
<Button Content="Save Current Photo to Library" Height="72"
HorizontalAlignment="Left" Margin="12,84,0,0" Name="savePhotoButton"
VerticalAlignment="Top" Width="419" IsEnabled="False"
Click="savePhotoButton_Click" />
<TextBlock Height="71" HorizontalAlignment="Left" Margin="29,197,0,0"
Name="statusText" Text="" VerticalAlignment="Top" Width="402"
Foreground="Red" TextWrapping="Wrap" />
</Grid>
Como último paso antes de la codificación, agrega una referencia a Microsoft.Xna.Framework.Vamos a usar el espacio de nombres Microsoft.Xna.Framework.Media en este ensamblado con el fin de guardar las imágenes en la biblioteca de medios del teléfono, y éste debe ser referenciado por tu proyecto antes que cualquiera de sus tipos, eventos o métodos sean utilizados en tu aplicación.
Para agregar Microsoft.Xna.Framework en tu aplicación:
· En el Explorador de soluciones, haz derecho en el nodo References en tu proyecto y acontinuación, selecciona Add Reference.
· Selecciona Microsoft.Xna.Framework de la lista y a continuación haz clic en OK.
Tomando, Seleccionando y visualizando imágenes
En el Explorador de soluciones, abre el archivo MainPage.xaml.cs, y agrega las siguientes líneas decódigo en la parte superior de la página, dejando las referencias por defecto en su lugar.
C#
using Microsoft.Phone.Tasks; using System.Windows.Media.Imaging; using System.IO; using System.IO.IsolatedStorage; using Microsoft.Xna.Framework.Media;
Esto le da acceso a tu código a los espacios de nombres necesarios para abrir la aplicación de lacámara en el teléfono y tomar una imagen, usar un objeto de mapa de bits de re-escritura paraalmacenar los datos de la imagen temporal, usar un stream de memoria para convertir la imagenen un archivo, guardar la imagen en el almacenamiento interno del teléfono, y mover una imagendel almacenamiento aislado del teléfono a la biblioteca multimedia del teléfono,respectivamente.
La selección de fotos y el uso de la cámara requerirán la coordinación entre algunos métodos, así que vamos a añadir algunos miembros de datos a la clase principal. Dos de ellos serán objetos Selectores, que permiten a las aplicaciones ceder el control a la funcionalidad integrada en el sistema operativo del teléfono a fin de facilitar las cosas como la elección de un contacto de una lista, tomar una foto, o seleccionar una foto de la galería de fotos del teléfono. Otro será una imagen de mapa de bits que se estará utilizando para almacenar la información de la imagen temporal, es decir, imágenes que hemos elegido ya sea desde la galería en el teléfono o simplemente tomadas con la cámara.
C#
public partial class MainPage : PhoneApplicationPage
{
// Declarar el objeto CameraCaptureTask con ámbito de la página.
CameraCaptureTask cameraCaptureTask;
PhotoChooserTask photoChooserTask;
BitmapImage bmp;
…
cameraCaptureTask y photoChooserTask van a necesitar conectar los manejadores de eventos que se disparan cuando se toma una fotografía o cuando se elige de la biblioteca de imágenes del teléfono, respectivamente. Esto significa que los dos eventos deben ser manejados:
- Evento Completed de cameraCaptureTask.
- Evento Completed de photoChooserTask.
Este tutorial tiene una peculiaridad: porque en ambos casos sólo queremos mostrar la imagen en pantalla, y porque los eventos Completed envían el mismo tipo de objeto a sus manejadores (unPhotoResult), usaremos un método para manejar ambos eventos. Vamos a llamar a este métodophotoCaptureOrSelectionCompleted, y obtendrá la foto que ha sido tomada por la cámara o seleccionada de la biblioteca de imágenes, y la mostrará en la pantalla. La conexión de ambos eventos Completed para este nuevo método se realiza en la función de inicio de la página,MainPage, dando como resultado lo siguiente:
C#
public MainPage()
{
InitializeComponent();
// Inicializa los objetos Selectores y asigna los manejadores para los eventos "Completed"
cameraCaptureTask = new CameraCaptureTask();
cameraCaptureTask.Completed += new EventHandler<PhotoResult>(photoCaptureOrSelectionCompleted);
photoChooserTask = new PhotoChooserTask();
photoChooserTask.Completed += new EventHandler<PhotoResult<(photoCaptureOrSelectionCompleted);
}
Anteriormente, cuando creamos la interfaz de usuario, agregamos un Image llamado myImage en la pantalla, pero no estableció su propiedad Source, dejándola en blanco. EnphotoCaptureOrSelectionCompleted, sabemos que el usuario ha tomado o seleccionado una imagen así que es momento de establecer la propiedad Source de myImage a esa imagen, después escalar la imagen de modo que quepa la zona de visualización de myImage. También actualizaremos el TextBlock statusText si es necesario. Por último, vamos a activar el botón que permite al usuario guardar la imagen mostrada.
La propiedad Stretch del objeto Image determina cómo la imagen será escalada para ajustarla a las dimensiones de myImage; utilizaremos Stretch.Uniform para preservar la relación de aspecto de la imagen original.
Así que podemos reservar la opción de guardar esta imagen si el usuario lo desea, utilizando elmapa de bits que hemos creado antes, llamado bmp, para recibir los datos de esta nueva imagen,entonces lo asignaremos a la propiedad Source de myImage de modo que se muestre en la pantalla. (En otro método que implementaremos después, el contenido de bmp se puede guardar en el almacenamiento interno del teléfono). El aspecto final dephotoCaptureOrSelectionCompleted será así:
C#
void photoCaptureOrSelectionCompleted(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
bmp = new BitmapImage();
bmp.SetSource(e.ChosenPhoto);
myImage.Source = bmp;
myImage.Stretch = Stretch.Uniform;
// Intercambio los estados de los elementos en la IU
savePhotoButton.IsEnabled = true;
statusText.Text = "";
}
else
{
savePhotoButton.IsEnabled = false;
statusText.Text = "Task Result Error: " + e.TaskResult.ToString();
}
}
Ahora conectamos los botones que colocamos en la interfaz de usuario para iniciar un Selector que nos permitirá tomar o seleccionar una imagen. Regresa al diseñador de la interfaz de usuario y haz doble clic en el botón "Take Photo". Esto crea un manejador de evento que será disparado cuando se haga clic en el botón. Nuestro botón se llama takePhotoButton, y sólo necesita una línea decódigo para iniciar el Selector. El evento Completed se disparará cuando la foto sea tomada, manejando el resto. El resultado es una función muy simple llamada takePhotoButton_Click:
C#
// La cámara muestra el Choosers en respuesta a un clic del botón.
private void takePhotoButton_Click(object sender, RoutedEventArgs e)
{
cameraCaptureTask.Show();
}
Ahora haz doble clic en el botón "Choose Existing", que nombramos choosePhotoButton. Una vezmás, es sólo una línea de código para iniciar el Selector que selecciona una foto, lo que resulta enun choosePhotoButton_Click que tiene este aspecto:
C#
// El selector de foto en respuesta a un clic del botón
private void choosePhotoButton_Click(object sender, RoutedEventArgs e)
{
photoChooserTask.Show();
}
Ahora la aplicación es capaz de capturar y seleccionar imágenes existentes y mostrarlas en la pantalla en su relación de aspecto correcto.
Como la advertencia en la interfaz de usuario dice, el teléfono debe estar desconectado delsoftware de Zune para que los Selectores sean lanzados correctamente.
Guardando imágenes en la Biblioteca de Imágenes
Con el fin de guardar la imagen a la biblioteca de imágenes del teléfono, debe ser primerocodificada como un JPEG mediante la clase Extensions del espacio de nombresSystem.Windows.Media.Imaging. Entonces, el ensamblado XNA que hemos importado se utilizarápara usar la clase MediaLibrary, cuyo método SavePicture finalmente escribe la imagen a la biblioteca de imágenes del teléfono, donde puede ser sincronizada con la computadora,visualizada en una presentación, etc.
Debido a que este proceso implica ambos pasos: guardar la imagen como JPEG y luego importarla ala biblioteca, vamos a escribir un archivo JPEG temporal en el almacenamiento interno del teléfono, conocido como el Almacenamiento Aislado. Entre otras cosas, el Almacenamiento Aislado para Windows Phone asigna un espacio exclusivo y seguro de archivos para cada aplicaciónen el teléfono. No vamos a entrar en detalles aquí con el uso del Almacenamiento Aislado, sólo tenemos que utilizar el espacio de almacenamiento de nuestra aplicación para escribir nuestroarchivo JPEG temporal. Se trata de crear primero un archivo vacío, luego asignarle contenido. Eltipo WriteableBitmap será usado para esta tarea, recibiendo el contenido de bmp, nuestros datos de imagen que creamos con anterioridad. Por último, queremos actualizar el Textblock statusTextcuando tenemos un resultado al guardar la imagen.
Regresa al diseñador de la interfaz de usuario y haz doble clic en el botón "Save Current Photo to Library", al que llamamos savePhotoButton. Al igual que con los otros botones, esto conecta un manejador de eventos en blanco al evento Click en el botón. Una vez implementado para cubrir todas las funcionalidades descritas, la versión final de savePhotoButton_Click se verá así:
private void savePhotoButton_Click(object sender, RoutedEventArgs e)
{
try
{
// Crea un nombre de archivo para el archivo JPEG en el almacenamiento aislado.
String tempJPEG = "TempJPEG";
// Crea el almacenamiento virtual y el stream del archivo. Compruebe si hay archivos duplicados tempJPEG.
var myStore = IsolatedStorageFile.GetUserStoreForApplication();
if (myStore.FileExists(tempJPEG))
{
myStore.DeleteFile(tempJPEG);
}
IsolatedStorageFileStream myFileStream = myStore.CreateFile(tempJPEG);
/ / Se crea un stream del archivo JPEG.
/ / En lugar de MyQuickApp en la URI, utilice el nombre de proyecto correcto.
/ / El uso de TempJPEG se estableció anteriormente.
Uri uri = new Uri("MyQuickApp;component/TempJPEG.jpg", UriKind.Relative);
// Crear un nuevo objeto WriteableBitmap y establece el stream de JPEG.
WriteableBitmap wb = new WriteableBitmap(bmp);
/ / Codifica un objeto WriteableBitmap a un stream JPEG.
/ / SaveJpeg (mapa de bits WriteableBitmap, targetStream Stream, targetWidth int,
/ / targetHeight int, int orientación, la calidad int)Extensions.SaveJpeg(wb, myFileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
myFileStream.Close();
/ Se crea un nuevo stream en el almacenamiento aislado, y guarda el archivo JPEG
/ / en la biblioteca de medios de Windows Phone.
myFileStream = myStore.OpenFile(tempJPEG, FileMode.Open, FileAccess.Read);
MediaLibrary library = new MediaLibrary();
Picture pic = library.SavePicture("SavedPicture.jpg", myFileStream);
myFileStream.Close();
savePhotoButton.IsEnabled = false;
statusText.Text = "Saved!";
}
catch (Exception myError)
{
statusText.Text = myError.Message;
}
}
Este tutorial se ha completado, y ahora tienes un ejemplo de un programa que controla la entrada de la cámara, además de leer y escribir en la biblioteca de fotos. Recuerda desconectar el teléfono del software Zune para que los Selectores en el método Start se puedan ejecutar.