im trying to scan a QR Code (with Zxing - the decode method of ZXing works only with Bitmap) from Camera in WPF. Here is what i have:
void Window2_Loaded(object sender, RoutedEventArgs e)
{
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 5, 0);
LoaclWebCamsCollection = new FilterInfoCollection(FilterCategory.VideoInputDevice);
LocalWebCam = new VideoCaptureDevice(LoaclWebCamsCollection[1].MonikerString);
LocalWebCam.NewFrame += new NewFrameEventHandler(Cam_NewFrame);
LocalWebCam.Start();
dispatcherTimer.Start();
}
convert method (bitmap source to bitmap) - got it from another thread:
Bitmap GetBitmap(BitmapSource source)
{
Bitmap bmp = new Bitmap(
source.PixelWidth,
source.PixelHeight,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
BitmapData data = bmp.LockBits(
new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size),
ImageLockMode.WriteOnly,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
source.CopyPixels(
Int32Rect.Empty,
data.Scan0,
data.Height * data.Stride,
data.Stride);
bmp.UnlockBits(data);
return bmp;
}
and the timer method:
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
BarcodeReader Reader = new BarcodeReader();
if (frameHolder.Source != null)
{
Result result = Reader.Decode(GetBitmap((BitmapSource)frameHolder.Source));
decoded = result.ToString().Trim();
hey.Text = decoded;
}
}
and the new frame method:
void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
try
{
System.Drawing.Bitmap img = (Bitmap)eventArgs.Frame.Clone();
MemoryStream ms = new MemoryStream();
img.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = ms;
bi.EndInit();
bi.Freeze();
Dispatcher.BeginInvoke(new ThreadStart(delegate
{
frameHolder.Source = bi;
}));
}
catch (Exception ex)
{
}
}
frameHolder
is my Image Control.
What am i doing wrong?. Im pretty sure that he cant get the Bitmap
out of the frameHolder
but i dont know why.
ZXing.Net provides a special version of the BarcodeReader class which consumes BitmapSource instances. Normally if you add the ZXing.Net package via nuget to your project there should be a reference to the zxing.presentation.dll. If not add it manually from the binary distribution. The special BarcodeReader is located in the namespace ZXing.Presentation. The following modified version of your method should work:
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
BarcodeReader Reader = new ZXing.Presentation.BarcodeReader();
if (frameHolder.Source != null)
{
Result result = Reader.Decode((BitmapSource)frameHolder.Source);
decoded = result?.Text;
hey.Text = decoded;
}
}
Don't forget to check for "result == null" which happens if no barcode is found.
By the way, forget your DispatcherTimer solution and make all the work inside Cam_NewFrame.
void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
try
{
System.Drawing.Bitmap img = (Bitmap)eventArgs.Frame.Clone();
// TODO: add some kind of mutex or similar here so that you don't start a new Decode before the previous one is finished
Dispatcher.BeginInvoke(new ThreadStart(delegate
{
// use the original BarcodeReader because we are using the bitmap instance directly
BarcodeReader Reader = new ZXing.BarcodeReader();
Result result = Reader.Decode(img);
decoded = result?.Text;
hey.Text = decoded;
}));
MemoryStream ms = new MemoryStream();
img.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = ms;
bi.EndInit();
bi.Freeze();
Dispatcher.BeginInvoke(new ThreadStart(delegate
{
frameHolder.Source = bi;
}));
}
catch (Exception ex)
{
}
}
Throw away the following
...
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 5, 0);
...
dispatcherTimer.Start();
...
Bitmap GetBitmap(BitmapSource source)
{
...
}
...
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
...
}
...
I didn't compile or test the code. Take it more like hints in the right direction.