WindowsPhone8.1 開發-- 二維碼掃描


隨着 WinRT 8.1 API 的發布Windows 8.1  Windows Phone 8.1 (基於 WinRT) 應用程序開發模型經歷戲劇性收斂性一些特定於平台的考慮我們現在可以 Windows 使用幾乎相同的 XAML 框架 API 來開發 Windows Phone 開發應用程序

"舊的"基於 Windows Phone 8.0 Silverlight API 繼續得到支持改善基於 WinRT 融合模型顯然未來

 

所以抽時間實現了wp8.1實現二維碼掃描的功能

1. 在項目中添加對Zxing的引用

  Zxing示例代碼下載地址:http://zxingnet.codeplex.com/

2.添加頁面代碼

  

 <Grid x:Name="LayoutRoot"  Background="Black">
        <Grid Background="Black">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="300"/>
                <ColumnDefinition Width="50"/>
            </Grid.ColumnDefinitions>
            <Grid Grid.Column="0" Height="366" Margin="0,0,0,0">

            </Grid>
            <!--取景器區域-->
            <Grid Grid.Column="1" x:Name="ScanViewGrid" Margin="0,0,0,0">
                <Grid.Resources>
                    <Storyboard x:Name="myStoryboard">
                        <DoubleAnimation
                                    Storyboard.TargetName="imgScan"
                                    Storyboard.TargetProperty="(Canvas.Top)"
                                    Duration="0:0:2.5"
                                    From="0"
                                    To="300"
                                    RepeatBehavior="Forever"/>
                    </Storyboard>
                </Grid.Resources>
                <!--掃描線-->
                
                    <Canvas Width="300"  Canvas.Top="170"  Height="300">
                        <CaptureElement  Stretch="UniformToFill" x:Name="VideoCapture"  Width="300" Height="300"  >
                         
                        </CaptureElement>
                        <Image x:Name="imgScan" Source="/Assets/img/light.png"  Width="300" Height="40" Stretch="Fill"/>

                        <Image x:Name="CaptureImage" Width="300" Height="300"  Visibility="Collapsed" />
                    </Canvas>
              
          
            </Grid>
            <Grid Grid.Column="2" Margin="0,0,0,0"/>
        </Grid>
      
        <TextBlock x:Name="Error" VerticalAlignment="Bottom" FontSize="32" Width="400" TextAlignment="Center" />
        <TextBlock x:Name="ScanResult" Text="hhh" FontSize="25" Foreground="White" VerticalAlignment="Bottom" TextAlignment="Center" Width="400"/>
    </Grid>
 

