Export (0) Print
Expand All
Information
The topic you requested is included in another documentation set. For convenience, it's displayed below. Choose Switch to see the topic in its original location.

How to create a base camera app for Windows Phone 8

May 10, 2014

Applies to: Windows Phone 8 and Windows Phone Silverlight 8.1 | Windows Phone OS 7.1

Starting with Windows Phone OS 7.1, you can programmatically access the phone’s camera using the Microsoft.Devices.PhotoCamera class. This topic is the first in a series that describes how to create a camera app that demonstrates using this API for capturing photos. This topic demonstrates how to display the camera viewfinder, programmatically trigger the shutter, and save a captured image to the media library and the local folder.

Starting with Windows Phone 8, apps can use the PhotoCaptureDevice class for advanced capture scenarios. PhotoCaptureDevice allows apps to control photo properties such as ISO, exposure compensation, and manual focus position (when available on the phone). This topic doesn’t demonstrate PhotoCaptureDevice; for more info, see Advanced photo capture for Windows Phone 8.

NoteNote:

multiple devices If photo capture is not a core feature of your app, 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 app memory use. This helps minimize your app’s memory use, which is particularly important when your app runs on a lower-memory device. For more information, see Developing apps for lower-memory phones for Windows Phone 8 and How to use the camera capture task for Windows Phone 8.

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 the local folder

TipTip:

This topic corresponds to the Basic Camera Sample.

After you complete this base camera app, 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 app in this topic first before proceeding. The following topics build upon this app 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 app. The flash, autofocus, and resolution buttons are added in the other topics in the series.

NoteNote:

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

This topic can’t be completed with a Windows Phone OS 7.1 emulator (Emulator 7.5). Develop this app with a phone or a Windows Phone 8 emulator.

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. Using the Windows Phone SDK, create a new project using the Windows Phone App template.

  2. After the project has been created, on the Project menu, select Add Reference. On the .NET tab, choose Microsoft.XNA.Framework, and then click OK.

  3. In the MainPage.xaml file, 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.

  4. In 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×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 used only for demonstrating programmatic access to the PhotoCamera API. To optimize the experience for the user, we recommend that your app uses the hardware shutter button on the camera. For info about how to implement the hardware shutter button, see How to access the hardware camera shutter button in Windows Phone 8.

  5. Open MainPage.xaml.cs, the code-behind file for the main page, 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;
    
    
  6. In MainPage.xaml.cs, in the MainPage class, add the following variable declarations before the MainPage class constructor.

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

    <Capability Name="ID_CAP_ISV_CAMERA"/>
    

    If your Windows Phone 8 app requires a back-facing camera, use the ID_REQ_BACKCAMERA hardware requirement to prevent users from downloading your app if they don’t have a back-facing camera. For more info about capabilities and requirements, see App capabilities and hardware requirements for Windows Phone 8.

  8. To access the media library, the media library capability must be declared in the app manifest file. Without this, the app won’t be able to save files to the media library. Depending on the version of Windows Phone that your app targets, add the following capability:

    • ID_CAP_MEDIALIB: Windows Phone OS 7.1 apps can use this capability to access the media library.

    • ID_CAP_MEDIALIB_PHOTO: Windows Phone 8 apps can use this capability to save photos to the media library.

    Windows Phone 8 apps need to use additional capabilities to access video and audio in the media library. For more info, see App capabilities and hardware requirements for Windows Phone 8.

  9. (Optional) If features of your app require a front-facing camera, also add the front-facing camera capability or hardware requirement to the app manifest file, depending on which Windows Phone version your app targets:

    • ID_HW_FRONTCAMERA: Windows Phone OS 7.1 apps can use this capability. With this capability, a user without a front-facing camera will be notified that some features of your app won’t work on their phone, but they can still choose to download it.

    • ID_REQ_FRONTCAMERA: Windows Phone 8 apps can use this hardware requirement. With this requirement, a user without a front-facing camera won’t be able to download your app.

    For more info about capabilities and requirements, see App capabilities and hardware requirements for Windows Phone 8.

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.

    NoteNote:

    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 phone.
                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 phone.
                        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 phone.
                    this.Dispatcher.BeginInvoke(delegate()
                    {
                        // Write message.
                        txtDebug.Text = "A Camera is not available on this phone.";
                    });
    
                    // 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 phone has a front-facing camera in addition to the primary camera, the app will use the front-facing camera. Not all phones 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 phone 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 info about how to analyze and process individual frames from the camera preview buffer, see How to work with grayscale in a camera app for Windows Phone 8.

  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 app 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 phone.
                    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 phone.

    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.

Two images are captured when a photo is taken. One is the full-resolution image, and the second is a thumbnail image used to bring up the full-resolution photo in a gallery view. This section demonstrates how to place the full-resolution image in the phone media library. It also demonstrates how to save the full-resolution image and the thumbnail image to the local folder.

To save images to the media library and the local folder

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

        // Informs when full resolution photo has been taken, saves to local media library and the local folder.
        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 photo.";
                });
    
                // Save photo to the media library camera roll.
                library.SavePictureToCameraRoll(fileName, e.ImageStream);
    
                // Write message to the UI thread.
                Deployment.Current.Dispatcher.BeginInvoke(delegate()
                {
                    txtDebug.Text = "Photo has been saved to camera roll.";
    
                });
    
                // Set the position of the stream back to start
                e.ImageStream.Seek(0, SeekOrigin.Begin);
    
                // Save photo as JPEG to the local folder.
                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 the local folder. 
                        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 = "Photo has been saved to the local folder.";
    
                });
            }
            finally
            {
                // Close image stream
                e.ImageStream.Close();
            }
    
        }
    
        // Informs when thumbnail photo has been taken, saves to the local folder
        // User will select this image in the Photos Hub to bring up the full-resolution. 
        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 the local folder.
                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 the local folder. 
                        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 the local folder.";
    
                });
            }
            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 media library and the local folder. The second method demonstrates how to save the thumbnail image to the local folder.

    NoteNote:

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

  2. On a phone, run the app by selecting the Debug | Start Debugging menu command. Test the app by pressing the SH button. The txtDebug TextBlock will indicate the status of the saving operations to the local folder. After you exit the app, you can find the photos that you captured with the app in the camera roll folder in the Photos 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 app, you can use it to work through the following topics:

Show:
© 2014 Microsoft