Hoy, vamos a hablar acerca de la cámara que se encuentra dentro de cada Windows Phone, y como podemos usarla en nuestras propias aplicaciones. Esta no es una discusión acerca de Launchers y Choosers que fueron cubiertas en la serie original de 31 días de Windows Phone en los días 7 y 8. Esas acciones permiten al usuario tomar o seleccionar una foto desde su teléfono. Nosotros cubriremos como mostrar la información directa en la pantalla, capturando una imagen. usando los botones vía hardware y salvar fotos al teléfono.
Si tu quisieras, descargar esta aplicación para ti Windows Phone, esta disponible en Windows Phone Marketplace de manera gratuita.
Cuando nosotros hablamos acerca de información directa de la cámara, hablamos de usar la información real de la cámara directamente en nuestra aplicación. Creo que la mejor forma de mostrar esto es con un video de una aplicación haciendo exactamente eso.
Así que ahora que has visto lo hecho (e iremos un poco mas allá), vamos a empezar escribiendo algo de código.
Mostrando la información de la cámara
Nuestro primer paso al construir una aplicación que utiliza la cámara es poder ver la información de la cámara en la pantalla. Este es un paso sorpresivamente fácil. Vamos a crear un rectángulo en nuestra página XAML, después vamos a ajustar la propiedad Fill de ese rectángul a un objeto en nuestro código C#. Aquí está el XAML.
<phone:PhoneApplicationPage
x:Class=”Dia_7_Camara.MainPage”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:phone=”clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone”
xmlns:shell=”clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone”
xmlns:d=”http://schemas.microsoft.com/expression/blend/2008″
xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006″
mc:Ignorable=”d” d:DesignWidth=”480″ d:DesignHeight=”768″
FontFamily=”{StaticResource PhoneFontFamilyNormal}”
FontSize=”{StaticResource PhoneFontSizeNormal}”
Foreground=”{StaticResource PhoneForegroundBrush}”
SupportedOrientations=”Portrait” Orientation=”Portrait”
shell:SystemTray.IsVisible=”True”>
<Grid x:Name=”LayoutRoot” Background=”Transparent”>
<Grid.RowDefinitions>
<RowDefinition Height=”Auto”/>
<RowDefinition Height=”*”/>
</Grid.RowDefinitions>
<StackPanel x:Name=”TitlePanel” Grid.Row=”0″ Margin=”12,17,0,28″>
<TextBlock x:Name=”ApplicationTitle” Text=”LA LIGA SILVERLIGHT” Style=”{StaticResource PhoneTextNormalStyle}”/>
<TextBlock x:Name=”PageTitle” Text=”camara” Margin=”9,-7,0,0″ Style=”{StaticResource PhoneTextTitle1Style}”/>
</StackPanel>
<Grid x:Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″>
<Rectangle Height=”460″ Margin=”-22,-1,-131,148″>
<Rectangle.Fill>
<VideoBrush x:Name=”rectImagen” />
</Rectangle.Fill>
<Rectangle.RenderTransform>
<RotateTransform Angle=”90″ CenterX=”240″ CenterY=”240″ />
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
Como pudes ver en el XAML, hemos agregado un rectángulo a la plantilla preestablecida y definido su propiedad Fill para ser un VideoBrush llamado “rectImagen”. Deberías también notar el RenderTransform que apliqué al rectángulo. Rotándolo 90°, estaremos ajustándonos al hecho de que las cámaras están montadas en el teléfono con una vista en modo Landscape. En nuestro código C#, necesitamos asignar la información de nuestra cámara a ese VideoBrush. Eso lo hacemos creando un objeto de tipo PhotoCamera llamado “camara” y ajustándolo al Source de nuestro VideoBrush para que sea ese objeto de tipo PhotoCamera.
using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Devices;
using System.Windows.Media.Imaging;
using System.Windows.Media;
namespace Dia_7_Camara
{
public partial class MainPage : PhoneApplicationPage
{
PhotoCamera camara;
MediaLibrary albumImagenes = new MediaLibrary();
public MainPage()
{
InitializeComponent();
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing))
camara = new PhotoCamera(CameraType.FrontFacing);
else
camara = new PhotoCamera(CameraType.Primary);
camara.CaptureImageAvailable += new System.EventHandler<ContentReadyEventArgs>(camera_CaptureImageAvailable);
rectImagen.SetSource(camara);
}
protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
{
if (camara != null)
{
camara.Dispose();
}
}
}
}
Como mencioné antes, esto es la parte sencilla, pero aquí hay un par de detalles importantes a mirar. Quizá notaste en el código de arriba que cuando yo cree el nuevo objeto de tipo PhotoCamera, usé los parámetros CameraType.Primary y CameraType.FrontFacing. Estas propiedades especifican que quiero usar la cámara que esté encontrada al reverso o enfrente del teléfono. Los teléfonos mas nuevos que fueron lanzados después de la actualización Mango, tienen la opción de una cámara frontal. En este ejemplo, estaremos usando la cámara estándar a menos que tengas una cámara frontal disponible.
También notarás que use los eventor OnNavigatedTo y OnNavigatingFrom. Cada vez que el usuario navega a estas páginas (dentro de nuestra aplicación o cuando navega desde otra aplicación), queremos asegurarnos que la cámara esta inicializada. Usamos el método OnNavigatingFrom para prescindir de la cámar cuando el usuario deje la página. Esto ahorrará tanto batería como memoria en el dispositivo, y es la forma responsable de trabajar con la cámara.
Tomate el tiempo para correr ahora tu aplicación. Si tu la despliegas en un dispositivo real, verás lo que la cámara ve, como una especie de video. Si tu estás usando el emulador, probablemente veas algo como esto.
El emulador no utiliza webcams o cualquier otra fuente de video, en su lugar, usa esta pantalla blanca como forma de sugerir una imagen “única”. Un rectángulo pequeño y negro rotará alrededor de la pantalla y cuando capturemos una imagen, una imagen muy similar nos será regresada. Vamos a ver como funciona.
Tomar una foto
El siguiente paso que queremos en nuestra aplicación de cámara, es permitir al usuario la capacidad de tomar una foto. Vamos a comenzar agregando un botón en nuestra interfaz. Abajo del rectángulo que creamos hace poco en nuestro código XAML, agrega la siguiente línea.
<Button Foreground=”Green” BorderBrush=”Green” Content=”Capturar” Height=”72″ HorizontalAlignment=”Left” Margin=”6,535,0,0″ x:Name=”btnCapturar” VerticalAlignment=”Top” Width=”160″ Click=”btnCapturar_Click” />
Lo hice verde para hacerlo distintivo de nuestro video, y si estás usando el emulador (lo cual es el 90% de los casos), no serías capaz de poder verlo. También creamos un manejador de eventos el cual hará que el teléfono tome una foto.
Abre tu archivo C# y vamos a escribir unos cuantos métodos. El primero es el manejador de eventos de nuestro botón. Este solo necesita una línea de código, pero como capturar una imagen es una tarea de procesamiento compleja, queremos asegurarnos de que cada “captura” se completa antes de que la siguiente comienze. Para nuestro ejemplo tan sencillo he agreado un bloque try/catch para prevenir esos errores.
private void btnCapturar_Click(object sender, RoutedEventArgs e)
{
try { camara.CaptureImage(); }
catch (Exception ex) { Dispatcher.BeginInvoke(() => MessageBox.Show(ex.Message)); }
}
Puedes ver que la principal línea de código es la llamada al método camara.CaptureImage(). Intenta usando esa línea por sí misma, presiona el botón de captura muchas veces rápido, tu aplicación tronará igual de rápido. También nota que incluso nuestro manejador de errores debe ser hecho con un manejo de hilos. En cada momento que estés usando un sensor del dispositivo, debes asegurarte que estás escribiendo código consciente del manejo de hilos. Mostraré esto de nuevo cuando tengamos la imagen de la cámara de nuevo.
Cuando llamamos al método camara.CaptureImage(), todo lo que hace es decir a la cámara que queremos tomar una imagen. Si no creamos un manejador de eventos para recibirlo cuando esté hecho, nunca obtendremos el resultado. Para hacer esto, usaremos el evento CaptureImageAvailable de nuestro objeto de tipo PhotoCamera.
Así ahora podrás copiar y pegar TODO el código en tu proyecto, estoy incluyendo todo el código C# abajo, Las cosas importantes para checar son los nuevos manejadores de eventos un nuestro método OnNavigatedTo, el método camara_CaptureImageAvailable (el cual pasa sus resultados a un hilo separado) y el método ThreadSafeImageCapture el cual finalmente obtiene el resultado de la captura de nuestra imagen. Asegúrate de notar igual que en el método OnNavigatinFrom(), nosotros desbaratamos todos los manejadores igual. Esto salvará en uso de memoria y batería del teléfono cuando nuestra aplicación esté en segundo plano.
using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Devices;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using Microsoft.Xna.Framework.Media;
namespace Dia_7_Camara
{
public partial class MainPage : PhoneApplicationPage
{
PhotoCamera camara;
MediaLibrary albumImagenes = new MediaLibrary();
public MainPage()
{
InitializeComponent();
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing))
camara = new PhotoCamera(CameraType.FrontFacing);
else
camara = new PhotoCamera(CameraType.Primary);
camara.CaptureImageAvailable += new System.EventHandler<ContentReadyEventArgs>(camera_CaptureImageAvailable);
rectImagen.SetSource(camara);
}
protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
{
if (camara != null)
{
camara.Dispose();
camara.CaptureImageAvailable -= camera_CaptureImageAvailable;
}
}
private void btnCapturar_Click(object sender, RoutedEventArgs e)
{
try { camara.CaptureImage(); }
catch (Exception ex) { Dispatcher.BeginInvoke(() => MessageBox.Show(ex.Message)); }
}
void camera_CaptureImageAvailable(object sender, ContentReadyEventArgs e)
{
Dispatcher.BeginInvoke(() => ThreadSafeImageCapture(e));
}
void ThreadSafeImageCapture(ContentReadyEventArgs e)
{
BitmapImage image = new BitmapImage();
image.SetSource(e.ImageStream);
ImageBrush still = new ImageBrush();
still.ImageSource = image;
ViewBox.Fill = still;
}
}
}
Como lo demostré en el método ThreadSafeImageCapture, necesitamos crear un nuevo objeto de tipo BitmapImage (el cual requiere una llamada a la sentencia using System.Media.Imaging hasta arriba), y ajusta la fuente de ese BitmapImage a los resultados de la captura de nuestra imagen.
Los pasos que quedan en ese método de hecho reemplazan el VideoBrush que estábamos usando para mostrar nuestra información con un ImageBrush, mostrando la imagen que recién capturamos en la pantalla.
Este es un buen inicio para nuestra aplicación de cámara, pero hay mucho más para hablar, como usar el botón nativo de hardware que hay en cada Windows Phone, y después, finalmente hablaremos acerca de salvar esas imágenes capturadas al mismo lugar que lo haría cualquier aplicación normal, el álbum de la cámara.
Usando el botón de hardware de la cámara
Para usar el botón de hardware de la cámara, hay tres eventos que el botón inicia: ShutterKeyHalfPress, ShutterKeyPressed y ShutterKeyReleased. Cuando creas una aplicación de cámara propia, el botón no tiene ninguna conducta preestablecida, así que necesitamos implementarlas por nosotros mismos. El usuario se sentirá muy familiar con esos eventos y nosotros deberíamos implementarlos com las conductas esperadas.
ShutterKeyHalfPress – Esta acción deberá enfocar la cámara.
ShutterKeyPress – Esta acción debería tomar una foto con la cámara.
ShutterKeyReleased – El evento solo nos deja saber que no hay mas que hacer y además nos dejará cancelar cualquier enfoque.
Lo primero que necesitamos hacer es implementar cada uno de esos eventos. El código fuente abajo solo muestra el manejador de eventos del método OnNavigatedTo, nosotros construiremos cada uno de los manejadores de eventos para ellos mas adelante.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing))
camara = new PhotoCamera(CameraType.FrontFacing);
else
camara = new PhotoCamera(CameraType.Primary);
camara.CaptureImageAvailable += new System.EventHandler<ContentReadyEventArgs>(camera_CaptureImageAvailable);
rectImagen.SetSource(camara);
CameraButtons.ShutterKeyHalfPressed += new EventHandler(CameraButtons_ShutterKeyHalfPressed);
CameraButtons.ShutterKeyPressed += new EventHandler(CameraButtons_ShutterKeyPressed);
CameraButtons.ShutterKeyReleased += new EventHandler(CameraButtons_ShutterKeyReleased);
}
El primer manejador de eventos que crearemos es para el evento ShuttereyHalfPressed, en primera porque es el mas involucrado de los tres (además de que es bastante sencillo). Como puedes ver abajo, tenemos que asegurarnos que tenemos un objeto de tipo PhotoCamera, y después tratar de enfocar con el evento Focus(). He envuelto esto dentro de un bloque try/catch porque no podemos llamar al evento Focus() cuando la cámara este capturando una imagen, pero notarás que no hacemos nada con la excepción. La excepción se arrojará cada vez que captures una imagen, porque el botón pasará por “medio presionado” en dos ocasiones al estado de “presionado” una vez ahí y de nuevo en el camino a el estado de “suelto”. Si quieres escribir esto en un archivo de registro, hazlo, pero para limitar las distracciones en este ejemplo lo dejaré vacío.
void CameraButtons_ShutterKeyHalfPressed(object sender, EventArgs e)
{
if (camara != null)
{
try { camara.Focus(); }
catch (Exception ex)
{
}
}
}
Para el evento ShutterKeyPressed, usaré el mismo código que usé antes, cuando cree el botón para capturar una imagen para nuestra aplicación.
void CameraButtons_ShutterKeyPressed(object sender, EventArgs e)
{
if (camara != null)
{
try { camara.CaptureImage(); }
catch (Exception ex) { Dispatcher.BeginInvoke(() => MessageBox.Show(ex.Message)); }
}
}
Finalmente tenemos el evento ShutterKeyReleased, en este caso, lo único que realmente necesitamos hacer con el, es cancelar cualquier enfoque que hayamos tratado de ajusta en el evento ShutterHalfKeyPressed. CancelFocus() no desenfoca la imagen, solo detiene a la cámara para seguir enfocando.
void CameraButtons_ShutterKeyReleased(object sender, EventArgs e)
{
if (camara != null)
camara.CancelFocus();
}
El paso final para usar estos eventos es asegurarnos de eliminar nuestros manejadores de eventos cuando dejemos nuestra página. Hacemos esto de la misma forma que con el manejador de eventos CaptureImageAvailable, usando nuestro evento OnNavigatingFrom. He incluido el código para el método entero, pero la única adición son las tres sentencias de los manejadores de eventos removidos de CameraButtons
protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
{
if (camara != null)
{
camara.Dispose();
camara.CaptureImageAvailable -= camera_CaptureImageAvailable;
CameraButtons.ShutterKeyHalfPressed -= CameraButtons_ShutterKeyHalfPressed;
CameraButtons.ShutterKeyPressed -= CameraButtons_ShutterKeyPressed;
CameraButtons.ShutterKeyReleased -= CameraButtons_ShutterKeyReleased;
}
}
Hasta ahora debes tener una aplicación de cámara trabajando que tome una imagen usando el botón de la cámara y la muestre en la pantalla. Nuestro siguiente paso debería ser salvarla, y eso es exactamente lo que vamos a hacer.
Guardar imágenes en el álbum de la cámara
Para hacer esto súper simple, Microsoft creó la biblioteca MediaLibrary. Vamos de hecho a construir una aplicación entera que tome ventaja de la clase MediaLibrary después en esta serie, pero por ahora, vamos a usarla para guardar nuestras imágenes capturadas en el álbum de la cámara en el dispositivo. Esto permitirá después buscarlas de la misma forma que los usuarios harían en con sus otras fotos en su teléfono, e incluso sincronizarlas con sus computadoras cuando las conecten a sus teléfonos.
El proceso entero de hecho son solo dos líneas de código y la primera línes es solo hacer referencia a la MediaLibrary. Hasta arriba de tu página, en el mismo lugar donde creaste el objeto de tipo PhotoCamera, vamos a agregar esta línea de código abajo de la mencionada.
MediaLibrary albumImagenes = new MediaLibrary();
Ese fue el primer paso, el segundo es echar un vistazo en el método ThreadSafeImageCapture que creamos antes. El código previo estaba ahí para capturar la imagen, cambia el Fill de nuestro rectángulo y reemplázalo con la imagen capturada. Vamos a limpiar el contenido de ese método para este ejemplo, y en su lugar colocar lo siguiente.
void ThreadSafeImageCapture(ContentReadyEventArgs e)
{
albumImagenes.SavePictureToCameraRoll(DateTime.Now.ToString() + “.jpg”, e.ImageStream);
}
Ahora deberías ser capaza de correr la aplicación en un teléfono, toma una foto y después búscala en el álbum de imágenes. Aquí hay otro video para demostrar de lo que estoy hablando.
Así, en el espíritu de la brevedad, eso es todo!!! Hay muchas mas cosas que puedes hacer con esta información. incluyendo capturar video, manipular la imagen capturada e incluso obtener acceso al flash. Hay una gran serie de tutoriales en los Códigos de ejemplo de Windows Phone en la página de MSDN, y puedes encontrar los ejemplos de la cámara aquí.
En resumen
En lo que es seguramente el artículo mas largo de la serie, aprendimos como mostrar al usuario la información de la cámara, como crear la interfaz de usuario y los elementos para guardar imágenes, como hacer uso del hardware dedicado del teléfono para las fotografías y finalmente como guardar las imágenes en el álbum de la cámara. Este podría ser probablemente un artículo de varios días, pero no quería postergarme.
Si quieres descargar la solución completa del código que usé en este artículo, puedes hacerlo
Mañana, vamos a cambiar completamente de giro y ver algo de la información del usuario del teléfono. Mas específicamente, voy a mostrarte como podemos acceder a la lista de contactos que el usuario tiene. Nos vemos.

1 comment
alex says:
Dec 11, 2011
hola Amin disculpa como podría hacerle para utilizar la luz del led de la cámara ?