How to create a base camera app for Windows Phone 8

[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]

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.

Note

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

Tip

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.

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.

Note

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.

Creating the camera UI

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.

Note

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.

  1. 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;
    
    ' Directives
    Imports Microsoft.Devices
    Imports System.IO
    Imports System.IO.IsolatedStorage
    Imports Microsoft.Xna.Framework.Media
    
  2. 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();
    
        ' Variables
        Private savedCounter As Integer = 0
        Private cam As PhotoCamera
        Dim library As New MediaLibrary()
    
  3. 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.

  4. 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.

  5. (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.

Implementing the viewfinder and camera-based events

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

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.

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

``` vb
    'Code for initialization, capture completed, image availability events; also setting the source for the viewfinder.
    Protected Overrides Sub OnNavigatedTo(ByVal e As System.Windows.Navigation.NavigationEventArgs)

        ' Check to see if the camera is available on the phone.
        If (PhotoCamera.IsCameraTypeSupported(CameraType.Primary) = True Or
            PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing) = True) Then

            ' Initiate camera.
            If PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing) Then

                ' 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)

            End If

            ' Event is fired when the PhotoCamera object has been initialized.
            AddHandler cam.Initialized, AddressOf cam_Initialized

            ' Event is fired when the capture sequence is complete
            AddHandler cam.CaptureCompleted, AddressOf cam_CaptureCompleted

            ' Event is fired when the capture sequence is complete and an image is available.
            AddHandler cam.CaptureImageAvailable, AddressOf cam_CaptureImageAvailable

            ' Event is fired when the capture sequence is complete and a thumbnail image is available.
            AddHandler cam.CaptureThumbnailAvailable, AddressOf cam_CaptureThumbnailAvailable

            ' Set the VideoBrush source to the camera.
            viewfinderBrush.SetSource(cam)

        Else
            ' The camera is not supported on the phone.
            Me.Dispatcher.BeginInvoke(Sub()
                                          ' Write message.
                                          txtDebug.Text = "A Camera is not available on this phone."
                                      End Sub)
            ' Disable UI.
            ShutterButton.IsEnabled = False
        End If
    End Sub

    Protected Overrides Sub OnNavigatingFrom(e As System.Windows.Navigation.NavigatingCancelEventArgs)
        If cam IsNot Nothing Then

            ' Dispose camera to minimize power consumption and to expedite shutdown.
            cam.Dispose()

            ' Release memory, ensure garbage collection.
            RemoveHandler cam.Initialized, AddressOf cam_Initialized
            RemoveHandler cam.CaptureCompleted, AddressOf cam_CaptureCompleted
            RemoveHandler cam.CaptureImageAvailable, AddressOf cam_CaptureImageAvailable
            RemoveHandler cam.CaptureThumbnailAvailable, AddressOf cam_CaptureThumbnailAvailable

        End If
    End Sub
```

This code uses the [OnNavigatedTo(NavigationEventArgs)](https://msdn.microsoft.com/en-us/library/system.windows.controls.page.onnavigatedto\(system.windows.navigation.navigationeventargs\)\(v=VS.105\)) 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)](https://msdn.microsoft.com/en-us/library/microsoft.devices.camera.iscameratypesupported\(microsoft.devices.cameratype\)\(v=VS.105\)) 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)](https://msdn.microsoft.com/en-us/library/system.windows.controls.page.onnavigatedto\(system.windows.navigation.navigationeventargs\)\(v=VS.105\)) method and explicitly disposed during the [OnNavigatingFrom(NavigatingCancelEventArgs)](https://msdn.microsoft.com/en-us/library/system.windows.controls.page.onnavigatingfrom\(system.windows.navigation.navigatingcanceleventargs\)\(v=VS.105\)) method. The event handlers for PhotoCamera events are added in [OnNavigatedTo(NavigationEventArgs)](https://msdn.microsoft.com/en-us/library/system.windows.controls.page.onnavigatedto\(system.windows.navigation.navigationeventargs\)\(v=VS.105\)) and removed in [OnNavigatingFrom(NavigatingCancelEventArgs)](https://msdn.microsoft.com/en-us/library/system.windows.controls.page.onnavigatingfrom\(system.windows.navigation.navigatingcanceleventargs\)\(v=VS.105\)) to help release memory.

Note

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.

  1. 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.";
                });
            }
        }
    
        ' Update the UI if initialization succeeds.
        Private Sub cam_Initialized(ByVal sender As Object, ByVal e As Microsoft.Devices.CameraOperationCompletedEventArgs)
    
            If e.Succeeded Then
    
                Me.Dispatcher.BeginInvoke(Sub()
                                              ' Write message.
                                              txtDebug.Text = "Camera initialized."
                                          End Sub)
            End If
        End Sub
    

    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.

  2. 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);
            }
    
        'Ensure that the viewfinder is upright in LandscapeRight.
        Protected Overrides Sub OnOrientationChanged(e As Microsoft.Phone.Controls.OrientationChangedEventArgs)
            If cam IsNot Nothing Then
    
                ' LandscapeRight rotation when camera is on back of phone.
                Dim landscapeRightRotation As Integer = 180
    
                ' Change LandscapeRight rotation for front-facing camera.
                If cam.CameraType = CameraType.FrontFacing Then landscapeRightRotation = -180
    
                ' Rotate video brush from camera.
                If e.Orientation = PageOrientation.LandscapeRight Then
                    ' Rotate for LandscapeRight orientation.
                    viewfinderBrush.RelativeTransform =
                        New CompositeTransform() With {.CenterX = 0.5, .CenterY = 0.5, .Rotation = landscapeRightRotation}
                Else
                    ' Rotate for standard landscape orientation.
                    viewfinderBrush.RelativeTransform =
                        New CompositeTransform() With {.CenterX = 0.5, .CenterY = 0.5, .Rotation = 0}
                End If
            End If
    
            MyBase.OnOrientationChanged(e)
        End Sub
    

    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.

