Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
If you’ve updated Windows Phone 7.5, you might have noticed that it has some nice built-in functionality for reading QR Codes using Bing Vision search. After trying it out for a while, I pretty quickly started wondering how I could use this in an app, and equally quickly I was disappointed to find that there are no APIs available for 3rd party developers to access this feature.
After a short hunt online, I found an excellent library that can be used as an alternative, and I built a simple reader with it. Here are the basic steps to create one yourself:
NOTE: To build and test this example you must use a physical phone rather than the emulator, as you will need access to the camera feed.
Create a new Windows Phone Project in Visual Studio
I used Visual Studio Ultimate, but the Express version that ships with the Windows Phone SDK will do just fine. Use the basic phone template for this example:
Be sure to select ‘Windows Phone 7.1’ as the target OS:
Update the App Manifest
If you plan to submit a camera-based app to the marketplace, then you must ensure that the WMAppManifest.xaml contains this capability element:
<Capability Name="ID_CAP_ISV_CAMERA"/>
A different element is required for the front-facing camera: ID_HW_FRONTCAMERA
Create the QR Reader Window and Output Area
Inside the content Grid in MainPage.xaml, add a Rectangle and a TextBlock:
<!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="QR SCANNER" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock x:Name="PageTitle" Text="scanner" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <!-- rectangle which acts as the 'camera window' --> <Rectangle Height="300" HorizontalAlignment="Left" Margin="82,61,0,0" Name="videoRectangle" Stroke="White" StrokeThickness="5" VerticalAlignment="Top" Width="300"> <Rectangle.RenderTransform> <RotateTransform x:Name="videoRotateTransform"/> </Rectangle.RenderTransform> <Rectangle.Fill> <VideoBrush x:Name="viewfinderBrush"/> </Rectangle.Fill> </Rectangle> <!-- Textblock which will hold the output of the QR Code --> <TextBlock Height="171" HorizontalAlignment="Left" Margin="31,406,0,0" Name="resultText" Text="<nothing to display>" VerticalAlignment="Top" Width="399" TextWrapping="Wrap" TextAlignment="Center" /> </Grid>
This should result in a main page like this:
The Rectangle will act as the camera viewer – notice that it has a VideoBrush as its fill; this will eventually contain the live feed from the camera. The TextBlock will display the content read from the QR Code.
Directives and Variables
In MainPage.xaml.cs, add a few relevant using statements, such as for the Devices namespace so we can use the PhotoCamera type:
using Microsoft.Devices; using System.IO; using System.Windows.Media.Imaging;
Declare some variables inside the main app class:
private PhotoCamera camera; private bool capturing = false;
Handle Navigation
It is recommended practice to initialise and dispose of the camera object when we navigate to and from our page, respectively, so we need to override these methods:
protected override void OnNavigatedTo( System.Windows.Navigation.NavigationEventArgs e) { if (null == camera) { camera = new PhotoCamera(); // filred when the camera is initialised camera.Initialized += camera_Initialised; // fired when the button is fully pressed CameraButtons.ShutterKeyPressed += camera_ButtonFullPress; // fired when an image is available. camera.CaptureImageAvailable += camera_CaptureImageAvailable; // set the VideoBrush source to the camera output videoRotateTransform.CenterX = videoRectangle.Width / 2; videoRotateTransform.CenterY = videoRectangle.Height / 2; videoRotateTransform.Angle = 90; viewfinderBrush.SetSource(camera); } base.OnNavigatedTo(e); } // user navigated away from page protected override void OnNavigatedFrom( System.Windows.Navigation.NavigationEventArgs e) { if (camera != null) { // unhook the event handlers CameraButtons.ShutterKeyPressed -= camera_ButtonFullPress; camera.CaptureImageAvailable -= camera_CaptureImageAvailable; camera.Initialized -= camera_Initialised; // dispose of the camera object camera.Dispose(); } base.OnNavigatedFrom(e); }
Here the PhotoCamera object is initialised to to use ‘primary’ camera, which is the rear-facing one. If you want to use the front-facing camera in an application, then you can call the alternate constructor like this:
camera = new PhotoCamera(CameraType.FrontFacing);
Add Camera Event Handlers
The event handlers are quite simple and simply initialise some settings and respond to the user taking a picture:
private void camera_Initialised(object sender, CameraOperationCompletedEventArgs e) { // set the camera resolution if (e.Succeeded) { var res = from resolution in camera.AvailableResolutions where resolution.Width == 640 select resolution; camera.Resolution = res.First(); } } // user has pressed the camera button private void camera_ButtonFullPress(object sender, EventArgs e) { if (capturing) return; capturing = true; camera.CaptureImage(); }
We will add the ‘camera_CaptureImageAvailable’ handler later.
Download the Barcode Library
The library can be downloaded here:
It ships with a sample Windows Phone 7 app, but this doesn’t read the data directly from the camera; instead it uses some hard-coded test images. It also ships with an example desktop app for generating your own codes.
Add the Barcode Library to the Project
In MainPage.xaml.cs, add the following using statement:
using MessagingToolkit.Barcode;
Add a reference to the Windows Phone 7 version of the library:
Decode the QR Code Image
The camera_CaptureImageAvailable event handler is called once we have an image to process. This is where we try to decode any possible QR Code it contains:
private void camera_CaptureImageAvailable( object sender, ContentReadyEventArgs e) { capturing = false; Stream imageStream = (Stream)e.ImageStream; BarcodeDecoder barcodeDecoder = new BarcodeDecoder(); Dictionary<DecodeOptions, object> decodingOptions = new Dictionary<DecodeOptions, object>(); List<BarcodeFormat> possibleFormats = new List<BarcodeFormat>(1); Result result; Dispatcher.BeginInvoke(() => { WriteableBitmap qrImage = new WriteableBitmap( (int)camera.Resolution.Width, (int)camera.Resolution.Height); imageStream.Position = 0; qrImage.LoadJpeg(imageStream); possibleFormats.Add(BarcodeFormat.QRCode); decodingOptions.Add( DecodeOptions.PossibleFormats, possibleFormats); try { result = barcodeDecoder.Decode(qrImage, decodingOptions); resultText.Text = result.Text; } catch (NotFoundException) { // this is expected if the image does not contain a valid // code, Or is too distorted to read resultText.Text = "<nothing to display>"; } catch (Exception ex) { // something else went wrong, so alert the user MessageBox.Show( ex.Message, "Error Decoding Image", MessageBoxButton.OK); } }); }
Compile and Deploy
As mentioned at the top of this post, you will need to deploy the app to a real phone, since the Emulator generates its own test output which is useless in this case.
That’s it. You should now have a basic QR Reader. Test it by reading the code below: