Creating a QR Code Reader App for Windows Phone 7
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: