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
Descarga el cĂłdigo fuente completo de este tutorial, hospedado en la galerĂa de cĂłdigo de Silverlight para Windows Phone.
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.





