Generation App – Día 21 – Acceder a la secuencia de imágenes de la cámara

Tu puedes crear una aplicación de cámara usando el API de la cámara para captura fotografías. En la lección del día de hoy te mostrare como desplegar el viewfinder de la cámara, disparar la cámara programáticamente, y salvar una fotografía tomada a la librería multimedia y en el almacenamiento aislado. Una vez que comprendas como crear una aplicación relacionada con la cámara, fácilmente estarás encaminado a implementar el flash y enfoque, cambiando la resolución de captura, y usando el botón físico de capturar imágenes.

Creando la interfaz de usuario de la cámara

En esta sección, crearemos una interfaz de usuario para la cámara que consiste en la región Viewfinder para desplegar las imágenes capturadas, y un botón disparador para capturar una imagen.

Creación del proyecto

  1. En Visual Studio 2010 Express para Windows Phone, crea un nuevo proyecto dando clic en Archivo –> Nuevo Proyecto

  2. En la ventana de nuevo proyecto. Expande las plantillas de Visual C#, y selecciona la plantilla Silverlight For Windows Phone

  3. Selecciona la plantilla Windows Phone Application. Coloca el nombre que desees para tu proyecto.

  4. Dale clic a OK. La pantalla de una Nueva aplicación para Windows Phone es desplegada

  5. Al momento de escoger la versión del S.O., asegúrate escoger la versión Windows Phone 7.1
  6. Da clic en OK. El nuevo proyecto es creado, y el archivo MainPage.xaml es abierto en el diseñado de Visual Studio

  7. Del menú de Proyecto, selecciona Add Reference. En la pestana de .NET, escogeMicrosoft.XNA.Framework y luego da clic a OK.

  8. En MainPage.xaml, actualiza el elemento phone:PhoneApplicationPage con el siguiente código:

    SupportedOrientations="Landscape" Orientation="LandscapeLeft"
        shell:SystemTray.IsVisible="False"

    Esto configura la pagina para soportar la orientación horizontal y esconder la bandeja del sistema.

  9. Ahora en MainPage.xaml, reemplaza el Grid nombrado LayoutRootcon el siguiente código:

    <!--LayoutRoot is the root grid where all page content is placed-->
        <Grid x:Name="LayoutRoot" Background="Transparent">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="640" />
                <ColumnDefinition Width="160" />
            </Grid.ColumnDefinitions>
    
            <Canvas x:Name="viewfinderCanvas" Width="640" Height="480" 
                       HorizontalAlignment="Left" >
    
                <!--Camera viewfinder -->
                <Canvas.Background>
                    <VideoBrush x:Name="viewfinderBrush" />
                </Canvas.Background>
             </Canvas>
    
            <!--Button StackPanel to the right of viewfinder>-->
            <StackPanel Grid.Column="1" >
                <Button x:Name="ShutterButton" Content="SH" 
                 Click="ShutterButton_Click" FontSize="26" 
                 FontWeight="ExtraBold" Height="75" />
            </StackPanel>
    
            <!--Used for debugging >-->
            <TextBlock Height="40" HorizontalAlignment="Left" Margin="8,428,0,0" 
             Name="txtDebug" VerticalAlignment="Top" Width="626" FontSize="24" 
             FontWeight="ExtraBold" />
        </Grid>

    Este código crea una región Viewfinder de 640 x 480 pixeles con un control StackPanel que contiene un botón disparador. Ahora Implementaremos el evento ShutterButtonClick en los siguientes pasos.

  10. Dirígete al código C# MainPage.xaml.cs y agrega las siguientes directivas en la parte superior de la pagina:

    // Directives
    using Microsoft.Devices;
    using System.IO;
    using System.IO.IsolatedStorage;
    using Microsoft.Xna.Framework.Media;
  11. Ahora en la clase MainPage, declara los siguientes atributos arriba del constructor:

    // Variables
    private int savedCounter = 0;
    PhotoCamera cam;
    MediaLibrary library = new MediaLibrary();
  12. Para crear la aplicación de cámara, la capacidad de la cámara tiene que ser declarado en el archivo de manifesto del aplicación. Abre el archivoWMAppManifest.xmly confirma el siguiente elemento se encuentra presente:

    <Capability Name="ID_CAP_ISV_CAMERA"/>
  13. (Opcional) Si quieres que tu aplicación utilice cámara frontal, adicionalmente se debe agregar la siguiente capacidad en los elementos Capabilities en el archivo de manifesto de la aplicación:

    <Capability Name="ID_HW_FRONTCAMERA"/>

