How to Build Xamarin.Forms Barcode QR Code Scanner

Getting Started with Xamarin.Forms Custom Renderers

Our goal is to create camera preview interface and invoke Dynamsoft Barcode Reader SDK for decoding barcode and QR code, thus it is inevitable to put lots of effort into platform-specific code. Fortunately, it is not necessary to reinvent the wheel. There are some official samples demonstrating how to use the custom renders to bridge the shared code and platform-specific code.

  • Camera API for Android
  • Native code takes over the whole content page rendering
  • Camera2 API for Android
  • Native code renders the custom view
svn checkout https://github.com/xamarin/xamarin-forms-samples/trunk/CustomRenderers/View

Implementing Xamarin.Forms Barcode QR Code Scanner

In the following paragraphs, we will show how to implement the barcode and QR code scanning feature in Xamarin.Forms. The steps include installing Dynamsoft Barcode Reader SDK, reading barcode and QR code from image file and live video stream, and drawing the results on overlay.

Install Dynamsoft Xamarin Barcode SDK for Android and iOS

Let’s open nuget package manager to search for dynamsoft xamarin barcode in Visual Studio.

Content Pages

The projects consists of three content pages: main page, picture page and camera page.

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BarcodeQrScanner.MainPage"
Title="Main Page">
<ContentPage.Content>
<StackLayout>
<Button x:Name="takePhotoButton" Text="Take Photo" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" Clicked="OnTakePhotoButtonClicked" />
<Button x:Name="takeVideoButton" Text="Take Video" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" Clicked="OnTakeVideoButtonClicked" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
x:Class="BarcodeQrScanner.PicturePage"
Title="Picture Page">
<ContentPage.Content>
<StackLayout>
<Label FontSize="18"
FontAttributes="Bold"
x:Name="ResultLabel"
Text="Results"
HorizontalOptions="Start"/>
<skia:SKCanvasView x:Name="canvasView"
WidthRequest="640" HeightRequest="640"
PaintSurface="OnCanvasViewPaintSurface" />

</StackLayout>
</ContentPage.Content>
</ContentPage>
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:BarcodeQrScanner;assembly=BarcodeQrScanner"
xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
x:Class="BarcodeQrScanner.CameraPage"
Title="Camera Page">
<Grid x:Name="scannerView" Margin="0">
<local:CameraPreview
x:Name="cameraView"
Camera="Rear"
ScanMode="Multiple"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
ResultReady="CameraPreview_ResultReady"/>
<Label FontSize="18"
FontAttributes="Bold"
TextColor="Blue"
x:Name="ResultLabel"
Text="Results"
HorizontalOptions="Center"
VerticalOptions="Center" />
<skia:SKCanvasView x:Name="canvasView"
Margin="0"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
PaintSurface="OnCanvasViewPaintSurface" />

</Grid>
</ContentPage>

Xamarin.Forms DependencyService

Barcode reader object needs to be created in native code. To invoke native platform functionality from shared code, we use the DependencyService class.

  1. In IBarcodeQRCodeService.cs, define an IBarcodeQRCodeService interface and a BarcodeQrData structure. The IBarcodeQRCodeService interface contains a method for initializing the SDK license and a method for decoding barcode and QR code from a file. The BarcodeQrData structure contains the barcode and QR code results.
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace BarcodeQrScanner.Services
{
public class BarcodeQrData
{
public string text;
public string format;
public SKPoint[] points;
}

public interface IBarcodeQRCodeService
{
Task<int> InitSDK(string license);
Task<BarcodeQrData[]> DecodeFile(string filePath);
}
}
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Com.Dynamsoft.Dbr;
using BarcodeQrScanner.Droid.Services;
using BarcodeQrScanner.Services;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

