最新ZXing.netでのQRコード読み取り

## 初めに
１年ぶりにZXing.Netを使ってQRコードを読み取るプログラムを組んでいたのですが、過去コードがコピペできず仕様変更があったので最新でのQRコードの読み取り方法を自分メモも担いで書き記しておこうと思います
## 環境
・.Net6
・VisualStudio2022
・ZXing.Net 0.16.9
## QRコードの読み取り
今回は引数にBitmapを指定することでそのBitmapイメージに含まれるQRコードを読み取るような関数を作ります
~~~C#:MainWindow.cs
using ZXing.QrCode;
using ZXing;
using System.IO;
using ZXing.Common;

private void qrRead(Bitmap img) {
            TextBlock_OutputShowing.Text = "読み取り中";
            if (canReadQR == false) return;
            try {
                MemoryStream memoryStream = new MemoryStream();
                img.Save(memoryStream, ImageFormat.Bmp);
                byte[] byteArray = memoryStream.GetBuffer();
                LuminanceSource source = new RGBLuminanceSource(byteArray,img.Width,img.Height);
                var binarizer = new HybridBinarizer(source);
                var binBitmap = new BinaryBitmap(binarizer);
                QRCodeReader qrCodeReader = new QRCodeReader();
                Result str = qrCodeReader.decode(binBitmap);
                Dispatcher.Invoke(() =>
                {
                    TextBlock_OutputShowing.Text = str != null ? "QRコードの内容: " + str.Text : "読み取り中";
                });
            }
            catch (Exception ex) {
                Dispatcher.Invoke(() => {
                    TextBlock_OutputShowing.Text = "error : " + ex.Message;
                });
            }
        }
~~~
以上のようにしてBitmap imgのQRコードを読み取ることができます
昔は非ジェネリック型のBarcodeReaderが用意されていて次のようにQRコード、バーコードを読み取ることができました
~~~C#:Old.cs
private void qrRead(Bitmap img) {
        ZXing.BarcodeReader reader = new ZXing.BarcodeReader();
        ZXing.Result result = reader.Decode(new Bitmap(img));
}
~~~

## 拡張
拡張としてデバイスのカメラから映像を取得しながらQRコードを読み取ってみます
以下のようにCombobox,Image,TextBlockを用意しました
~~~xml:
<Grid>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Grid Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center">
                <StackPanel Orientation="Vertical">
                    <ComboBox SelectionChanged="AvaiCameraBox_SelectionChanged" DataContextChanged="AvaiCameraBox_DataContextChanged" x:Name="AvaiCameraBox" />
                    <Border BorderThickness="2" BorderBrush="Black">
                        <Image x:Name="ImageBox_Camera" Width="300" Height="300" />
                    </Border>
                </StackPanel>
            </Grid>
            <Grid Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center">
                <TextBlock x:Name="TextBlock_OutputShowing" Text="this is output showing"/>
            </Grid>
        </Grid>
    </Grid>
~~~
C#側ではAForge.Videoを使って映像をImageに出力しながらZxingでQRコードを読み取るといった感じになっています
~~~C#:
using AForge.Video;
using AForge.Video.DirectShow;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using ZXing;
using ZXing.Common;
using ZXing.QrCode;

private VideoCaptureDevice videoSource = null;
public FilterInfoCollection videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
public VideoCaptureDevice videosource;
private bool canReadQR = true;
private bool DeviceExist = false;
private void getCameraInfo() {
        try {
            // 端末で認識しているカメラデバイスの一覧を取得
            videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            AvaiCameraBox.Items.Clear();
             if (videoDevices.Count == 0)
                throw new ApplicationException();
                foreach (FilterInfo device in videoDevices) {
                //カメラデバイスの一覧をコンボボックスに追加
                AvaiCameraBox.Items.Add(device.Name);
                AvaiCameraBox.SelectedIndex = 0;
                DeviceExist = true;
            }
        }
        catch (ApplicationException) {
            DeviceExist = false;
            AvaiCameraBox.Items.Add("Deviceが存在していません。");
        }
    }

    private void videoRendering(object sender, NewFrameEventArgs eventArgs) {
        Bitmap src = (Bitmap)eventArgs.Frame.Clone();
        BitmapFrame imgSource;
            using (Stream st = new MemoryStream()) {
                src.Save(st, ImageFormat.Bmp);
                st.Seek(0, SeekOrigin.Begin);
                imgSource = BitmapFrame.Create(st, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
            }

            try {
                //qrRead(src);
                Dispatcher.Invoke(() => {
                    ImageBox_Camera.Source = imgSource;
                    qrRead(src);
                });
            }
            catch {
                //MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace);
            }
        }

        private void CloseVideoSource() {
            if (!(videoSource == null))
                if (videoSource.IsRunning) {
                    videoSource.SignalToStop();
                    videoSource = null;
                }
        }

        private void qrRead(Bitmap img) {
            TextBlock_OutputShowing.Text = "読み取り中";
            if (canReadQR == false) return;
            try {
                MemoryStream memoryStream = new MemoryStream();
                img.Save(memoryStream, ImageFormat.Bmp);
                byte[] byteArray = memoryStream.GetBuffer();
                LuminanceSource source = new RGBLuminanceSource(byteArray,img.Width,img.Height);
                var binarizer = new HybridBinarizer(source);
                var binBitmap = new BinaryBitmap(binarizer);
                QRCodeReader qrCodeReader = new QRCodeReader();
                Result str = qrCodeReader.decode(binBitmap);
                Dispatcher.Invoke(() =>
                {
                    TextBlock_OutputShowing.Text = str != null ? "QRコードの内容: " + str.Text : "読み取り中";
                });
            }
            catch (Exception ex) {
                Dispatcher.Invoke(() => {
                    TextBlock_OutputShowing.Text = "error : " + ex.Message;
                });
            }
        }

        private void AvaiCameraBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            TextBlock_OutputShowing.Text = "selection changed";
            if (DeviceExist) {
                videoSource = new VideoCaptureDevice(videoDevices[AvaiCameraBox.SelectedIndex].MonikerString);
                videoSource.NewFrame += new NewFrameEventHandler(videoRendering);
                CloseVideoSource();
                videoSource.Start();
            }
        }
~~~