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 = "";
});
}
}
}