Implementando Viewfinder y eventos de la cámara

Para implementar el viewfinder, deberás establecer la fuente ViewfinderBrush en la cámara del Windows Phone. Además de esto implementaremos varios eventos relacionados de la cámara como la inicialización, captura completada, y disponibilidad de imagen.

Para implementar los eventos de cámara

  1. En MainPage.xaml.cs, agrega el siguiente código a la clase MainPage:

    //Code for initialization, capture completed, image availability events; also setting the source for the viewfinder.
    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
       // Check to see if the camera is available on the device.
       if ((PhotoCamera.IsCameraTypeSupported(CameraType.Primary) == true) ||
          (PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing) == true))
       {
          // Initialize the camera, when available.
          if (PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing))
          {
             // Use front-facing camera if available.
             cam = new Microsoft.Devices.PhotoCamera(CameraType.FrontFacing);
          }
          else
          {
             // Otherwise, use standard camera on back of device.
             cam = new Microsoft.Devices.PhotoCamera(CameraType.Primary);
          }
    
          // Event is fired when the PhotoCamera object has been initialized.
          cam.Initialized += new EventHandler<Microsoft.Devices.CameraOperationCompletedEventArgs>(cam_Initialized);
    
          // Event is fired when the capture sequence is complete.
          cam.CaptureCompleted += new EventHandler<CameraOperationCompletedEventArgs>(cam_CaptureCompleted);
    
          // Event is fired when the capture sequence is complete and an image is available.
          cam.CaptureImageAvailable += new EventHandler<Microsoft.Devices.ContentReadyEventArgs>(cam_CaptureImageAvailable);
    
          // Event is fired when the capture sequence is complete and a thumbnail image is available.
          cam.CaptureThumbnailAvailable += new EventHandler<ContentReadyEventArgs>(cam_CaptureThumbnailAvailable);
    
          //Set the VideoBrush source to the camera.
          viewfinderBrush.SetSource(cam);
       }
       else
       {
          // The camera is not supported on the device.
          this.Dispatcher.BeginInvoke(delegate()
          {
          // Write message.
          txtDebug.Text = "A Camera is not available on this device.";
          });
    
          // Disable UI.
          ShutterButton.IsEnabled = false;
       }
    }
    protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
    {
       if (cam != null)
       {
          // Dispose camera to minimize power consumption and to expedite shutdown.
          cam.Dispose();
    
          // Release memory, ensure garbage collection.
          cam.Initialized -= cam_Initialized;
          cam.CaptureCompleted -= cam_CaptureCompleted;
          cam.CaptureImageAvailable -= cam_CaptureImageAvailable;
          cam.CaptureThumbnailAvailable -= cam_CaptureThumbnailAvailable;
       }
    }
  2. En MainPage.xaml.cs, agrega el siguiente código a la clase MainPage:
    // Update the UI if initialization succeeds.
    void cam_Initialized(object sender, Microsoft.Devices.CameraOperationCompletedEventArgs e)
    {
       if (e.Succeeded)
       {
          this.Dispatcher.BeginInvoke(delegate()
          {
             // Write message.
             txtDebug.Text = "Camera initialized.";
          });
       }
    }

    Este código utiliza el evento de la cámara Initialize, y actualiza el TextBlocknombrado txtDebug. El método BeginInvoke es requerido para actualiza el estado porque la interfaz de la aplicación se ejecuta en otro hilo de proceso diferente.

  3. En MainPage.xaml.cs, agrega el siguiente código a la clase MainPage:
    // Ensure that the viewfinder is upright in LandscapeRight.
    protected override void OnOrientationChanged(OrientationChangedEventArgs e)
    {
         if (cam != null)
         {
              // LandscapeRight rotation when camera is on back of device.
              int landscapeRightRotation = 180;
    
              // Change LandscapeRight rotation for front-facing camera.
              if (cam.CameraType == CameraType.FrontFacing) landscapeRightRotation = -180;
    
              // Rotate video brush from camera.
              if (e.Orientation == PageOrientation.LandscapeRight)
              {
                   // Rotate for LandscapeRight orientation.
                   viewfinderBrush.RelativeTransform = new CompositeTransform() 
                   { CenterX = 0.5, CenterY = 0.5, Rotation = landscapeRightRotation };
              }
              else
              {
                   // Rotate for standard landscape orientation.
                   viewfinderBrush.RelativeTransform = new CompositeTransform() 
                   { CenterX = 0.5, CenterY = 0.5, Rotation = 0 };
              }
         }
    
         base.OnOrientationChanged(e);
    }

    Este código asegura que el viewfinder, viewFinderBrush esta orientado de la manera correcta en la manera en que el usuario este sosteniendo el Windows Phone. Si la cámara frontal esta siendo utilizada, el brush correspondiente debe ser rotada a la dirección opuesta como si se encontrara en la parte trasera del dispositivo.

  4. En MainPage.xaml.cs, agrega el siguiente código a la clase MainPage:

    private void ShutterButton_Click(object sender, RoutedEventArgs e)
    {    if (cam != null)    {       try       {          // Start image capture.          cam.CaptureImage();       }       catch (Exception ex)       {          this.Dispatcher.BeginInvoke(delegate()             {             // Cannot capture an image until the previous capture has completed.             txtDebug.Text = ex.Message;             });       }    }
    }
    void cam_CaptureCompleted(object sender, CameraOperationCompletedEventArgs e)
    {    // Increments the savedCounter variable used for generating JPEG file names.    savedCounter++;
    }

    Este código implementa los eventos del botón disparador y captura completada. El botón disparador es el elemento que agregamos en el código XAML para capturar fotografías con la cámara. El evento de captura completada es utilizado en este proyecto para incrementar la variable contador savedCounter. Es utilizado para la siguiente sección para nombrar las imágenes JPEG guardadas.

Guardando fotografías a la galería multimedia

Para una aplicación de cámara para Windows Phone 7.1, dos imágenes son capturadas cuando una foto es tomada. Una es la imagen con la resolución máxima, y la segunda es una imagen thumbnail usados para mostrar una versión mas reducida para mostrar en la galería de imágenes. Esta sección explica como guardar la imagen con resolución máxima en la librería multimedia del dispositivo. También aprenderá como salvar una imagen con resolución máxima y la imagen thumbnail en el almacenamiento aislado.

Para guardar la imagen en la librería multimedia y almacenamiento aislado

  1. En MainPage.xaml.cs, agrega el siguiente código a la clase MainPage:

    // Informs when full resolution picture has been taken, saves to local media library and isolated storage.
    void cam_CaptureImageAvailable(object sender, Microsoft.Devices.ContentReadyEventArgs e)
    {
       string fileName = savedCounter + ".jpg";
    
       try
       {   // Write message to the UI thread.
          Deployment.Current.Dispatcher.BeginInvoke(delegate()
          {
          txtDebug.Text = "Captured image available, saving picture.";
          });
    
          // Save picture to the library camera roll.
          library.SavePictureToCameraRoll(fileName, e.ImageStream);
    
          // Write message to the UI thread.
          Deployment.Current.Dispatcher.BeginInvoke(delegate()
          {
          txtDebug.Text = "Picture has been saved to camera roll.";
          });
    
          // Set the position of the stream back to start
          e.ImageStream.Seek(0, SeekOrigin.Begin);
    
          // Save picture as JPEG to isolated storage.
          using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
          {
             using (IsolatedStorageFileStream targetStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write))
             {
                // Initialize the buffer for 4KB disk pages.
                byte[] readBuffer = new byte[4096];
                int bytesRead = -1;
    
                // Copy the image to isolated storage. 
                while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
                {
                   targetStream.Write(readBuffer, 0, bytesRead);
                }
             }
          }
    
          // Write message to the UI thread.
          Deployment.Current.Dispatcher.BeginInvoke(delegate()
          {
             txtDebug.Text = "Picture has been saved to isolated storage.";
          });
       }
       finally
       {
          // Close image stream
          e.ImageStream.Close();
       }
    }
    
    // Informs when thumbnail picture has been taken, saves to isolated storage
    // User will select this image in the pictures application to bring up the full-resolution picture. 
    public void cam_CaptureThumbnailAvailable(object sender, ContentReadyEventArgs e)
    {
       string fileName = savedCounter + "_th.jpg";
    
       try
       {
          // Write message to UI thread.
          Deployment.Current.Dispatcher.BeginInvoke(delegate()
          {
          txtDebug.Text = "Captured image available, saving thumbnail.";
          });
    
          // Save thumbnail as JPEG to isolated storage.
          using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
          {
             using (IsolatedStorageFileStream targetStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write))
             {
                // Initialize the buffer for 4KB disk pages.
                byte[] readBuffer = new byte[4096];
                int bytesRead = -1;
    
                // Copy the thumbnail to isolated storage. 
                while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
                {
                   targetStream.Write(readBuffer, 0, bytesRead);
                }
             }
          }
    
          // Write message to UI thread.
          Deployment.Current.Dispatcher.BeginInvoke(delegate()
          {
             txtDebug.Text = "Thumbnail has been saved to isolated storage.";
          });
       }
       finally
       {
          // Close image stream
          e.ImageStream.Close();
       }
    }

    Este código implementa los eventos CaptureImageAvailable yCaptureThumbnailAvailable. El primer método guarda la imagen con resolución máxima en la librería multimedia y en almacenamiento aislado. El segundo método te muestra como se guarda una imagen thumbnail en almacenamiento aislado.

  2. En el dispositivo, ejecuta la aplicación seleccionando el comando de menúDebug|Start Debugging. Presiona el botón SH. El textblock txtDebug te indicara el estado de las operaciones para guardar las imágenes en almacenamiento aislado. Después de cerrar la aplicación, puedes encontrar las fotos que tomaste con tu aplicación la carpeta camera roll en el hub de fotos. En la siguiente imagen te ilustra como debería aparecer la interfaz grafica en este punto.

    En este ejemplo. el botón disparador SH, es mostrado en la esquina superior derecha de la interfaz. Una imagen de mangos es mostrado en el control Canvas nombrado viewFinderCanvas.

Cabe mencionar que estos ejemplos es solo una introducción a lo que se puede implementar usando la cámara. Existen mas funcionalidades útiles que involucran la cámara como usar el Flash, el enfoque, la resolución de la imagen capturada, etc.

Autor: Jorge Ramirez      Síguelo en twitter @JorgeRamirezMSP
Publicación original –> http://j.mp/WtR40h
Fuente 1 –> http://j.mp/UGcGMN

Anuncios

1 comentario

Archivado bajo Windows Phone

Una respuesta a “Generation App – Día 21 – Acceder a la secuencia de imágenes de la cámara

  1. Pingback: Con Generation App nunca fue tan fácil desarrollar para Windows Phone « El Blog de MSP para Latinoamerica [BETA]

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s