Note

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.

  1. 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++;
        }
    
        Private Sub ShutterButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            If cam IsNot Nothing Then
                Try
                    ' Start image capture.
                    cam.CaptureImage()
    
                Catch ex As Exception
                    ' Cannot capture an image until the previous capture has completed.
                    Me.Dispatcher.BeginInvoke(Sub() txtDebug.Text = ex.Message)
    
                End Try
            End If
        End Sub
    
        Private Sub cam_CaptureCompleted(ByVal sender As Object, ByVal e As CameraOperationCompletedEventArgs)
    
            ' Increments the savedCounter variable used for generating JPEG file names.
            savedCounter += 1
        End Sub
    

    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.

Saving to the media library and the local folder

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();
            }
        }
    
        ' Informs when full resolution photo has been taken, saves to local media library and the local folder
        Private Sub cam_CaptureImageAvailable(ByVal sender As Object, ByVal e As Microsoft.Devices.ContentReadyEventArgs)
    
            Dim fileName As String = savedCounter & ".jpg"
    
            Try
                ' Save the photo to the media library.
                Me.Dispatcher.BeginInvoke(Sub() txtDebug.Text = "Captured image available, saving photo.")
    
                ' Save photo to library camera roll.
                library.SavePictureToCameraRoll(fileName, e.ImageStream)
    
                ' Save the photo to the media library.
                Me.Dispatcher.BeginInvoke(Sub() 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 a JPEG to the local folder.
                Using isStore As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()
                    Using targetStream As IsolatedStorageFileStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write)
    
                        ' Initialize the buffer for 4KB disk pages.
                        Dim readBuffer(4095) As Byte
                        Dim bytesRead As Integer = -1
    
                        ' Copy the image to the local folder.
                        Do
                            bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)
                            targetStream.Write(readBuffer, 0, bytesRead)
                        Loop While (bytesRead > 0)
                    End Using
                End Using
    
                ' Save the photo to the media library.
                Me.Dispatcher.BeginInvoke(Sub() txtDebug.Text = "Photo has been saved to the local folder.")
    
            Finally
    
                ' Close image stream
                e.ImageStream.Close()
    
            End Try
    
        End Sub
    
    
        ' 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 photo. 
        Public Sub cam_CaptureThumbnailAvailable(ByVal sender As Object, ByVal e As ContentReadyEventArgs)
    
            Dim fileName As String = savedCounter & "_th.jpg"
    
            Try
                ' Write message to the UI thread.
                Me.Dispatcher.BeginInvoke(Sub() txtDebug.Text = "Captured image available, saving thumbnail.")
    
                ' Save thumbnail as a JPEG to the local folder.
                Using isStore As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()
                    Using targetStream As IsolatedStorageFileStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write)
    
                        ' Initialize the buffer for 4KB disk pages.
                        Dim readBuffer(4095) As Byte
                        Dim bytesRead As Integer = -1
    
                        ' Copy the thumbnail to the local folder.
                        Do
                            bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)
                            targetStream.Write(readBuffer, 0, bytesRead)
                        Loop While (bytesRead > 0)
                    End Using
                End Using
    
                ' Write message to the UI thread.
                Me.Dispatcher.BeginInvoke(Sub() txtDebug.Text = "thumbnail has been saved to the local folder.")
    
            Finally
    
                ' Close image stream
                e.ImageStream.Close()
    
            End Try
    
        End Sub
    

    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.

Note

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.

  1. On a phone, run the app by selecting the Debug | Start Debugging menu command. Test the app by pressing the SH button. The txtDebugTextBlock 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.

    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.

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

See Also

Other Resources

Advanced photo capture for Windows Phone 8

Capturing video for Windows Phone 8

Lenses for Windows Phone 8

How to use the camera capture task for Windows Phone 8