[assembly: Dependency(typeof(BarcodeQRCodeService))]
namespace BarcodeQrScanner.Droid.Services
{
public class DBRLicenseVerificationListener : Java.Lang.Object, IDBRLicenseVerificationListener
{
public void DBRLicenseVerificationCallback(bool isSuccess, Java.Lang.Exception error)
{
if (!isSuccess)
{
System.Console.WriteLine(error.Message);
}
}
}

public class BarcodeQRCodeService: IBarcodeQRCodeService
{
BarcodeReader reader;

Task<int> IBarcodeQRCodeService.InitSDK(string license)
{
BarcodeReader.InitLicense(license, new DBRLicenseVerificationListener());
reader = new BarcodeReader();
TaskCompletionSource<int> taskCompletionSource = new TaskCompletionSource<int>();
taskCompletionSource.SetResult(0);
return taskCompletionSource.Task;
}

Task<BarcodeQrData[]> IBarcodeQRCodeService.DecodeFile(string filePath)
{
BarcodeQrData[] output = null;
try
{
PublicRuntimeSettings settings = reader.RuntimeSettings;
settings.ExpectedBarcodesCount = 0;
reader.UpdateRuntimeSettings(settings);
TextResult[] results = reader.DecodeFile(filePath);
if (results != null)
{
output = new BarcodeQrData[results.Length];
int index = 0;
foreach (TextResult result in results)
{
BarcodeQrData data = new BarcodeQrData();
data.text = result.BarcodeText;
data.format = result.BarcodeFormatString;
LocalizationResult localizationResult = result.LocalizationResult;
data.points = new SKPoint[localizationResult.ResultPoints.Count];
int pointsIndex = 0;
foreach (Com.Dynamsoft.Dbr.Point point in localizationResult.ResultPoints)
{
SKPoint p = new SKPoint();
p.X = point.X;
p.Y = point.Y;
data.points[pointsIndex++] = p;
}
output[index++] = data;
}
}
}
catch (Exception e)
{
}

TaskCompletionSource<BarcodeQrData[]> taskCompletionSource = new TaskCompletionSource<BarcodeQrData[]>();
taskCompletionSource.SetResult(output);
return taskCompletionSource.Task;
}
}
}
using System;
using Xamarin.Forms;
using BarcodeQrScanner.Services;
using DBRiOS;
using BarcodeQrScanner.iOS.Services;
using System.Threading.Tasks;
using Foundation;
using SkiaSharp;

[assembly: Dependency(typeof(BarcodeQRCodeService))]
namespace BarcodeQrScanner.iOS.Services
{
public class DBRLicenseVerificationListener : NSObject, IDBRLicenseVerificationListener
{
public void DBRLicenseVerificationCallback(bool isSuccess, NSError error)
{
if (error != null)
{
System.Console.WriteLine(error.UserInfo);
}
}
}

public class BarcodeQRCodeService: IBarcodeQRCodeService
{
DynamsoftBarcodeReader reader;



Task<int> IBarcodeQRCodeService.InitSDK(string license)
{
DynamsoftBarcodeReader.InitLicense(license, new DBRLicenseVerificationListener());
reader = new DynamsoftBarcodeReader();
TaskCompletionSource<int> taskCompletionSource = new TaskCompletionSource<int>();
taskCompletionSource.SetResult(0);
return taskCompletionSource.Task;
}

Task<BarcodeQrData[]> IBarcodeQRCodeService.DecodeFile(string filePath)
{
BarcodeQrData[] output = null;
try
{
NSError error;

iPublicRuntimeSettings settings = reader.GetRuntimeSettings(out error);
settings.ExpectedBarcodesCount = 0;
reader.UpdateRuntimeSettings(settings, out error);

iTextResult[] results = reader.DecodeFileWithName(filePath, "", out error);
if (results != null)
{
output = new BarcodeQrData[results.Length];
int index = 0;
foreach (iTextResult result in results)
{
BarcodeQrData data = new BarcodeQrData();
data.text = result.BarcodeText;
data.format = result.BarcodeFormatString;
iLocalizationResult localizationResult = result.LocalizationResult;
data.points = new SKPoint[localizationResult.ResultPoints.Length];
int pointsIndex = 0;
foreach (NSObject point in localizationResult.ResultPoints)
{
SKPoint p = new SKPoint();
p.X = (float)((NSValue)point).CGPointValue.X;
p.Y = (float)((NSValue)point).CGPointValue.Y;
data.points[pointsIndex++] = p;
}
output[index++] = data;
}
}
}
catch (Exception e)
{
}

TaskCompletionSource<BarcodeQrData[]> taskCompletionSource = new TaskCompletionSource<BarcodeQrData[]>();
taskCompletionSource.SetResult(output);
return taskCompletionSource.Task;
}

}
}
_barcodeQRCodeService = DependencyService.Get<IBarcodeQRCodeService>();
await Task.Run(() =>
{
try
{
_barcodeQRCodeService.InitSDK("DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==");
}
catch (Exception ex)
{
DisplayAlert("Error", ex.Message, "OK");
}

return Task.CompletedTask;
});