3.功能實現

 

  public sealed partial class QCodeView : Page
    {
        private readonly MediaCapture _mediaCapture = new MediaCapture();
        private Result _result;
        private NavigationHelper navigationHelper;
        private ObservableDictionary defaultViewModel = new ObservableDictionary();
        private DispatcherTimer _timer;
      
        public QCodeView()
        {
            this.InitializeComponent();
            //設備屏幕方向
            DisplayInformation.AutoRotationPreferences = DisplayOrientations.Portrait;
            ///隱藏StatusBar
            var statusBar = StatusBar.GetForCurrentView();
            statusBar.HideAsync();
            this.navigationHelper = new NavigationHelper(this);
            this.navigationHelper.LoadState += this.NavigationHelper_LoadState;
            this.navigationHelper.SaveState += this.NavigationHelper_SaveState;
        }

        /// <summary>
        /// 獲取與此 <see cref="Page"/> 關聯的 <see cref="NavigationHelper"/>/// </summary>
        public NavigationHelper NavigationHelper
        {
            get { return this.navigationHelper; }
        }

        /// <summary>
        /// 獲取此 <see cref="Page"/> 的視圖模型。
        /// 可將其更改為強類型視圖模型。
        /// </summary>
        public ObservableDictionary DefaultViewModel
        {
            get { return this.defaultViewModel; }
        }

        /// <summary>
        /// 使用在導航過程中傳遞的內容填充頁。  在從以前的會話
        /// 重新創建頁時,也會提供任何已保存狀態。
        /// </summary>
        /// <param name="sender">
        /// 事件的來源; 通常為 <see cref="NavigationHelper"/>
        /// </param>
        /// <param name="e">事件數據,其中既提供在最初請求此頁時傳遞給
        /// <see cref="Frame.Navigate(Type, Object)"/> 的導航參數,又提供
        /// 此頁在以前會話期間保留的狀態的
        /// 字典。 首次訪問頁面時,該狀態將為 null。</param>
        private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
        {
        }

        /// <summary>
        /// 保留與此頁關聯的狀態,以防掛起應用程序或
        /// 從導航緩存中放棄此頁。值必須符合
        /// <see cref="SuspensionManager.SessionState"/> 的序列化要求。
        /// </summary>
        /// <param name="sender">事件的來源;通常為 <see cref="NavigationHelper"/></param>
        ///<param name="e">提供要使用可序列化狀態填充的空字典
        ///的事件數據。</param>
        private void NavigationHelper_SaveState(object sender, SaveStateEventArgs e)
        {

        }

        #region NavigationHelper 注冊

        /// <summary>
        /// 此部分中提供的方法只是用於使
        /// NavigationHelper 可響應頁面的導航方法。
        /// <para>
        /// 應將頁面特有的邏輯放入用於
        /// <see cref="NavigationHelper.LoadState"/>
        ///<see cref="NavigationHelper.SaveState"/> 的事件處理程序中。
        /// 除了在會話期間保留的頁面狀態之外
        /// LoadState 方法中還提供導航參數。
        /// </para>
        /// </summary>
        /// <param name="e">提供導航方法數據和
        /// 無法取消導航請求的事件處理程序。</param>
        protected  override void OnNavigatedTo(NavigationEventArgs e)
        {
          
            myStoryboard.Begin();
            InitVideoCapture();
            InitVideoTimer();
                
            this.navigationHelper.OnNavigatedTo(e);
        }


        /// <summary>
        /// 初始化攝像
        /// </summary>
        private async void InitVideoCapture()
        {
            ///攝像頭的檢測
            var cameras = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
            if (cameras.Count < 1)
            {
                Error.Text = "設備沒有攝像頭,讀取本地資源";
                await DecodeStaticResource();
                return;
            }
           
            ///  創建 MediaCaptureInitializationSettings 對象的新實例。
            var settings = new MediaCaptureInitializationSettings
            {
                StreamingCaptureMode = StreamingCaptureMode.AudioAndVideo,
                MediaCategory = MediaCategory.Other,
                AudioProcessing = Windows.Media.AudioProcessing.Default,
                VideoDeviceId = cameras[1].Id
            };
            //if (cameras.Count == 1)
            //{
            //    settings = new MediaCaptureInitializationSettings { VideoDeviceId = cameras[0].Id }; // 0 => front, 1 => back
            //}
            //else
            //{
            //    settings = new MediaCaptureInitializationSettings { VideoDeviceId = cameras[1].Id }; // 0 => front, 1 => back
            //}

            await _mediaCapture.InitializeAsync(settings);
            VideoCapture.Source = _mediaCapture;
            await _mediaCapture.StartPreviewAsync();
        }
        private void InitVideoTimer()
        {
            _timer = new DispatcherTimer();
            _timer.Interval = TimeSpan.FromSeconds(6);
            _timer.Tick += _timer_Tick;
            _timer.Start();

        }
        private bool IsBusy = false;
        async void _timer_Tick(object sender, object e)
        {
            try
            {
                while (_result == null)
                {
                    if (!IsBusy)
                    {
                        IsBusy = true;
                        ///獲取焦點
                        //var autoFocusSupported = _mediaCapture.VideoDeviceController.FocusControl.SupportedFocusModes.Contains(FocusMode.Auto);
                        //if (autoFocusSupported)
                        //{
                        //    var focusSettings = new FocusSettings
                        //    {
                        //        Mode = FocusMode.Auto,
                        //        AutoFocusRange = AutoFocusRange.Normal
                        //    };
                        //    _mediaCapture.VideoDeviceController.FocusControl.Configure(focusSettings);
                        //    //await _mediaCapture.VideoDeviceController.FocusControl.FocusAsync().AsTask(_cancellationTokenSource.Token);
                        //}

                        var photoStorageFile = await KnownFolders.PicturesLibrary.CreateFileAsync("qcode.jpg", CreationCollisionOption.ReplaceExisting);
                        await _mediaCapture.CapturePhotoToStorageFileAsync(ImageEncodingProperties.CreateJpeg(), photoStorageFile);

                        var stream = await photoStorageFile.OpenReadAsync();
                        // initialize with 1,1 to get the current size of the image
                        var writeableBmp = new WriteableBitmap(1, 1);
                        writeableBmp.SetSource(stream);
                        // and create it again because otherwise the WB isn't fully initialized and decoding
                        // results in a IndexOutOfRange
                        writeableBmp = new WriteableBitmap(writeableBmp.PixelWidth, writeableBmp.PixelHeight);
                        stream.Seek(0);
                        writeableBmp.SetSource(stream);
                        _result = ScanBitmap(writeableBmp);
                        await photoStorageFile.DeleteAsync(StorageDeleteOption.PermanentDelete);
                    }
                    if (_result != null)
                    {
                        await _mediaCapture.StopPreviewAsync();
                        VideoCapture.Visibility = Visibility.Collapsed;
                        CaptureImage.Visibility = Visibility.Visible;
                        ScanResult.Text = _result.Text;
                        _timer.Stop();
                        myStoryboard.Stop();
                        imgScan.Visibility = Visibility.Collapsed;
                       
                    }  
                    IsBusy = false;
                 
                }
            }
            catch (Exception ex)
            {
               
                IsBusy = false;
                //Error.Text = ex.Message;
            }
        }
        /// <summary>
        /// 讀取本地資源
        /// </summary>
        /// <returns></returns>
        private async System.Threading.Tasks.Task DecodeStaticResource()
        {
            var file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(@"Assets\1.png");
            var stream = await file.OpenReadAsync();
            // initialize with 1,1 to get the current size of the image
            var writeableBmp = new WriteableBitmap(1, 1);
            writeableBmp.SetSource(stream);
            // and create it again because otherwise the WB isn't fully initialized and decoding
            // results in a IndexOutOfRange
            writeableBmp = new WriteableBitmap(writeableBmp.PixelWidth, writeableBmp.PixelHeight);
            stream.Seek(0);
            writeableBmp.SetSource(stream);
            CaptureImage.Source = writeableBmp;
            VideoCapture.Visibility = Visibility.Collapsed;
            CaptureImage.Visibility = Visibility.Visible;

            _result = ScanBitmap(writeableBmp);
            if (_result != null)
            {
                ScanResult.Text += _result.Text;
            }
            return;
        }
        /// <summary>
        /// 解析二維碼圖片
        /// </summary>
        /// <param name="writeableBmp">拍攝的圖片</param>
        /// <returns></returns>
        private Result ScanBitmap(WriteableBitmap writeableBmp)
        {
            var barcodeReader = new BarcodeReader
            {
                TryHarder = true,
                AutoRotate = true
            };
            var result = barcodeReader.Decode(writeableBmp);

            if (result != null)
            {
                CaptureImage.Source = writeableBmp;
            }

            return result;
        }
        /// <summary>
        /// 頁面離開時對_mediaCapture對象進行釋放 
        /// 防止內存溢出及資源占用
        /// </summary>
        /// <param name="e"></param>
        protected override async void OnNavigatedFrom(NavigationEventArgs e)
        {
            try
            {
                await _mediaCapture.StopPreviewAsync();
                await _mediaCapture.StopRecordAsync();
                _mediaCapture.Dispose();
            }
            catch (Exception)
            {

            }
            this.navigationHelper.OnNavigatedFrom(e);
        }
        #endregion
    }

 源碼下載地址:http://vdisk.weibo.com/s/ztJnMX2jYqaK3

  注意事項: 在調試時如果出現死機現象 ,請長按鎖屏鍵+音量(-)鍵 方可重啟手機。

 學習交流QQ群:157153754 (入群成員請將您的昵稱改為: 城市-昵稱 )


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM