Display Image in an Image Viewer - Xamarin C#

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 an Image Viewer in 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

Required Knowledge

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.

Create the Project and Add the LEADTOOLS References

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:

Set the License File

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 and references and setting a license are covered in more detail in the Add References and Set a License tutorial.

Initialize the Image Viewer

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.

XML
   <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.

C#
// 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.

C#
// 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.

C#
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.

C#
// Dependency service 
namespace DataService 
{ 
   public interface IPicturePicker 
   { 
      Task<Stream> GetImageStreamAsync(); 
   } 
} 

Add Application Permissions (Android)

in the Solution Explorer, open MainActivity.cs. Add the below statements to the using block at the top:

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.

C#
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); 
    } 
} 

Add Application Permissions (iOS)

In the Solution Explorer, right-click on Info.plist. Click Open With.... Select Generic PList Editor, then click OK.

Select Generic PList Editor

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.

Add Photo Library Access

Add the PicturePicker Implementation Class (Android)

Right-click on <Project>.Android and select Add -> New Item. Select the Class option and name the class PicturePickerImplementation.cs, then click Add.

Add PicturePickerImplementation.cs to Android project

Add the below using statements to the new class:

C#
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.

C#
[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.

C#
// 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); 
        } 
    } 
} 

Add the PicturePicker Implementation Class (iOS)

Right-click on <Project>.iOS and select Add -> New Item. Select the Class option and name the class PicturePickerImplementation.cs, then click Add.

Add PicturePickerImplementation.cs to iOS project

Add the below using statements to the new class:

C#
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.

C#
[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:

C#
Leadtools.Controls.iOS.Assembly.Use(); 

Add the Load Image Code

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.

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

Run the Project

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:

Android Device Screen Capture

iOS:

iOS Device Screen Capture

Wrap-up

This tutorial showed how to load and display images. In addition, it showed how to use the ImageViewer and RasterCodecs classes.

See Also

Help Version 21.0.2020.10.22
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2020 LEAD Technologies, Inc. All Rights Reserved.