5 out of 6 rated this helpful - Rate this topic

How to: Create a Base Camera Application for Windows Phone

Windows Phone

March 22, 2012

With Windows Phone OS 7.1, you can programmatically access the device camera. This topic is the first in a series that describes how to create a camera application that demonstrates using the camera API for capturing pictures. This topic demonstrates how to display the camera viewfinder, programmatically trigger the shutter, and save a captured image to the media library and isolated storage.

NoteNote:

multiple devices If photo capture is not a core feature of your application, consider using the Camera Capture Task to capture photos instead of using the camera APIs directly. Memory allocated for the Camera Capture Task does not count toward total application memory use. This helps minimize your application’s memory use, which is particularly important when your application runs on a 256-MB device. For more information, see Developing for 256-MB Devices and How to: Use the Camera Capture Task for Windows Phone.

This topic covers the following steps:

  1. Creating the Camera UI

  2. Implementing the Viewfinder and Camera-based Events

  3. Saving to the Media Library and Isolated Storage

TipTip:

This topic corresponds to the Basic Camera Sample. To download the complete project, see Code Samples for Windows Phone.

After you complete this base camera application, the following topics incorporate features such as implementing flash and focus, changing capture resolution, and using the phone hardware shutter button. You must complete the base camera application in this topic first before proceeding. The following topics build upon this application and add functionality to the features implemented in this topic.

After completing all of these topics, the finished solution will appear as shown in the following image.

AP_Con_CameraAnatomy

In this topic, only the SH button is added to the application. The flash, auto-focus, and resolution buttons are added in the other topics in the series.

NoteNote:

When upgrading Windows Phone OS 7.0 applications to use the capabilities in Windows Phone OS 7.1, the camera capability ID_CAP_ISV_CAMERA is not automatically added to the application manifest file, WMAppManifest.xml. Without ID_CAP_ISV_CAMERA, applications using the camera API will not function. In new Windows Phone OS 7.1 projects, this capability is included in the application manifest file.

For this release of the Windows Phone SDK, this topic can be completed only on a Windows Phone device and not on Windows Phone Emulator.

This topic is based on C# development; however, Visual Basic code is also provided.

In this section, you create the camera UI that consists of a viewfinder region to display captured frames, and a shutter button to capture an image.

To create the camera UI

  1. In Visual Studio 2010 Express for Windows Phone, create a new project by selecting the File | New Project menu command.

  2. The New Project window is displayed. Expand the Visual C# templates, and then select the Silverlight for Windows Phone templates.

  3. Select the Windows Phone Application template. Fill in the Name box with a name of your choice.

  4. Click OK. The New Windows Phone Application window is displayed.

  5. In the Target Windows Phone Version menu, ensure that Windows Phone 7.1 is selected.

  6. Click OK. A new project is created, and MainPage.xaml is opened in the Visual Studio designer window.

  7. From the Project menu, select Add Reference. In the .NET tab, choose Microsoft.XNA.Framework, and click OK.

  8. On MainPage.xaml, update the phone:PhoneApplicationPage element as shown in the following code.

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

    This configures the page for landscape orientation and hides the system tray.

  9. On MainPage.xaml, replace the Grid named LayoutRoot with the following code.

        <!--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>
    
    

    This code creates a 640 x 480 viewfinder region with a StackPanel control that contains the shutter button, SH. You implement the ShutterButton_Click event in the following sections.

    NoteNote:

    The software shutter button in this exercise is only for demonstrating programmatic access to the PhotoCamera API. To optimize the experience for the end user, we recommend that your application uses the hardware shutter button on the camera. For information about how to implement the hardware shutter button, see How to: Access the Hardware Camera Shutter Button in Windows Phone.

  10. Open the code-behind file for the main page, MainPage.xaml.cs, and add the following directives at the top of the page.

    // Directives
    using Microsoft.Devices;
    using System.IO;
    using System.IO.IsolatedStorage;
    using Microsoft.Xna.Framework.Media;
    
    
  11. On MainPage.xaml.cs, in the MainPage class, add the following variable declarations above the MainPage class constructor.

        // Variables
        private int savedCounter = 0;
        PhotoCamera cam;
        MediaLibrary library = new MediaLibrary();
    
    
  12. To create a camera application, the camera capability must be declared in the application manifest file. Without it, the application will not function. Open WMAppManifest.xml and confirm that the following capabilities element is present.

    <Capability Name="ID_CAP_ISV_CAMERA"/>
    
  13. (Optional) If you want your application to require a front-facing camera, additionally add the front-facing camera capability to the Capabilities element in the application manifest file.

    <Capability Name="ID_HW_FRONTCAMERA"/>
    

    This capability will not be automatically added to new projects; it must be added manually. A user without a front-facing camera will be notified that their device does not meet the requirements of your application, but they can still choose to download it. This application has been designed to use either camera; this capability is not required for this application. For more information, see the Capabilities section in Camera and Photos Overview for Windows Phone.

