A Step-by-Step Guide on View Pages as Thumbnails Using Xamarin Forms pdf Viewer

The PdfRenderer class in Android and the CGPDFDocument class in iOS can be used to display PDF documents by converting each PDF page to an image, then displaying the images in an image viewer. You can also display PDF documents using a Web View control, although this approach doesn’t work out of the box for Android and Windows platforms. Both approaches provide only a basic PDF viewing experience. They don’t offer the best PDF viewing experience with features like document navigation, zooming, text search, text selection, and copying and annotation.

Thumbnails using Xamarin forms pdf viewer

Previously, we have seen how to generate thumbnails using ASP.NET MVC where we have learned about what exactly Page thumbnails are? Basically, these are miniature previews of the pages in a very document. You’ll be able to use page thumbnails to navigate to a required page quickly. We can achieve the thumbnail view at the applying level by exporting PDF pages as images.

In this blog, we’ll see a way to do that using our Syncfusion Xamarin PDF Viewer component.

Create a Xamarin app and add dependencies

First, Create the New Xamarin app and install Syncfusion Xamarin. Forms PDF Viewer and ListView NuGet packages in it.

Syncfusion Xamarin. Forms PDF Viewer

The Syncfusion Xamarin. Forms PDF Viewer addresses these shortcomings and provides this optimal PDF viewing experience with your applications. Easily integrate the PDF viewing functionality within your Xamarin applications employee few lines of code. View PDF files within Xamarin. Forms, Xamarin. Android, and Xamarin. iOS applications using the Syncfusion PDF the Viewer control. The subsequent features are included out of the box:

  • Annotate PDF documents using common annotation types like highlight, underline, strikethrough, freehand drawing or inking, line, rectangles, and ellipses.
  • Easily navigate using the bookmarks, links, and a table of contents to the Syncfusion Xamarin. Forms.
  • Search for text.
  • Select text and replica it to the clipboard.
  • Fill and sign form fields.
  • Utilize RTL language support.
  • Load quickly: PDF pages are loaded on demand to assist reduce the initial load time and memory consumption.

  Integrating the Control in Xamarin. Forms Applications

  1. Open Visual Studio and build a cross-platform project with the name “HelloWorld” and choose .NET Standard because of the code-to-sharing strategy.
  • Open the Manage NuGet Packages with the Solution.

Browse for Syncfusion. Xamarin. SfPdfViewer NuGet Packages and install it to all or any of the projects within the solution.

  • Open Main Page. XAML and include the XML namespace to sit down with the PDF Viewer assembly. Then add to a SfPdfViewer because of the content to the ContentPage.
  • To use SfPdfViewer in an iOS application, the application must initialize SfPdfDocumentViewRenderer and SfRangeSliderRenderer. do that within the FinishedLaunching overriding method of the AppDelegate class as shown within the following:

Create a Xamarin app and add to dependencies

Create for Xamarin app and install Syncfusion Xamarin. Forms PDF Viewer and ListView NuGet packages in it.

Create a thumbnail view

Create a content view in the thumbnail view. XAML file by adding Xamarin.Forms.

<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:syncfusion="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"
             xmlns:local = "clr-namespace:PdfViewerThumbnail"
             x:Class = "PdfViewerThumbnail.Views.thumbnail view">
    <ContentView.Resources>
        <ResourceDictionary>
            <local:ImageSourceConverter x:Key = "ImageSourceConverter"/>
            <DataTemplate x:Key = "itemTemplate">
                <ViewCell >
                    <ViewCell.View>
                        <Grid x:Name = "grid" RowSpacing = "15"                ColumnSpacing = "15" Margin = "10,10,10,10">
                           <Image Source = "{Binding ImageSource, Converter={StaticResource ImageSourceConverter}}" Aspect="Fill"/>
                        </Grid>
                    </ViewCell.View> 
                </ViewCell>
            </DataTemplate>
      </ResourceDictionary>
    </ContentView.Resources>
    <syncfusion:SfListView x:Name="listView"
                           x:FieldModifier = "public"
                           Margin = "15"
                           VerticalOptions = "CenterAndExpand"
                           HorizontalOptions = "CenterAndExpand"
                           RowSpacing="15"
                           ColumnSpacing = "15"
                           ItemTapped = "listView_ItemTapped"                                        
                           ItemSize = "160"
                           LoadMoreOption = "Auto" 
                           LoadMoreCommand = "{Binding LoadMoreItemsCommand}"
                           LoadMoreCommandParameter = "{Binding Source={x:Reference Name=ListView}}"
                           LoadMorePosition = "Bottom"
                           ItemTemplate = "{StaticResource itemTemplate}"                   
                           Orientation = "Horizontal"                  
                           ItemsSource = "{Binding ImageCollection}" >
        <syncfusion:SfListView.LoadMoreTemplate>
            <DataTemplate>
                <Grid IsVisible = "{Binding IsBusy, Source ={x:Reference Name =listView}}" >
                  <syncfusion:LoadMoreIndicator WidthRequest = "60" HeightRequest ="60" Color="Pink " IsRunning = "True" VerticalOptions ="CenterAndExpand"/>
                </Grid>
            </DataTemplate>
        </syncfusion:SfListView.LoadMoreTemplate>
    </syncfusion:SfListView>
</ContentView>

Create a content view in the thumbnail view. Cs file by adding Xamarin.Forms

/// <summary>
/// Represents the image conversion methods for the thumbnail view.
/// </summary>
    
public class ImageSourceConverter: IValueConverter
{
   public object Convert(object value, Type targetType,
     object parameter, CultureInfo culture)
   {
     var image = value as byte[];
     if (image == null)
        return null;
     return ImageSource.FromStream(() => new MemoryStream(image));
   }
 
   public object ConvertBack(object value, Type targetType,
      object parameter, CultureInfo culture)
   {
      throw new NotImplementedException();
   }
 }

Create content page, add PDF Viewer and thumbnail view

Create the main content page. Add the Syncfusion Xamarin. Forms PDF Viewer component to display the PDF document and the created thumbnail view as the child elements to the main content page.

<ContentPage xmlns = "http://xamarin.com/schemas/2014/forms"
             xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class = "PdfViewerThumbnail.PdfViewerView"
             xmlns:Syncfusion = "clr-namespace:Syncfusion.SfPdfViewer.XForms;assembly=Syncfusion.SfPdfViewer.XForms"
             xmlns:local = "clr-namespace:PdfViewerThumbnail"          
             xmlns:views = "clr-namespace:PdfViewerThumbnail.Views">
 
    <ContentPage.BindingContext>
        <local:PdfViewerThumbnailViewModel></local:PdfViewerThumbnailViewModel>
    </ContentPage.BindingContext>
    <Grid x:Name = "MainGrid">
       <Grid.RowDefinitions>
          <RowDefinition Height = "{Static GridLength.Star}" />
       </Grid.RowDefinitions>       
       <Grid Grid.Row = "0" x:Name = "MainContent" VerticalOptions = "FillAndExpand" HorizontalOptions = "FillAndExpand">
            <Grid.RowDefinitions>
                <RowDefinition Height = "60"/>
                <RowDefinition Height = "*" />
                <RowDefinition Height  ="60" />
            </Grid.RowDefinitions>
            <Grid Grid.Row = "0" x:Name = "AppBar" BackgroundColor = "#1777D6" HorizontalOptions ="FillAndExpand">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width ="*"></ColumnDefinition>
                    <ColumnDefinition Width ="60"></ColumnDefinition>
                    <ColumnDefinition Width ="60"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Label Grid.Column = "0" Grid.Row = "0" x:Name = "thumbnail" Text = "Thumbnail View" Margin = "5,0,0,0" TextColor = "White" FontSize = "Medium" VerticalOptions ="Center"></Label>
            </Grid>
            <Grid Grid.Row = "1" x:Name = "PdfViewerGrid">
                <syncfusion:SfPdfViewer x:Name = "pdfViewerControl" PageNumber ="{Binding PageNumber}" InputFileStream="{Binding PdfDocumentStream}" />
            </Grid>
            <Grid Grid.Row ="2"  x:Name ="PageThumbnailsGrid" HorizontalOptions ="FillAndExpand" BackgroundColor="#1777D6">
                <views:ThumbnailView x:Name ="pageThumbnails"></views:ThumbnailView>
            </Grid>
        </Grid>
    </Grid>
</ContentPage>

Export images for thumbnails and load them on demand

private void pdfViewerControl_DocumentLoaded(object sender, EventArgs args)
{
    int initialThumbnailsCount = 8;           
 
    // PdfViewerControl object that helps to navigate to the selected page index.
    pageThumbnails.PdfViewerControl = this.pdfViewerControl;
 
    // Export PDF pages as images and add them to the thumbnail view.
    var pageCount = pdfViewerControl.PageCount > initialThumbnailsCount ? initialThumbnailsCount :
    pdfViewerControl.PageCount;
 
    (BindingContext as PdfViewerThumbnailViewModel).AddThumbnailImages(pageThumbnails.listView, 0, pageCount - 1);
}