Scan Barcode and QR Code from Image File

To take pictures with the camera, we use MediaPicker, which is provided by Xamarin.Essentials.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.BarcodeQrScanner" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
<application android:label="BarcodeQrScanner"></application>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<queries>
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
</manifest>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>CFBundleName</key>
<string>BarcodeQrScanner</string>
<key>NSCameraUsageDescription</key>
<string>This app is using the camera</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app is saving photo to the library</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs access to microphone for taking videos.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app needs access to the photo gallery for picking photos and videos.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to photos gallery for picking photos and videos.</string>
async void OnTakePhotoButtonClicked (object sender, EventArgs e)
{
try
{
var photo = await MediaPicker.CapturePhotoAsync();
await LoadPhotoAsync(photo);
Console.WriteLine($"CapturePhotoAsync COMPLETED: {PhotoPath}");
}
catch (FeatureNotSupportedException fnsEx)
{
// Feature is not supported on the device
}
catch (PermissionException pEx)
{
// Permissions not granted
}
catch (Exception ex)
{
Console.WriteLine($"CapturePhotoAsync THREW: {ex.Message}");
}
}

async Task LoadPhotoAsync(FileResult photo)
{
// canceled
if (photo == null)
{
PhotoPath = null;
return;
}
// save the file into local storage
var newFile = Path.Combine(FileSystem.CacheDirectory, photo.FileName);
using (var stream = await photo.OpenReadAsync())
using (var newStream = File.OpenWrite(newFile))
await stream.CopyToAsync(newStream);

PhotoPath = newFile;

await Navigation.PushAsync(new PicturePage(PhotoPath, _barcodeQRCodeService));
}
namespace BarcodeQrScanner
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class PicturePage : ContentPage
{
string path;
SKBitmap bitmap;
IBarcodeQRCodeService _barcodeQRCodeService;
public PicturePage(string imagepath, IBarcodeQRCodeService barcodeQRCodeService)
{
InitializeComponent();
_barcodeQRCodeService = barcodeQRCodeService;
path = imagepath;
try
{
using (var stream = new SKFileStream(imagepath))
{
bitmap = SKBitmap.Decode(stream);
}

}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}
async void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;

canvas.Clear();

var imageCanvas = new SKCanvas(bitmap);

SKPaint skPaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Blue,
StrokeWidth = 10,
};

BarcodeQrData[] data = await _barcodeQRCodeService.DecodeFile(path);
ResultLabel.Text = "";
if (data != null)
{
foreach (BarcodeQrData barcodeQrData in data)
{
ResultLabel.Text += barcodeQrData.text + "\n";
imageCanvas.DrawLine(barcodeQrData.points[0], barcodeQrData.points[1], skPaint);
imageCanvas.DrawLine(barcodeQrData.points[1], barcodeQrData.points[2], skPaint);
imageCanvas.DrawLine(barcodeQrData.points[2], barcodeQrData.points[3], skPaint);
imageCanvas.DrawLine(barcodeQrData.points[3], barcodeQrData.points[0], skPaint);
}
}
else
{
ResultLabel.Text = "No barcode QR code found";
}

