This tutorial shows how to use the LEADTOOLS SDK in a C# Xamarin application and display images in an Image Viewer.
Overview | |
---|---|
Summary | This tutorial covers how to display images in a LEADTOOLS Image Viewer a C# Xamarin application |
Completion Time | 30 minutes |
Visual Studio Project | Download tutorial project (49 MB) |
Platform | C# Xamarin Cross-Platform Application |
IDE | Visual Studio 2017, 2019 |
Development License | Download LEADTOOLS |
Get familiar with the basic steps of creating a project by reviewing the Add References and Set a License tutorial, before working on the Display Image in an Image Viewer - Xamarin C# tutorial.
In Visual Studio, create a new C# Xamarin project, and add the following necessary LEADTOOLS references.
The references needed depend upon the purpose of the project. For this project, the following NuGet package are needed:
Leadtools.Viewer.Controls.Xamarin
Leadtools.Formats.Raster.Common
The License unlocks the features needed for the project. It must be set before any toolkit function is called. For details, including tutorials for different platforms, refer to Setting a Runtime License.
There are two types of runtime licenses:
Note
Adding LEADTOOLS NuGet references and setting a license are covered in more detail in the Add References and Set a License tutorial.
With the project created, the references added, and the license set, coding can begin.
In Solution Explorer, open MainPage.xaml
. Add the following code inside the ContentPage
to add a load image button and Image Viewer container.
<ContentPage.Content>
<Grid x:Name="imageViewerContainer" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="Black">
<Grid.RowDefinitions>
<RowDefinition x:Name="row0" Height="*"/>
<RowDefinition x:Name="loadButtonRow" Height="50"/>
</Grid.RowDefinitions>
<Grid Margin="10,5" Grid.Row="1" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="_loadFromGallery" Text="Load" BorderColor="LightCoral" Clicked="_loadFromGallery_Clicked" HorizontalOptions="FillAndExpand"/>
</Grid>
</Grid>
</ContentPage.Content>
Right click on the page and select View Code or press F7, to bring up the code behind MainPage.xaml
. Add the following statements to the using
block at the top of MainPage.xaml.cs
.
// Using block at the top
using System;
using System.Text;
using System.ComponentModel;
using Xamarin.Forms;
using Leadtools;
using Leadtools.Codecs;
using Leadtools.Controls;
using System.IO;
using System.Threading.Tasks;
using DataService;
Add the below code to initialize the Image Viewer.
// Add this global variable
private ImageViewer _imageViewer;
private RasterImage _image;
Add a new method called InitImageViewer()
and call it inside the MainPage()
method after InitializeComponent();
call.
private void InitImageViewer()
{
_imageViewer = new ImageViewer
{
ViewHorizontalAlignment = ControlAlignment.Center,
ViewVerticalAlignment = ControlAlignment.Center,
BackgroundColor = Color.FromHex("#1E1E1E"),
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Margin = new Thickness(0, 0),
AutoDisposeImages = true,
};
Grid.SetRow(_imageViewer, 0);
Grid.SetRowSpan(_imageViewer, 1);
ImageViewerPanZoomInteractiveMode panZoom = new ImageViewerPanZoomInteractiveMode();
_imageViewer.InteractiveModes.Add(panZoom);
imageViewerContainer.Children.Add(_imageViewer);
}
Add a new namespace to the bottom of MainPage.xaml.cs
called DataService
. This namespace will be the dependency service for the picture picker.
// Dependency service
namespace DataService
{
public interface IPicturePicker
{
Task<Stream> GetImageStreamAsync();
}
}
in the Solution Explorer, open MainActivity.cs
. Add the below statements to the using
block at the top:
using Android.Support.V4.App;
using Android;
Add a new method called RequestPermission()
and call it at the bottom of the OnCreate(Bundle savedInstanceState)
method. Add the below code to ensure the necessary permissions are allowed.
private static readonly int REQUEST_PERMISSION_CODE = 0;
public static MainActivity Instance { get; private set; }
void RequestPermissions()
{
//if any of the permissions that we need are denied then request them
if (ActivityCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) == Permission.Denied
|| ActivityCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) == Permission.Denied
)
{
// Camera permission has not been granted yet. Request it directly.
ActivityCompat.RequestPermissions(this, new string[] { Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage }, REQUEST_PERMISSION_CODE);
}
}
In the Solution Explorer, right-click on Info.plist
. Click Open With.... Select Generic PList Editor, then click OK.
Click the +
button on the last row in the editor. This will be called Custom Property
, with the Type set to String and an empty value. Click on the Property
name and the dropdown will appear. From that dropdown select the Privacy - Photo Library Usage Description
. Then enter a description into the Value
column for why the application wants to access that given feature.
Right-click on <Project>.Android
and select Add -> New Item. Select the Class
option and name the class PicturePickerImplementation.cs
, then click Add.
Add the below using
statements to the new class:
using Android.Content;
using System.IO;
using System.Threading.Tasks;
using Xamarin.Forms;
using DataService;
using Display_Images_in_an_Image_Viewer.Droid;
Add a new method to the PicturePickerImplementation
class called GetImageStreamAsync()
that returns a Task<Stream>
. Add the below code to implement the PicturePicker
on an Android device.
[assembly: Dependency(typeof(PicturePickerImplementation))]
namespace Display_Images_in_an_Image_Viewer.Droid
{
class PicturePickerImplementation : IPicturePicker
{
public Task<Stream> GetImageStreamAsync()
{
Intent intent = new Intent();
intent.SetType("image/*");
intent.SetAction(Intent.ActionGetContent);
MainActivity activity = MainActivity.Instance;
if (activity.PickImageTaskCompletionSource == null || activity.PickImageTaskCompletionSource.Task.IsCompleted || activity.PickImageTaskCompletionSource.Task.IsCanceled)
{
activity.StartActivityForResult(Intent.CreateChooser(intent, "Select Picture"), MainActivity.PickImageId);
activity.PickImageTaskCompletionSource = new TaskCompletionSource<Stream>();
return activity.PickImageTaskCompletionSource.Task;
}
else
{
return activity.PickImageTaskCompletionSource.Task;
}
}
}
}
Make sure to add the [assembly: Dependency(typeof(PicturePickerImplementation))]
line of code so that it can find the implementation of the DependencyService
.
In the Solution Explorer, open MainActivity.cs
. Add the below code to the OnActivityResult
method to handle the image selected with the picture picker, gather the stream, and hand the stream to the task completion source.
// Add these variables used in `OnActivityResult()`
public TaskCompletionSource<Stream> PickImageTaskCompletionSource { set; get; }
public static readonly int PickImageId = 1000;
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == PickImageId)
{
if (resultCode == Result.Ok && data != null)
{
Android.Net.Uri uri = data.Data;
Stream stream = ContentResolver.OpenInputStream(uri);
PickImageTaskCompletionSource.SetResult(stream);
}
else
{
PickImageTaskCompletionSource.SetResult(null);
}
}
}
Right-click on <Project>.iOS
and select Add -> New Item. Select the Class
option and name the class PicturePickerImplementation.cs
, then click Add.
Add the below using
statements to the new class:
using System;
using System.IO;
using System.Threading.Tasks;
using Xamarin.Forms;
using UIKit;
using Display_Images_in_an_Image_Viewer.iOS;
using Foundation;
using DataService;
Add a new method to the PicturePickerImplementation
class called GetImageStreamAsync()
that returns a Task<Stream>
. Add the below code to implement the PicturePicker
on an iOS device.
[assembly: Dependency(typeof(PicturePickerImplementation))]
namespace Display_Images_in_an_Image_Viewer.iOS
{
[Xamarin.Forms.Internals.Preserve(AllMembers = true)]
class PicturePickerImplementation : IPicturePicker
{
TaskCompletionSource<Stream> taskCompletionSource;
UIImagePickerController imagePicker;
public Task<Stream> GetImageStreamAsync()
{
try
{
// Create and define UIImagePickerController
imagePicker = new UIImagePickerController
{
SourceType = UIImagePickerControllerSourceType.PhotoLibrary,
MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.PhotoLibrary)
};
// Set event handlers
imagePicker.FinishedPickingMedia += OnImagePickerFinishedPickingMedia;
// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);
// Return Task object
taskCompletionSource = new TaskCompletionSource<Stream>();
return taskCompletionSource.Task;
}
catch (Exception ex) { Console.WriteLine(ex.Message); return null; }
}
void OnImagePickerFinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs args)
{
UIImage image = args.EditedImage ?? args.OriginalImage;
if (image != null)
{
// Convert UIImage to .NET Stream object
NSData data = image.AsJPEG(1);
Stream stream = data.AsStream();
// Set the Stream as the completion of the Task
taskCompletionSource.SetResult(stream);
}
else
{
taskCompletionSource.SetResult(null);
}
imagePicker.DismissModalViewController(true);
}
}
}
Make sure to add the [assembly: Dependency(typeof(PicturePickerImplementation))]
line of code so that it can find the implementation of the DependencyService
.
In the Solution Explorer, open AppDelegate.cs
. Add the below line to the FinishedLaunching()
method:
Leadtools.Controls.iOS.Assembly.Use();
In the Solution Explorer, open MainPage.xaml.cs
. Add a new Clicked
event handler for loadFromGallery
, if it does not already exist. Add the below code inside the handler to load the image from the device's gallery.
private async void _loadFromGallery_Clicked(object sender, EventArgs e)
{
try
{
Stream imageStream = await DependencyService.Get<IPicturePicker>().GetImageStreamAsync();
if (imageStream != null)
{
using (RasterCodecs codecs = new RasterCodecs())
{
codecs.Options.Load.XResolution = 200;
codecs.Options.Load.YResolution = 200;
_image = codecs.Load(imageStream);
_imageViewer.Image = _image;
}
}
}
catch (Exception ex)
{
await DisplayAlert("Error", ex.ToString(), "OK");
}
}
Select the desired project (iOS or Android) and run the project by pressing F5, or by selecting Debug -> Start Debugging.
If the steps were followed correctly, the application runs and it will ask to allow Storage
permissions which is required. For testing, click the Load button at the bottom of the device's screen and select any of the images in the device's gallery. The image will then be loaded as a RasterImage and will be displayed in the ImageViewer.
Android:
iOS:
This tutorial showed how to load and display images. In addition, it showed how to use the ImageViewer
and RasterCodecs
classes.