Read QR Code from Image or Stream
Ever needed to find a QR code in an image or MemoryStream? With the snippet below you can. It uses the ZXing.Net Library to scan a MemoryStream for a QR Code and output the text.
The code below is for a WPF App. But the C# code itself can be used in other projects as well. The App can read a QR code from disk or take a screenshot of the desktop (even with multiple monitors) and search for the QR code.
Another example would be to create a tool that scans the feed from a webcam or IP camera every x seconds and do something when you hold a QR code in front of it.
Code Snippets
The XAML of the MainWindow.
<Window x:Class="ReadQrCodeFromStream.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ReadQrCodeFromStream" mc:Ignorable="d" Title="QR Code Reader" Height="400" Width="370" Background="#566895"> <StackPanel> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="10" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="15" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="10" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="10" /> <RowDefinition Height="30" /> <RowDefinition Height="30" /> <RowDefinition Height="70" /> </Grid.RowDefinitions> <Button Name="ReadFromDesktop" Grid.Row="1" Grid.Column="1" Content="Read QR Code from Desktop" Click="ReadFromDesktop_Click" Background="#435175" BorderBrush="#2a385a" Foreground="White" /> <Button Name="ReadFromDisk" Grid.Row="1" Grid.Column="3" Content="Read QR Code from Disk" Click="ReadFromDisk_Click" Background="#435175" BorderBrush="#2a385a" Foreground="White" /> <TextBlock Name="TextBlock1" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" TextWrapping="Wrap" Foreground="White" /> </Grid> <Image Name="Image1" Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="3" Width="200" Height="200" Margin="0, 10, 0, 0" /> </StackPanel> </Window>
And the MainWindow C# code to make it all work.
using System; using System.Windows; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; using System.IO; using System.Windows.Media.Imaging; using System.Threading.Tasks; using ZXing; using ZXing.Common; namespace ReadQrCodeFromStream { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void ReadFromDesktop_Click(object sender, RoutedEventArgs e) { //reset the ui ResetUI(); //make sure the UI updates first before scanning the desktop otherwise it will find it's previously scanned qr code await Task.Run(() => Task.Delay(1)); //get the size of the virtual screen (includes all monitors) int left = SystemInformation.VirtualScreen.Left; int top = SystemInformation.VirtualScreen.Top; int width = SystemInformation.VirtualScreen.Width; int height = SystemInformation.VirtualScreen.Height; //create a bitmap of the entire desktop using (var stream = new MemoryStream()) using (var bmp = new Bitmap(width, height)) using (var g = Graphics.FromImage(bmp)) { g.CopyFromScreen(left, top, 0, 0, bmp.Size); //save to disk or a memorystream if you need the screenshot elsewhere //bmp.Save(stream, ImageFormat.Jpeg); //bmp.Save(@"c:\temp\test.jpg", ImageFormat.Jpeg); //try to find a qr code in the screenshot and display result TextBlock1.Text = FindQrCodeInImage(bmp); } } private void ReadFromDisk_Click(object sender, EventArgs e) { //reset the ui ResetUI(); //open the file dialog with only images as the filter var dialog = new Microsoft.Win32.OpenFileDialog() { Filter = "QR Code | *.jpg; *.jpeg; *.gif; *.bmp; *.png" }; //a file is selected if (dialog.ShowDialog() == true) { //read the selected file as a byte array var bin = File.ReadAllBytes(dialog.FileName); //try cath if the selected file is not an image or is corrupted try { //make a bmp from the selected file using (var stream = new MemoryStream(bin)) using (var bmp = new Bitmap(stream)) { //read the qr code and show the result TextBlock1.Text = FindQrCodeInImage(bmp); } } catch { } } } private string FindQrCodeInImage(Bitmap bmp) { //decode the bitmap and try to find a qr code var source = new BitmapLuminanceSource(bmp); var bitmap = new BinaryBitmap(new HybridBinarizer(source)); var result = new MultiFormatReader().decode(bitmap); //no qr code found in bitmap if (result == null) { System.Windows.MessageBox.Show("No QR Code found!"); return null; } //create a new qr code image var writer = new BarcodeWriter { Format = BarcodeFormat.QR_CODE, Options = new EncodingOptions { Height = 300, Width = 300 } }; //write the result to the new qr code bmp image var qrcode = writer.Write(result.Text); //make the bmp transparent qrcode.MakeTransparent(); //show the found qr code in the app var stream = new MemoryStream(); qrcode.Save(stream, ImageFormat.Png); //display the new qr code in the ui Image1.Source = BitmapFrame.Create(stream); Image1.Visibility = Visibility.Visible; //and/or save the new qr code image to disk if needed try { //qrcode.Save($"qr_code_{DateTime.Now.ToString("yyyyMMddHHmmss")}.gif", ImageFormat.Gif); } catch { //handle disk write errors here } //return the found qr code text return result.Text; } private void ResetUI() { this.Dispatcher.Invoke(() => { Image1.Visibility = Visibility.Hidden; TextBlock1.Text = ""; }); } } }