Scanning barcode and saving page screenshot on Windows Phone

Scanning barcode and saving page screenshot on Windows Phone

Scanning barcodes is an interesting discipline. One of the most popular open source libraries for doing that is ZXing. There’s a little problem for Windows Phone developers, though. It can be used only with Java (Android). This is where CodePlex becomes interesting again. There is already a port for Silverlight called Windows Phone 7 Silverlight ZXing Barcode Scanning Library. I’ll show you how to take a picture using your primary phone camera, scan the picture for barcode using the Silverlight ZXing library, and save the application screenshot to media library.

Create a new Windows Phone project. Add the reference to WriteableBitmapEx by writing the following line in the Package Console:

Install-Package WriteableBitmapEx  

Now, download the Windows Phone 7 Silverlight ZXing Barcode Scanning Library from here.

Unzip it, and remember the location. Go to the references in your newly created WP7 project and add the following references:

Microsoft.Xna.Framework.dll  
WP7_Barcode_Library.dll  

Have the following usings in MainPage.xaml.cs:

using System;  
using System.IO;  
using System.Windows;  
using System.Windows.Media.Imaging;  
using Microsoft.Devices;  
using Microsoft.Phone.Controls;  
using Microsoft.Xna.Framework.Media;  
using WP7_Barcode_Library;  

Create the UI of the application in MainPage.xaml:

<Grid x:Name="LayoutRoot" Background="Transparent" DoubleTap="video_DoubleTap">  
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,0">
            <TextBlock x:Name="ApplicationTitle" Text="BARCODER live scan" Style="{StaticResource PhoneTextNormalStyle}"/>
        </StackPanel>

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Canvas Name="video" Tap="video_Tap">
                <Canvas.Background>
                    <VideoBrush x:Name="liveScan">
                    </VideoBrush>
                </Canvas.Background>
            </Canvas>
            <StackPanel Name="barStack" Visibility="Collapsed">
                <TextBlock Name="number" FontWeight="Bold" HorizontalAlignment="Center" FontSize="20"/>
                <Image Name="barcode" Height="380"/>
            </StackPanel>
        </Grid>
    </Grid>

Photo capture and barcode detection

In order to capture a photo from PhotoCam, start by adding the following line to MainPage.xaml.cs:

PhotoCamera cam;  

In the MainPage constructor, override what happens when you half press and press down the camera shutter button:

        public MainPage()
        {
            InitializeComponent();
            CameraButtons.ShutterKeyHalfPressed += new EventHandler(CameraButtons_ShutterKeyHalfPressed);
            CameraButtons.ShutterKeyPressed += new EventHandler(CameraButtons_ShutterKeyPressed);
        }</pre>
When navigating to and from the MainPage create and dispose the <strong>PhotoCamera</strong> objects:  
<pre class="brush:csharp">protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)  
{
    cam = new PhotoCamera(CameraType.Primary);
    liveScan.SetSource(cam);
    base.OnNavigatedTo(e);
}

protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)  
{
    if (cam != null)
        cam.Dispose();

    base.OnNavigatingFrom(e);
}

I used the half pressed camera shutter button for focusing, to keep the experience the same for user. When you press the camera shutter button down, the image gets captured and the barcode gets scanned:

void CameraButtons_ShutterKeyHalfPressed(object sender, EventArgs e)  
{
    if (video.Visibility == System.Windows.Visibility.Visible)
        cam.Focus();
}

void CameraButtons_ShutterKeyPressed(object sender, EventArgs e)  
{
    int x,y;
    x=(int)cam.PreviewResolution.Width;
    y=(int)cam.PreviewResolution.Height;
    int[] ARGBcam = new int[x*y];
    WriteableBitmap wbmp = new WriteableBitmap(x, y);
    cam.GetPreviewBufferArgb32(ARGBcam);
    ARGBcam.CopyTo(wbmp.Pixels, 0);
    MemoryStream ms = new MemoryStream();
    BitmapImage bmp = new BitmapImage();
    wbmp.SaveJpeg(ms, x, y, 0, 100);
    bmp.SetSource(ms);
    try
    {
        WP7BarcodeManager.ScanBarcode(bmp, new Action<BarcodeCaptureResult>(BarcodeResults_Finished));
    }
    catch
    {
        System.Diagnostics.Debug.WriteLine("Something went wrong.");
    }
}

The first method is pretty clear – I just called the Focus method on cam object. When the user presses down the shutter button, an array of integers gets created, which holds the PreviewBuffer of cam object. The array is then copied to pixels of a WriteableBitmap object called wbmp. A MemoryStream and BitmapImage get created. The method SaveJpeg is called, and the captured image is held in a MemoryStream object, which is then used for creating a BitmapImage. That BitmapImage called bmp is a parameter in WP7BarcodeManager.ScanBarcode method, along with the method which gets called when the scan completes. The implementation of that method is the following:

public void BarcodeResults_Finished(BarcodeCaptureResult BCResults)  
{
    if (BCResults.State == CaptureState.Success)
    {
        video.Visibility = System.Windows.Visibility.Collapsed;
        barStack.Visibility = System.Windows.Visibility.Visible;
        barcode.Source = WP7BarcodeManager.LastCaptureResults.BarcodeImage;
        number.Text = BCResults.BarcodeText;
    }
}

If the capture was successful, the video gets hidden and the image of the barcode along with the barcode number gets shown on the screen. Here’s an example of a barcode scan of a tasty Swiss mousse chocolate :)

Barcode-screenshot (3)

As you can see, the number has been read correctly!

Save the page screenshot to Media Library

How did I get that nice screenshot in my library? You may have noticed in the MainPage.xaml a DoubleTap event handler on the LayoutGrid. The event handler does the following:

private void video_DoubleTap(object sender, System.Windows.Input.GestureEventArgs e)  
{
    WriteableBitmap screenshot = new WriteableBitmap((int)this.ActualWidth, (int)this.ActualHeight);
    screenshot.Render(this, null);
    screenshot.Invalidate();
    MediaLibrary lib = new MediaLibrary();
    MemoryStream ms = new MemoryStream();
    screenshot.SaveJpeg(ms, (int)this.ActualWidth, (int)this.ActualHeight, 0, 100);
    lib.SavePicture("Barcode-screenshot.jpg", ms.ToArray());
    MessageBox.Show("Screenshot saved!");
}

Here’s a short explanation: first I create a WriteableBitmap called screenshot with actual width and height of the MainPage to constructor. Then I call the Render method which turns the UIElement to WriteableBitmap. The Invalidate method also needs to be called in order to render the latest bitmap changes to screenshot. Then I simply get the MediaLibrary and create a new MemoryStream object used for saving the screenshot JPEG to, and then save that memory stream to the library (actually, the byte array which I get by calling the ToArray method). In the end I show a MessageBox saying that everything went fine! :)

This is it – if you find the article useful, feel free to leave a comment or question and share the link to the article on social networks and other places. :)

Igor Ralic

igor ralic

View Comments
Microsoft Certified Solutions Developer: Windows Store Apps in C#