float scale = Math.Min((float)info.Width / bitmap.Width,
(float)info.Height / bitmap.Height);
float x = (info.Width - scale * bitmap.Width) / 2;
float y = (info.Height - scale * bitmap.Height) / 2;
SKRect destRect = new SKRect(x, y, x + scale * bitmap.Width,
y + scale * bitmap.Height);

canvas.DrawBitmap(bitmap, destRect);
}

Scan Barcode and QR Code from Live Video Stream

Dynamsoft Barcode Reader supports multiple barcode and QR code detection. So we add a new property to the pre-created CameraPreview.cs file.

public enum ScanOptions
{
Single,
Multiple
}

public static readonly BindableProperty ScanProperty = BindableProperty.Create(
propertyName: "ScanMode",
returnType: typeof(ScanOptions),
declaringType: typeof(CameraPreview),
defaultValue: ScanOptions.Single);

public ScanOptions ScanMode
{
get { return (ScanOptions)GetValue(ScanProperty); }
set { SetValue(ScanProperty, value); }
}
public class ResultReadyEventArgs : EventArgs
{
public ResultReadyEventArgs(object result, int previewWidth, int previewHeight)
{
Result = result;
PreviewWidth = previewWidth;
PreviewHeight = previewHeight;
}

public object Result { get; private set; }
public int PreviewWidth { get; private set; }
public int PreviewHeight { get; private set; }

}

public event EventHandler<ResultReadyEventArgs> ResultReady;

public void NotifyResultReady(object result, int previewWidth, int previewHeight)
{
if (ResultReady != null)
{
ResultReady(this, new ResultReadyEventArgs(result, previewWidth, previewHeight));
}
}
public class CameraPreviewRenderer : FrameLayout, IVisualElementRenderer, IViewRenderer, TextureView.ISurfaceTextureListener, IPreviewCallback, Handler.ICallback
{
public void OnPreviewFrame(byte[] data, Android.Hardware.Camera camera)
{
try
{
YuvImage yuvImage = new YuvImage(data, ImageFormatType.Nv21,
previewWidth, previewHeight, null);
stride = yuvImage.GetStrides();
try
{
if (isReady)
{
if (backgroundHandler != null)
{
isReady = false;
Message msg = new Message();
msg.What = 100;
msg.Obj = yuvImage;
backgroundHandler.SendMessage(msg);
}
}
}
catch (BarcodeReaderException e)
{
e.PrintStackTrace();
}
}
catch (System.IO.IOException)
{
}
}

void PrepareAndStartCamera()
{
camera.SetPreviewCallback(null);
camera.StopPreview();

var display = activity.WindowManager.DefaultDisplay;
if (display.Rotation == SurfaceOrientation.Rotation0)
{
camera.SetDisplayOrientation(90);
}

if (display.Rotation == SurfaceOrientation.Rotation270)
{
camera.SetDisplayOrientation(180);
}

Parameters parameters = camera.GetParameters();
previewWidth = parameters.PreviewSize.Width;
previewHeight = parameters.PreviewSize.Height;
if (parameters.SupportedFocusModes.Contains(Parameters.FocusModeContinuousVideo))
{
parameters.FocusMode = Parameters.FocusModeContinuousVideo;
}
camera.SetParameters(parameters);
camera.SetPreviewCallback(this);
camera.StartPreview();
}
}
class CaptureOutput : AVCaptureVideoDataOutputSampleBufferDelegate
{
...

public override void DidOutputSampleBuffer(AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection)
{
if (ready)
{
ready = false;
CVPixelBuffer cVPixelBuffer = (CVPixelBuffer)sampleBuffer.GetImageBuffer();

cVPixelBuffer.Lock(CVPixelBufferLock.ReadOnly);
nint dataSize = cVPixelBuffer.DataSize;
width = cVPixelBuffer.Width;
height = cVPixelBuffer.Height;
IntPtr baseAddress = cVPixelBuffer.BaseAddress;
bpr = cVPixelBuffer.BytesPerRow;
cVPixelBuffer.Unlock(CVPixelBufferLock.ReadOnly);
buffer = NSData.FromBytes(baseAddress, (nuint)dataSize);
cVPixelBuffer.Dispose();
queue.DispatchAsync(ReadTask);
}
sampleBuffer.Dispose();
}
...
}

