windows phone 开发之二维码扫描

    伴随着智能手机的高速发展,人们获取信息的方式也变的越来越多样化,一些新技术新概念都逐步走入人们日常生活中。

低功耗蓝牙4.0,近场通信NFC,指纹识别,柔性屏幕等最新技术也将会很快的普及。

由于现在的工作的项目中刚刚添加二维码扫描的功能,所以这里就介绍一下 Windows Phone 开发中 二维码功能的添加。

    windows phone 开发之二维码扫描

    二维码的原理就不赘述了,直奔主题:

    1.windows phone二维码的解析类库。

       由于wp中没有直接解析二维码信息的api接口,所以我们要用到第三方类库ZXing.Net

       ZXing.Net在开源网站CodePlxe.com可以下载到(http://zxingnet.codeplex.com/)

       下载完成后选择对应的ZXing.dll添加到项目引用就可以了。

 

    2.从windows phone摄像头获取二维码信息。

       以下以wp8平台为例,界面模仿微信扫描二维码页面效果。

       UI部分:(文章下面有图)

       a.让Rectangle的填充属性(fill)为VideoBrush, 把VideoBrush的数据源设为一个PhotoCamera实例

       b.在ContentPanel容器里面放置4个黑色半透明Rectangle形成周围图像比中间的暗的效果

       c.在中间明亮区域边缘放置8个几像素的Rectangle形成图中红色的四角边框

       d.用一个高度很窄的Rectangle模仿中间区域绿色的扫描线效果,并设置一个扫动动画

       代码实现部分:

       a.新建一个Reader实例用来解码得到的图片,reader可以看做是一个解码器,可以设定解码的类型(条形码,二维码等)

       b.新建一个继承自LuminanceSource抽象类型的PhotoCameraLuminanceSource的类型

       c.原理是通过设置一个计时器间隔几秒获取camera的数据复制到PhotoCameraLuminanceSource,最后让reader来解析

 

    3.从图片中识别二维码信息

       

       a.通过PhotoChooserTask图片选择器选取手机图片库中的图片

       b.将图片stream数据复制到一个WriteableBitmap对象里面

       c.新建一个继承自LuminanceSource抽象类型的BitmapLuminanceSource的类型类获取图形中的数据

      d.使用reader来解析BitmapLuminanceSource数据

       

       这里出现的一个问题是我们熟知的BitmapImage类型并不能直接得到位图的像素数据,

       后来我发现WriteableBitmap类型恰好有Pixels属性,那么可否通过新建WriteableBitmap类型然后设置Source来获取位图数据呢,经过实践就是用它了.

 

其实ZXing库很强大,能解析很多种类型的条码二维码,可以使用MultiFormatReader来读取多种类型的电子码

文章很简单,希望在大家做简单的wp8二维码识别的时候会起到参考作用。

 

-------------------截图---------------------------

  windows phone 开发之二维码扫描

 

-------------------------------代码-------------------------------------------

      ScanPage.xaml代码如下

windows phone 开发之二维码扫描
<phone:PhoneApplicationPage
    x:Class="Demo.Pages.ScanPage"
    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="False">
    <phone:PhoneApplicationPage.Resources>
        <Storyboard x:Name="storyScanning" RepeatBehavior="Forever">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="recScanning">
                <EasingDoubleKeyFrame KeyTime="0" Value="-147"/>
                <EasingDoubleKeyFrame KeyTime="0:0:3" Value="147"/>
                <EasingDoubleKeyFrame KeyTime="0:0:6" Value="-147"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </phone:PhoneApplicationPage.Resources>

    <Grid x:Name="LayoutRoot" Background="#FF212021">
        <Grid.RowDefinitions>
            <RowDefinition Height="66"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid Height="66" VerticalAlignment="Top">
            <Grid.Background>
                <ImageBrush Stretch="Fill" ImageSource="/PayeasePay;component/Resources/nav-top@2x.png"/>
            </Grid.Background>
            <TextBlock x:Name="tbkTitle" FontSize="32" Foreground="Black" VerticalAlignment="Center" HorizontalAlignment="Center" Text="扫描二维码"/>
            <!--<Image x:Name="imgReturn" Visibility="Collapsed" Height="40" Margin="0,0,12,0" Tap="imgReturn_Tap" HorizontalAlignment="Right" Source="/PayeasePay;component/Resources/return.png"/>-->
        </Grid>

        <Grid x:Name="ContentPanel" Grid.Row="1" Height="640">

            <Rectangle x:Name="rec" Height="640">
                <Rectangle.Fill>
                    <VideoBrush x:Name="vBrush">
                        <VideoBrush.RelativeTransform>
                            <CompositeTransform x:Name="transform" CenterX="0.5" CenterY="0.5"/>
                        </VideoBrush.RelativeTransform>
                    </VideoBrush>
                </Rectangle.Fill>
            </Rectangle>

            <Rectangle HorizontalAlignment="Left" Width="90" Fill="#99000000"/>
            <Rectangle HorizontalAlignment="Right" Width="90" Fill="#99000000"/>
            <Rectangle VerticalAlignment="Top" Width="300" Height="170" Fill="#99000000"/>
            <Rectangle VerticalAlignment="Bottom" Width="300" Height="170" Fill="#99000000"/>

            <TextBlock x:Name="tbkTip" VerticalAlignment="Bottom" Foreground="White" HorizontalAlignment="Center" Margin="36" Text="提示:请将二维码图案放置在取景框内"/>

            <Grid Width="306" Height="306">
                <Rectangle Width="3" Height="50" Fill="Red" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                <Rectangle Width="3" Height="50" Fill="Red" HorizontalAlignment="Right" VerticalAlignment="Top"/>
                <Rectangle Width="3" Height="50" Fill="Red" HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
                <Rectangle Width="3" Height="50" Fill="Red" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
                <Rectangle Width="50" Height="3" Fill="Red" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                <Rectangle Width="50" Height="3" Fill="Red" HorizontalAlignment="Right" VerticalAlignment="Top"/>
                <Rectangle Width="50" Height="3" Fill="Red" HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
                <Rectangle Width="50" Height="3" Fill="Red" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>

                <Rectangle x:Name="recScanning"  Margin="12,3" Height="2" RenderTransformOrigin="0.5,0.5">
                    <Rectangle.RenderTransform>
                        <CompositeTransform/>
                    </Rectangle.RenderTransform>
                    <Rectangle.Projection>
                        <PlaneProjection/>
                    </Rectangle.Projection>
                    <Rectangle.Fill>
                        <LinearGradientBrush EndPoint="0,0.5" StartPoint="1,0.5">
                            <GradientStop Color="#331CF106" Offset="0.15"/>
                            <GradientStop Color="#331CF106" Offset="0.85"/>
                            <GradientStop Color="#FF1CF106" Offset="0.5"/>
                        </LinearGradientBrush>
                    </Rectangle.Fill>

                </Rectangle>
            </Grid>
        </Grid>

        <TextBlock x:Name="tbkResult" Grid.Row="1" Foreground="White" VerticalAlignment="Top" TextWrapping="Wrap"  Margin="12,18" FontSize="25" Text="扫描结果:"/>
    </Grid>

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBar.Buttons>
                <shell:ApplicationBarIconButton x:Name="appbarSelectImage" IconUri="/Assets/qr_code.png" Text="从相册选取" IsEnabled="True" Click="appbarSelectImage_Click"/>
            </shell:ApplicationBar.Buttons>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>
    
</phone:PhoneApplicationPage>
   
View Code

      ScanPage.xaml.cs代码如下

windows phone 开发之二维码扫描
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using ZXing;
using Microsoft.Devices;
using System.Windows.Threading;
using ZXing.QrCode;
using ZXing.OneD;
using ZXing.Common;
using Demo.Utils;
using Microsoft.Phone.Tasks;
using System.Windows.Media.Imaging;
using Windows.UI;

namespace Demo.Pages
{
    public partial class ScanPage : PhoneApplicationPage
    {
        private const string StrScanning = "正在扫描......";
        private const string StrScanCompleted = "扫描结果:";
        private const string StrNoQRDecode = "图片中可能不包含二维码信息,请重新选取";

        private static PhotoCamera photoCamera;
        private PhotoCameraLuminanceSource _luminance;
        private readonly DispatcherTimer _timer;
        private Reader _reader = null;//解码器

        public ScanPage()
        {
            InitializeComponent();

            this._timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(250) };
            this._timer.Tick += _timer_Tick;

            MainPage.tabControl.Hide();

            photoCamera = new PhotoCamera();
            photoCamera.Initialized += photoCamera_Initialized;
            this.vBrush.SetSource(photoCamera);
        }


        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
                this._timer.Stop();
                try
                {
                    photoCamera.CancelFocus();

                }
                catch
                {
                }
 

            if (photoCamera != null)
            {
                photoCamera.Dispose();
            }

            base.OnNavigatedFrom(e);
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            string type = "";
            if (NavigationContext.QueryString.TryGetValue("type", out type) && type == "qrcode")
            {
                this._reader = new QRCodeReader();
            }
            else
            {
                this._reader = new EAN13Reader();
            }

            base.OnNavigatedTo(e);
        }

        private void photoCamera_Initialized(object sender, CameraOperationCompletedEventArgs e)
        {
            if (e.Succeeded)
            {
                int width = Convert.ToInt32(photoCamera.PreviewResolution.Width);
                int height = Convert.ToInt32(photoCamera.PreviewResolution.Height);
                this._luminance = new PhotoCameraLuminanceSource(width, height);

                this.Dispatcher.BeginInvoke(() =>
                {
                    this.transform.Rotation = photoCamera.Orientation;
                    this._timer.Start();
                    this.storyScanning.Begin();
                    this.tbkResult.Text = StrScanning;
                });
                photoCamera.FlashMode = FlashMode.Off;
                photoCamera.Focus();

                this._isCameraInitialized = true;
            }
        }

        private void _timer_Tick(object sender, EventArgs e)
        {
            this.ScanPreviewBuffer();
        }

        private void ScanPreviewBuffer()
        {
            try
            {
                photoCamera.GetPreviewBufferY(_luminance.PreviewBufferY);
                var binarizer = new HybridBinarizer(_luminance);
                var binBitmap = new BinaryBitmap(binarizer);
                Result result = _reader.decode(binBitmap);
                if (result != null)
                {
                    this._timer.Stop();
                    this.storyScanning.Stop();
                    Dispatcher.BeginInvoke(() =>
                    {
                        this.tbkResult.Text = StrScanCompleted + result.Text;
                    });
                }
                else
                {
                    photoCamera.Focus();
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message);
            }
        }

        private void appbarSelectImage_Click(object sender, EventArgs e)
        {
            PhotoChooserTask select = new PhotoChooserTask() { ShowCamera = false, PixelWidth = 480, PixelHeight = 480 };
            select.Completed += select_Completed;
            select.Show();
        }

        private void select_Completed(object sender, PhotoResult e)
        {
            if (e.TaskResult == TaskResult.OK)
            {
                WriteableBitmap r = new WriteableBitmap(480, 480);
                r.SetSource(e.ChosenPhoto);

                //多格式解码
                //MultiFormatReader multiFormatReader = new MultiFormatReader();
                //// 解码的参数  
                //Dictionary<DecodeHintType, Object> hint = new Dictionary<DecodeHintType, Object>(2);
                //// 可以解析的编码类型  
                //List<BarcodeFormat> decodeFormats = new List<BarcodeFormat>();
                //if (decodeFormats == null || decodeFormats.Count == 0)
                //{
                //    decodeFormats = new List<BarcodeFormat>();
                //    设置可解码格式
                //    decodeFormats.Add(BarcodeFormat.EAN_13);
                //    decodeFormats.Add(BarcodeFormat.QR_CODE);
                //    decodeFormats.Add(BarcodeFormat.DATA_MATRIX);
                //}
                //hint.Add(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
                //// 设置继续的字符编码格式为UTF8  
                //hint.Add(DecodeHintType.CHARACTER_SET, "UTF8");
                //// 设置解析配置参数  
                //multiFormatReader.Hints = hint;

                BitmapLuminanceSource luminance = new BitmapLuminanceSource(r);
                HybridBinarizer binarizer = new HybridBinarizer(luminance);
                BinaryBitmap binBitmap = new BinaryBitmap(binarizer);
                Result result = _reader.decode(binBitmap);
                if (result != null)
                {
                    this.Dispatcher.BeginInvoke(delegate
                    {
                        this.tbkResult.Text = StrScanCompleted + result.Text;
                    });
                }
                else
                {
                    this.tbkResult.Text = StrNoQRDecode;
                    MessageBox.Show(StrNoQRDecode, "提示", MessageBoxButton.OK);
                }
            }
        }
    }

    internal class PhotoCameraLuminanceSource : LuminanceSource
    {
        public byte[] PreviewBufferY
        {
            get;
            private set;
        }

        public PhotoCameraLuminanceSource(int width, int height)
            : base(width, height)
        {
            PreviewBufferY = new byte[width * height];
        }

        public override byte[] Matrix
        {
            get { return (byte[])(Array)PreviewBufferY; }
        }

        public override byte[] getRow(int y, byte[] row)
        {
            if (row == null || row.Length < Width)
            {
                row = new byte[Width];
            }
            for (int i = 0; i < Height; i++)
                row[i] = (byte)PreviewBufferY[i * Width + y];

            return row;
        }

    }

    internal class BitmapLuminanceSource : LuminanceSource
    {
        private byte[] _bitmapPixels;

        public BitmapLuminanceSource(WriteableBitmap bitmap)
            : base(bitmap.PixelWidth, bitmap.PixelHeight)
        {
            int[] data = new int[bitmap.PixelWidth * bitmap.PixelHeight];

            this._bitmapPixels = new byte[bitmap.PixelWidth * bitmap.PixelHeight];

            data = bitmap.Pixels;
            for (int i = 0; i < data.Length; i++)
            {
                this._bitmapPixels[i] = (byte)data[i];
            }
        }

        public override byte[] getRow(int y, byte[] row)
        {
            Array.Copy(this._bitmapPixels, y * this.Width, row, 0, this.Width);
            return row;
        }

        public override byte[] Matrix
        {
            get
            {
                return this._bitmapPixels;
            }
        }
    }

}
View Code

windows phone 开发之二维码扫描

上一篇:【Python实战07】用with来处理文件


下一篇:C++常见用法规范整理