BarcodeScanner icon indicating copy to clipboard operation
BarcodeScanner copied to clipboard

Windows Phone 8 Modifications to add focus and capture button

Open npateman opened this issue 9 years ago • 0 comments

Hi there,

I made a few modifications to the Windows Phone 8 capture code for my own use as the way it stands at current, it thread locks during capture, preventing focusing. It's also using more CPU than it should be using as it's continually trying to find a QR code even when there isn't one in view. This might not be suitable for some people but this is what I have done,


in BarcodeScannerUI.xaml

<phone:PhoneApplicationPage
    x:Class="WPCordovaClassLib.Cordova.Commands.BarcodeScannerUI"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d"
    shell:SystemTray.IsVisible="True">

    <Grid Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="96"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Canvas x:Name="CameraCanvas" Grid.ColumnSpan="2" >
            <Canvas.Background>
                <VideoBrush x:Name="CameraBrush">
                    <VideoBrush.RelativeTransform>
                        <CompositeTransform
                            CenterX="0.5"
                            CenterY="0.5"
                            Rotation="90"/>
                    </VideoBrush.RelativeTransform>
                </VideoBrush>
            </Canvas.Background>
        </Canvas>
        <Button Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Click="Focus_Click">Focus</Button>
        <Button Grid.Row="1" Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Click="Capture_Click">Capture</Button>
    </Grid>
</phone:PhoneApplicationPage>

in BarcodeScannerUI.xaml.cs

namespace WPCordovaClassLib.Cordova.Commands
{
    using System;
    using System.Windows;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Input;

    using Microsoft.Devices;
    using Microsoft.Phone.Controls;
    using Microsoft.Phone.Tasks;

    using ZXing;

    /// <summary>
    /// Class that represents UI for barcode scanner.
    /// </summary>
    public partial class BarcodeScannerUI
    {
        /// <summary>
        /// The result of scan operation.
        /// </summary>
        private BarcodeScannerTask.ScanResult result;

        /// <summary>
        /// The barcode reader object
        /// </summary>
        private BarcodeReader reader;

        /// <summary>
        /// Device camera object
        /// </summary>
        private PhotoCamera camera;

        /// <summary>
        /// Initializes a new instance of the <see cref="BarcodeScannerUI"/> class.
        /// This implementation not use camera autofocus.
        /// </summary>
        public BarcodeScannerUI()
        {
            this.InitializeComponent();

            // Instantiate objects and start camera preview
            this.camera = new PhotoCamera();
            this.reader = new BarcodeReader {Options = {TryHarder = true}};
            this.CameraBrush.SetSource(this.camera);

            // Bind events
            this.camera.CaptureCompleted += this.CaptureCompleted;
            this.camera.Initialized += this.CameraInitialized;
            this.reader.ResultFound += this.ReaderResultFound;
        }

        /// <summary>
        /// Occurs when barcode scan is [completed].
        /// </summary>
        public event EventHandler<BarcodeScannerTask.ScanResult> Completed;

        /// <summary>
        /// Called when a page is no longer the active page in a frame.
        /// </summary>
        /// <param name="e">An object that contains the event data.</param>
        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // If result is null, user is cancelled scan operation
            this.result = this.result ?? new BarcodeScannerTask.ScanResult(TaskResult.Cancel);
            this.Completed(this, this.result);
            this.CleanUp();
            base.OnNavigatedFrom(e);
        }

        private void CaptureCompleted(object sender, CameraOperationCompletedEventArgs e)
        {
            // Start scan process in separate thread
            Deployment.Current.Dispatcher.BeginInvoke(
                () =>
                {
                    var cameraBuffer = new WriteableBitmap(
                        (int)camera.PreviewResolution.Width,
                        (int)camera.PreviewResolution.Height);

                    camera.GetPreviewBufferArgb32(cameraBuffer.Pixels);
                    cameraBuffer.Invalidate();

                    reader.Decode(cameraBuffer);
                });
        }

        /// <summary>
        /// Called when device camera initialized.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="CameraOperationCompletedEventArgs"/> instance containing the event data.</param>
        private void CameraInitialized(object sender, CameraOperationCompletedEventArgs e)
        {
            if (e.Succeeded)
            {
                //do nothing
            }
            else
            {
                this.result = new BarcodeScannerTask.ScanResult(TaskResult.None);
                NavigationService.GoBack();
            }
        }

        /// <summary>
        /// Called when reader find barcode.
        /// </summary>
        /// <param name="obj">Scan result object.</param>
        private void ReaderResultFound(Result obj)
        {
            VibrateController.Default.Start(TimeSpan.FromMilliseconds(100));
            this.result = new BarcodeScannerTask.ScanResult(TaskResult.OK) { Barcode = obj };
            NavigationService.GoBack();
        }

        private void Capture_Click(object sender, RoutedEventArgs e)
        {
            this.camera.CaptureImage();
        }

        private void Focus_Click(object sender, RoutedEventArgs e)
        {
            this.camera.Focus();
        }

        /// <summary>
        /// Cleans up resources and removes unnecessary callbacks.
        /// </summary>
        private void CleanUp()
        {
            if (this.camera != null)
            {
                this.camera.Initialized -= this.CameraInitialized;
                this.camera.Dispose();
                this.camera = null;
            }

            if (this.reader != null)
            {
                this.reader.ResultFound -= this.ReaderResultFound;
                this.reader = null;
            }
        }
    }
}

Now what happens is you can press the focus button to focus, and capture to get the qr code. if the qr code is detected, it will return otherwise it will just discard it and let you take another. I'm testing it out still but has enabled me to capture qr codes with my windows phone which I couldn't do previously.

npateman avatar May 06 '15 10:05 npateman