void Initialize()
{
CaptureSession = new AVCaptureSession();
previewLayer = new AVCaptureVideoPreviewLayer(CaptureSession)
{
Frame = Bounds,
VideoGravity = AVLayerVideoGravity.ResizeAspectFill
};

var videoDevices = AVCaptureDevice.DevicesWithMediaType(AVMediaType.Video);
var cameraPosition = (cameraOptions == CameraOptions.Front) ? AVCaptureDevicePosition.Front : AVCaptureDevicePosition.Back;
var device = videoDevices.FirstOrDefault(d => d.Position == cameraPosition);

if (device == null)
{
return;
}

NSError error;

iPublicRuntimeSettings settings = reader.GetRuntimeSettings(out error);
settings.ExpectedBarcodesCount = (cameraPreview.ScanMode == ScanOptions.Single) ? 1 : 0;
reader.UpdateRuntimeSettings(settings, out error);

var input = new AVCaptureDeviceInput(device, out error);
CaptureSession.AddInput(input);
var videoDataOutput = new AVCaptureVideoDataOutput()
{
AlwaysDiscardsLateVideoFrames = true
};
if (CaptureSession.CanAddOutput(videoDataOutput))
{
CaptureSession.AddOutput(videoDataOutput);
captureOutput.reader = reader;
captureOutput.update = UpdateResults;

DispatchQueue queue = new DispatchQueue("camera");
videoDataOutput.SetSampleBufferDelegateQueue(captureOutput, queue);
videoDataOutput.WeakVideoSettings = new NSDictionary<NSString, NSObject>(CVPixelBuffer.PixelFormatTypeKey, NSNumber.FromInt32((int)CVPixelFormatType.CV32BGRA));
}
CaptureSession.CommitConfiguration();

Layer.AddSublayer(previewLayer);
CaptureSession.StartRunning();
IsPreviewing = true;
}
BarcodeQrData[] output = null;
try
{
YuvImage image = (YuvImage)msg.Obj;
if (image != null)
{
int[] stridelist = image.GetStrides();
TextResult[] results = barcodeReader.DecodeBuffer(image.GetYuvData(), previewWidth, previewHeight, stridelist[0], EnumImagePixelFormat.IpfNv21);
if (results != null && results.Length > 0)
{
output = new BarcodeQrData[results.Length];
int index = 0;
foreach (TextResult result in results)
{
BarcodeQrData data = new BarcodeQrData();
data.text = result.BarcodeText;
data.format = result.BarcodeFormatString;
LocalizationResult localizationResult = result.LocalizationResult;
data.points = new SKPoint[localizationResult.ResultPoints.Count];
int pointsIndex = 0;
foreach (Com.Dynamsoft.Dbr.Point point in localizationResult.ResultPoints)
{
SKPoint p = new SKPoint();
p.X = point.X;
p.Y = point.Y;
data.points[pointsIndex++] = p;
}
output[index++] = data;
}
}
}
}
catch (BarcodeReaderException e)
{
e.PrintStackTrace();
}
output = null;
if (reader != null)
{
results = reader.DecodeBuffer(buffer,
width,
height,
bpr,
EnumImagePixelFormat.Argb8888,
"", out errorr);

if (results != null && results.Length > 0)
{
output = new BarcodeQrData[results.Length];
int index = 0;
foreach (iTextResult result in results)
{
BarcodeQrData data = new BarcodeQrData();
data.text = result.BarcodeText;
data.format = result.BarcodeFormatString;
iLocalizationResult localizationResult = result.LocalizationResult;
data.points = new SKPoint[localizationResult.ResultPoints.Length];
int pointsIndex = 0;
foreach (NSObject point in localizationResult.ResultPoints)
{
SKPoint p = new SKPoint();
p.X = (float)((NSValue)point).CGPointValue.X;
p.Y = (float)((NSValue)point).CGPointValue.Y;
data.points[pointsIndex++] = p;
}
output[index++] = data;
}
}
else
{
result = "";
}
}
Element.NotifyResultReady(output, previewWidth, previewHeight);
cameraPreview.NotifyResultReady(captureOutput.output, (int)captureOutput.width, (int)captureOutput.height);
private void CameraPreview_ResultReady(object sender, ResultReadyEventArgs e)
{
if (e.Result != null)
{
data = (BarcodeQrData[])e.Result;
}
else
{
data = null;
}

imageWidth = e.PreviewWidth;
imageHeight = e.PreviewHeight;

canvasView.InvalidateSurface();
}

public static SKPoint rotateCW90(SKPoint point, int width)
{
SKPoint rotatedPoint = new SKPoint();
rotatedPoint.X = width - point.Y;
rotatedPoint.Y = point.X;
return rotatedPoint;
}

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
double width = canvasView.Width;
double height = canvasView.Height;

var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
var orientation = mainDisplayInfo.Orientation;
var rotation = mainDisplayInfo.Rotation;
var density = mainDisplayInfo.Density;

width *= density;
height *= density;

double scale, widthScale, heightScale, scaledWidth, scaledHeight;

if (orientation == DisplayOrientation.Portrait)
{
widthScale = imageHeight / width;
heightScale = imageWidth / height;
scale = widthScale < heightScale ? widthScale : heightScale;
scaledWidth = imageHeight / scale;
scaledHeight = imageWidth / scale;
}
else
{
widthScale = imageWidth / width;
heightScale = imageHeight / height;
scale = widthScale < heightScale ? widthScale : heightScale;
scaledWidth = imageWidth / scale;
scaledHeight = imageHeight / scale;
}

SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;

canvas.Clear();

SKPaint skPaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Blue,
StrokeWidth = 10,
};

SKPaint textPaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Red,
TextSize = (float)(18 * density),
StrokeWidth = 4,
};

ResultLabel.Text = "";
if (data != null)
{
foreach (BarcodeQrData barcodeQrData in data)
{
for (int i = 0; i < 4; i++)
{
if (orientation == DisplayOrientation.Portrait)
{
barcodeQrData.points[i] = rotateCW90(barcodeQrData.points[i], imageHeight);
}

if (widthScale < heightScale)
{
barcodeQrData.points[i].X = (float)(barcodeQrData.points[i].X / scale);
barcodeQrData.points[i].Y = (float)(barcodeQrData.points[i].Y / scale - (scaledHeight - height) / 2);
}
else
{
barcodeQrData.points[i].X = (float)(barcodeQrData.points[i].X / scale - (scaledWidth - width) / 2);
barcodeQrData.points[i].Y = (float)(barcodeQrData.points[i].Y / scale);
}
}

canvas.DrawText(barcodeQrData.text, barcodeQrData.points[0], textPaint);
canvas.DrawLine(barcodeQrData.points[0], barcodeQrData.points[1], skPaint);
canvas.DrawLine(barcodeQrData.points[1], barcodeQrData.points[2], skPaint);
canvas.DrawLine(barcodeQrData.points[2], barcodeQrData.points[3], skPaint);
canvas.DrawLine(barcodeQrData.points[3], barcodeQrData.points[0], skPaint);
}
}
else
{
ResultLabel.Text = "No barcode QR code found";
}
}

Source Code

https://github.com/yushulx/xamarin-forms-barcode-qrcode-scanner

--

--

Manager of Dynamsoft Open Source Projects | Tech Lover

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Xiao Ling

Xiao Ling

Manager of Dynamsoft Open Source Projects | Tech Lover