Create PdfViewerThumbnailViewModel.cs

/// <summary>
/// Constructor of the view model class.
/// </summary>
public PdfViewerThumbnailViewModel()
{
    LoadMoreItemsCommand = new Command<object>(LoadMoreItems);
    //Accessing the PDF document added as embedded resource as stream.
typeof(App).GetTypeInfo().Assembly.GetManifestResourceStream("PdfViewerThumbnail.Assets.GIS Succinctly.pdf");
}
 
/// <summary>
/// Load more items to the thumbnail view on demand.
/// </summary>
/// <param name="obj">List view</param>
internal void LoadMoreItems(object obj)
{
   var startPageIndex = this.ThumbnailImages.Count;
   if (startPageIndex == this.PdfViewer.PageCount)
   {
      return;
   }
   int endPageIndex = startPageIndex + loadMoreItemsCount;
   endPageIndex = endPageIndex > this.PdfViewer.PageCount - 1 ? this.PdfViewer.PageCount - 1 : endPageIndex - 1;
 
   AddThumbnailImages(obj as SfListView, startPageIndex, endPageIndex);
}
 
/// <summary>
/// Export PDF pages as images and add them to the thumbnail view.
/// </summary>
/// <param name="listView">list view object</param>
/// <param name="startPageIndex">start page index of the document</param>
/// <param name="endPageIndex">end page index of the document</param>
internal async void AddThumbnailImages(SfListView listView, int startPageIndex, int endPageIndex)
{
   if (!listView.IsBusy)
   {
      listView.IsBusy = true;
      Stream[] imageStreamList = null;
      imageStreamList = await PdfViewer?.ExportAsImageAsync(startPageIndex, endPageIndex, 0.3f);
      foreach (Stream imageStream in imageStreamList)
      {
          imageStream.Position = 0;
          byte[] bytes = ReadBytes(imageStream);
          this.ThumbnailImages.Add(new ThumbnailModel(bytes));
      }
      listView.IsBusy = false;
   }
}
 
/// <summary>
/// Convert image stream to byte array.
/// </summary>
/// <param name="imageStream">image stream</param>
/// <returns>image byte array</returns>
internal byte[] ReadBytes(Stream imageStream)
{
    byte[] buffer = new byte[16 * 1024];
    using (MemoryStream ms = new MemoryStream())
    {
       int read;
       while ((read = imageStream.Read(buffer, 0, buffer.Length)) > 0)
       {
          ms.Write(buffer, 0, read);
       }
       return ms.ToArray();
    }
}

Create the model class ThumbnailModel to the ThumbnailModel.cs

public class ThumbnailModel: INotifyPropertyChanged
{
    private byte[] _imageSource;
 
    public byte[] ImageSource
    {
      get
      {
         return _imageSource;
      }
      set
      {
          _imageSource = value;
          this.RaisedOnPropertyChanged("ImageSource");
      }
    }
 
   public event PropertyChangedEventHandler PropertyChanged;
 
   public ThumbnailModel(byte[] imageSource)
   {
      ImageSource = imageSource;
   }
 
   public void RaisedOnPropertyChanged(string _PropertyName)
   {
      if (PropertyChanged != null)
      {
         PropertyChanged(this, new PropertyChangedEventArgs(_PropertyName));
      }
   }
}

Conclusion

View PDF pages as thumbnails using our Syncfusion Xamarin. Forms PDF Viewer component. this might facilitate your easily navigating PDF pages. This will help you easily navigate PDF pages. attempt the steps given during this blog post and share your feedback within the comment section below.

Technical Director, iFour Technolab Pvt. Ltd.

A Seasoned technocrat with years of experience building technical solutions for various industries using Microsoft technologies. With a sharp understanding and technical acumen, he has delivered hundreds of Web, Cloud, Desktop, and Mobile solutions and is heading the technical department at an esteemed Microsoft 365 development company – iFour Technolab Pvt. Ltd.

mm
Author
Ajay Patel – Technical Director, iFour Technolab Pvt. Ltd. A Seasoned technocrat with years of experience building technical solutions for various industries using Microsoft technologies. With a sharp understanding and technical acumen, he has delivered hundreds of Web, Cloud, Desktop, and Mobile solutions and is heading the technical department at an esteemed Microsoft 365 development company – iFour Technolab Pvt. Ltd. https://www.ifourtechnolab.com

Leave a Reply

Your email address will not be published. Required fields are marked *