To implement the viewfinder, you set the viewfinderBrush source to the Windows Phone camera. You also implement several camera-based events such as camera initialization, capture completed, and image availability.

To implement viewfinder and camera-based events

  1. In MainPage.xaml.cs, add the following code to the MainPage class.

    Note Note:

    Until you complete the following steps of this procedure, Visual Studio may list errors about methods that do not exist in the current context. These methods will be added in the following steps.

            //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;
                }
            }
    
    

    This code uses the OnNavigatedTo(NavigationEventArgs) method to create a PhotoCamera object named cam and configure several events. This code also sets the VideoBrush source to the phone camera object, cam.

    If the device has a front-facing camera in addition to the primary camera, the application will use the front-facing camera. Not all devices have a front-facing camera, so the IsCameraTypeSupported(CameraType) method is used to check if it is available before creating the PhotoCamera object. It is also possible that the device does not have any type of camera. In that case, the UI is disabled and a message is displayed.

    To account for the Windows Phone execution model, the PhotoCamera object is initialized in the OnNavigatedTo(NavigationEventArgs) method and explicitly disposed during the OnNavigatingFrom(NavigatingCancelEventArgs) method. The event handlers for PhotoCamera events are added in OnNavigatedTo(NavigationEventArgs) and removed in OnNavigatingFrom(NavigatingCancelEventArgs) to help release memory.

    NoteNote:

    For information about how to analyze and process individual frames from the camera preview buffer, see How to: Work with Grayscale in a Camera Application for Windows Phone.

  2. In MainPage.xaml.cs, add the following code to the MainPage class.

        // 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.";
                });
            }
        }
    
    

    This code uses the camera Initialized event to update the TextBlock named txtDebug. The BeginInvoke method is required for updating the status because the application UI runs on a different thread.

  3. In MainPage.xaml.cs, add the following code to the MainPage class.

            // 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);
            }
    
    

    This code ensures that the viewfinder, viewfinderBrush, is upright when the camera is upside-down (LandscapeRight orientation). If the camera is front-facing, the corresponding brush needs to be rotated in the opposite direction than if it is on the back of the device.

    NoteNote:

    Although rotating the video brush 180 degrees in either direction yields the same result, this code provides an example of how UI orientation can be based on the type of camera.

  4. In MainPage.xaml.cs, add the following code to the MainPage class.

            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++;
        }
    
    

    This code implements the shutter button and capture completed events. The shutter button is the software button you created with XAML code to capture still images. The CaptureCompleted event is used in this project to increment the savedCounter variable. It is used in the next section for JPEG naming.

For a camera application that targets Windows Phone OS 7.1, two images are captured when a picture is taken. One is the full-resolution image, and the second is a thumbnail image used to bring up the full-resolution picture in a gallery view. This section demonstrates how to place the full-resolution image in the device media library. It also demonstrates how to save the full-resolution image and the thumbnail image to isolated storage.

To save images to the media library and isolated storage

  1. In MainPage.xaml.cs, add the following code to the MainPage class.

        // 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();
            }
        }
    
    

    This code implements the CaptureImageAvailable and CaptureThumbnailAvailable events. The first method saves the full-resolution image to the device media library and isolated storage. The second method demonstrates how to save the thumbnail image to isolated storage.

    NoteNote:

    To save pictures to the Saved Pictures album in the Pictures Hub, use the SavePicture method. The SavePictureToCameraRoll method, used in this example, saves images to the Camera Roll album.

  2. On a device, run the application by selecting the Debug | Start Debugging menu command. Test the application by pressing the SH button. The txtDebug TextBlock will indicate the status of the saving operations to isolated storage. After you exit the application, you can find the pictures that you captured with the application in the camera roll folder in the Pictures Hub.

    The following example illustrates how the UI should appear at this point.

    AP_Con_CameraWireFrame

    In this example, the software shutter button, SH, is shown in the top-right corner of the UI. A photo of mangos appears in the Canvas control named viewfinderCanvas.

  3. Now that you have completed this base camera application, you can use it to work through the following topics:

Did you find this helpful?
(1500 characters remaining)