Introduction
Our previous product showcase focused on how to use LEAD’s new Xamarin Camera Control to easily leverage a mobile device camera. We also incorporated the Barcode SDK into the application to read barcodes and display the data found to the device’s screen.
Staying on the Xamarin Camera Control train, we are now going to incorporate one of the new LEADTOOLS Cloud Services methods to our application, the Merge method. This method merges specific pages into another file and can be called with a POST Request to the following URL:
[POST] https://azure.leadtools.com/api/Conversion/Merge
The LEADTOOLS Cloud Services are Web API endpoints for customers to access the high-powered functionality provided by LEADTOOLS SDK without the hassle of setting up their own servers. We currently offer Document Conversion, Document Merging, Redaction, Barcode, OCR, MICR, AAMVAID, and Business Card Extraction services.
The Merge method we are using for this application gives users the ability to choose which pages from the input documents to be merged. Specify a range of pages, an array of pages, or the entire document to be merged. If the target format is a document type, merge retains the text and only uses OCR when needed.
Applying both the Xamarin Camera Control and LEADTOOLS Cloud Services has limitless potential for applications across various industries. For instance, say an insurance company requires pictures of damaged property for proof of damages. Instead of sending 20 individual images, you can create one file that includes those 20 images.
Setting up Your App
The first step is to retrieve your free 30-day evaluation license by registering at https://www.leadtools.com/downloads/nuget and create an account for your free trial of LEADTOOLS Cloud Services at https://services.leadtools.com/account/register.
Once you have a LEADTOOLS license, open Visual Studio 2017 and create a new project. First, add the Leadtools.Camera.Xamarin assembly in the MainPage.xaml.
xmlns:leadtools="clr-namespace:Leadtools.Camera.Xamarin;assembly=Leadtools.Camera.Xamarin"
Now replace the default auto-generated label within the StackLayout
with the Xamarin CameraView
, as well as a button that will be used to take the picture and one that will merge all the images that have been taken.
<StackLayout>
<leadtools:CameraView x:Name="leadCamera" CameraOptions="Rear" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"/>
<Button x:Name="snapBtn" HorizontalOptions="FillAndExpand" Text="Snap Picture" Clicked="SnapClicked" />
<Button x:Name="mergeBtn" HorizontalOptions="FillAndExpand" Text="Merge" Clicked="performMerge" />
<Button x:Name="downloadFileBtn" HorizontalOptions="FillAndExpand" Text="Go to file!" Clicked="downloadFile"/>
</StackLayout>
For more of an introduction to using the LEADTOOLS Camera Control for Xamarin as well as setting the LEADTOOLS license, check out the previous article, https://www.codeproject.com/Articles/1349139/Finally-a-Camera-Control-for-Xamarin. Please note that the previous article is necessary to complete before continuing.
Now that the Xamarin Camera Control has been added and the license has been set, add the code to take the picture. The CameraView
Class has an event called PictureReceived
which will be fired when an image is captured after calling ICamera.TakePicture()
.
The call to the TakePicture
method will go in the button click event.
void SnapClicked(object sender, EventArgs args)
{
snapBtn.IsEnabled = false;
leadCamera.Camera.TakePicture();
}
To create the event handler for PictureReceived
, add the following line of code after InitializeComponent()
:
leadCamera.PictureReceived += LeadCamera_PictureReceived;
The Code
First, create some global variables and create a new class.
private static HttpClient client;
private List<MergeRequestObject> MergeImages = new List<MergeRequestObject>();
private string hostedServicesUrl = "https://azure.leadtools.com/api/";
private static string fileUrl;
public class MergeRequestObject
{
public string FileId { get; set; }
}
As mentioned above, and from our previous article, MainPage.xaml.cs has everything needed to start the Xamarin Camera Control. On top of that, add code to auto-rotate the image, enable the merge button, disable the download button, and an InitClient
method. You should have the following below InitializeComponent()
.
leadCamera.CameraOptions.AutoRotateImage = true;
leadCamera.PictureReceived += LeadCamera_PictureReceived;
mergeBtn.IsEnabled = false;
downloadFileBtn.IsEnabled = false;
InitClient();
InitClient
is needed for authenticating your application with the LEADTOOLS Cloud Services.
private void InitClient()
{
string AppId = "Enter AppID Here";
string Password = "Enter SecretKey Here";
client = new HttpClient
{
BaseAddress = new Uri(hostedServicesUrl)
};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string authData = string.Format("{0}:{1}", AppId, Password);
string authHeaderValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(authData));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authHeaderValue);
}
The code inside PictureReceived
will be for saving each image that has been taken and then uploading them to the LEADTOOLS Cloud Services. In this example, the images will be stored in a MemoryStream
as a PNG. After the image is saved, it will need to be uploaded to the LEADTOOLS Cloud Services. To do that, a method called UploadForMerge
will be used. This method will need the memory stream and will return a GUID. Once you have the GUID, it will be stored in a list, List<MergeRequestObject>
mergeImages. The MergeRequestObject
is a class that we created that contains a string called FileID
. FileID
will now be the GUID that was returned from UploadForMerge
. Each image that is taken will go through this process and will have its own GUID that will be added to the list.
private void LeadCamera_PictureReceived(FrameHandlerEventArgs e)
{
Device.BeginInvokeOnMainThread(() =>
{
snapBtn.Text = "Image is uploading to LEADTOOLS Cloud Services, please wait";
mergeBtn.IsEnabled = false;
});
using (MemoryStream ms = new MemoryStream())
{
using (RasterCodecs codecs = new RasterCodecs())
{
codecs.Save(e.Image, ms, RasterImageFormat.Png, 0);
var id = UploadForMerge(ms);
MergeImages.Add(new MergeRequestObject { FileId = id.ToString() });
Device.BeginInvokeOnMainThread(() =>
{
snapBtn.IsEnabled = true;
snapBtn.Text = "Snap Picture";
mergeBtn.Text = $"Merge {MergeImages.Count} file(s)";
DisplayAlert("Image saved!", "Image has been uploaded", "OK");
mergeBtn.IsEnabled = true;
});
}
}
}
The UploadForMerge
method is where the image is getting sent to the LEADTOOLS Cloud Services and then returning a GUID.
public Guid UploadForMerge(MemoryStream uploadForMergeStream)
{
HttpContent byteContent = new ByteArrayContent(uploadForMergeStream.ToArray());
using (var formData = new MultipartFormDataContent())
{
formData.Add(byteContent, "imageStream");
var url = "UploadFile?forMerge=true";
var res = client.PostAsync(url, formData).Result;
var guid = Guid.Empty;
if (res.IsSuccessStatusCode)
{
var id = res.Content.ReadAsStringAsync().Result;
return Guid.Parse(id);
}
else
return Guid.Empty;
}
}
Once all the pictures have been taken and are uploaded to the LEADTOOLS Cloud Services, it’s time to merge them to a single file. For this, create a new method called PerformMerge
.
void performMerge(object sender, EventArgs args)
{
Device.BeginInvokeOnMainThread(() =>
{
mergeBtn.Text = "Merging files, please wait";
snapBtn.IsEnabled = false;
mergeBtn.IsEnabled = false;
});
var id = PostMerge();
if (id == Guid.Empty)
Device.BeginInvokeOnMainThread(() =>
{
DisplayAlert("Error", "GUID is empty", "OK");
});
var results = Query(id.ToString());
JArray array = JArray.Parse(results);
foreach (var requestReturn in array)
{
var UrlArray = JArray.Parse(requestReturn.SelectToken("urls").ToString());
foreach (var uri in UrlArray)
{
Device.BeginInvokeOnMainThread(() =>
{
fileUrl = uri.ToString();
});
}
}
MergeImages.Clear();
Device.BeginInvokeOnMainThread(() =>
{
downloadFileBtn.IsEnabled = true;
mergeBtn.Text = "File(s) have been merged";
snapBtn.IsEnabled = true;
});
}
Inside PerformMerge
is another method called PostMerge
method which will also return a GUID.
public Guid PostMerge()
{
var stringContent = new StringContent(JsonConvert.SerializeObject(MergeImages), Encoding.UTF8, "application/json");
var url = $"Conversion/Merge?Format=4";
var res = client.PostAsync(url, stringContent).Result;
if (res.IsSuccessStatusCode)
{
var id = res.Content.ReadAsStringAsync().Result;
return Guid.Parse(id);
}
else
return Guid.Empty;
}
Continuing with the PerformMerge
method, this is where the results will be returned from using the ID returned from PostMerge
and then queried using a new method called Query which takes in a string and returns results.
private string Query(string id)
{
string queryUrl = $"Query?id={id.ToString()}";
int status = 100;
string results = "";
JObject returnedData = null;
while (status == 100 || status == 123)
{
Task.Delay(500).Wait();
var result = client.PostAsync(queryUrl, null).Result;
var returnedContent = result.Content.ReadAsStringAsync().Result;
returnedData = JObject.Parse(returnedContent);
status = (int)returnedData.SelectToken("FileStatus");
}
if (status == 200)
results = returnedData.SelectToken("RequestData").ToString();
return results;
}
Add the downloadFile
method for downloading the file.
void downloadFile(object sender, EventArgs args)
{
Device.OpenUri(new Uri(fileUrl));
}
Conclusion
These two technologies provide developers with one, a high-level API to access a mobile devices camera, and two, a programmer-friendly Web API. Combining these gives developers the ability to create on the go mobile service applications.
Create an account and get your first 50 pages for free!
https://services.leadtools.com/account/register
Support
Need help getting this sample up and going? Contact our support team for free technical support! For pricing or licensing questions, you can contact our sales team (sales@leadtools.com) or call us at 704-332-5532.