Articles in this section
Category / Section

How to print PDF documents in Xamarin.Forms platform?

7 mins read

PDF documents can be printed in Xamarin Forms’ Android, iOS, and UWP platforms by obtaining the currently loaded PDF as stream and printing the stream using native printing functionalities available in the respective platforms using DependencyService of Xamarin Forms. These platform specific printing options can be used by defining an interface in the portable project and implementing the same in the platform projects using the specific code.

The following code snippets illustrate printing PDF documents in Xamarin Forms’ Android, iOS, and UWP platforms.

Portable

Define the following interface.

C#

namespace PDFPrintingSample
{
    public interface IPrintService
    {
        void Print(Stream inputStream, string fileName);
    }
}

 

Load the PDF to PdfViewer. Call the Print method with the stream obtained from PdfViewer and file name using DependencyService when the print button is clicked in the code behind. Give the name of the interface as the type parameter to the method DependencyService.Get<T>().

C#

public MainPage()
{
     InitializeComponent();
     documentStream =    typeof(App).GetTypeInfo().Assembly.GetManifestResourceStream("PDFPrintingSample.Assets.GIS Succinctly.pdf");
     pdfViewerControl.LoadDocument(documentStream);
     printButton.Clicked += PrintButton_Clicked;
}
 
private void PrintButton_Clicked(object sender, EventArgs e)
{
            //Obtain the PDF as a stream
            Stream stream = pdfViewerControl.SaveDocument();
            DependencyService.Get<IPrintService>().Print(stream, "GIS Succinctly.pdf");
}

 

Implement the interface in the platform projects with the available platform specific printing options.

Android

C#

//Register the Android implementation of the interface with DependencyService
[assembly: Dependency(typeof(PrintService))]
 
namespace PDFPrintingSample.Droid
{
    class PrintService : IPrintService
    {
        public void Print(Stream inputStream, string fileName)
        {
            if (inputStream.CanSeek)
                //Reset the position of PDF document stream to be printed
                inputStream.Position = 0;            
            //Create a new file in the Personal folder with the given name
            string createdFilePath = System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), fileName);
            //Save the stream to the created file
            using (var dest = System.IO.File.OpenWrite(createdFilePath))
                inputStream.CopyTo(dest);
            string filePath = createdFilePath;
  var activity = Xamarin.Essentials.Platform.CurrentActivity;
            PrintManager printManager = (PrintManager)activity.GetSystemService(Context.PrintService);       
     PrintDocumentAdapter pda = new CustomPrintDocumentAdapter(filePath);
            //Print with null PrintAttributes
            printManager.Print(fileName, pda, null);
        }
    }
}

 

Define a class derived from the PrintDocumentAdapter and write the contents of the input file to the print destination in the OnWrite method.

C#

namespace PDFPrintingSample.Droid
{
    internal class CustomPrintDocumentAdapter : PrintDocumentAdapter
    {
        internal string FileToPrint { get; set; }
 
        internal CustomPrintDocumentAdapter(string fileDesc)
        {
            FileToPrint = fileDesc;
        }
        public override void OnLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras)
        {
            if (cancellationSignal.IsCanceled)
            {
                callback.OnLayoutCancelled();
                return;
            }
 
 
            PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(FileToPrint).SetContentType(Android.Print.PrintContentType.Document).Build();
 
            callback.OnLayoutFinished(pdi, true);
        }
 
        public override void OnWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback)
        {
            InputStream input = null;
            OutputStream output = null;
 
            try
            {
                //Create FileInputStream object from the given file
                input = new FileInputStream(FileToPrint);
                //Create FileOutputStream object from the destination FileDescriptor instance
                output = new FileOutputStream(destination.FileDescriptor);
 
                byte[] buf = new byte[1024];
                int bytesRead;
 
                while ((bytesRead = input.Read(buf)) > 0)
                {
                    //Write the contents of the given file to the print destination
                    output.Write(buf, 0, bytesRead);
                }
 
                callback.OnWriteFinished(new PageRange[] { PageRange.AllPages });
 
            }
            catch (FileNotFoundException ee)
            {
                //Catch exception
            }
            catch (Exception e)
            {
                //Catch exception
            }
            finally
            {
                try
                {
                    input.Close();
                    output.Close();
                }
                catch (IOException e)
                {
                    e.PrintStackTrace();
                }
            }
        }
    }
}

 

iOS

C#

//Register the iOS implementation of the interface with DependencyService
[assembly: Dependency(typeof(PrintService))]
 
namespace PDFPrintingSample.iOS
{
    class PrintService : IPrintService
    {
        public void Print(Stream inputStream, string fileName)
        {
            var printInfo = UIPrintInfo.PrintInfo;
            printInfo.OutputType = UIPrintInfoOutputType.General;
            printInfo.JobName = "Print PDF Sample";
 
            //Get the path of the MyDocuments folder
            var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            //Get the path of the Library folder within the MyDocuments folder
            var library = Path.Combine(documents, "..", "Library");
            //Create a new file with the input file name in the Library folder
            var filepath = Path.Combine(library, fileName);
 
            //Write the contents of the input file to the newly created file
            using (MemoryStream tempStream = new MemoryStream())
            {
                inputStream.Position = 0;
                inputStream.CopyTo(tempStream);
                File.WriteAllBytes(filepath, tempStream.ToArray());
            }
 
            var printer = UIPrintInteractionController.SharedPrintController;
            printInfo.OutputType = UIPrintInfoOutputType.General;
 
            printer.PrintingItem = NSUrl.FromFilename(filepath);
            printer.PrintInfo = printInfo;
 
 
            printer.ShowsPageRange = true;
 
            printer.Present(true, (handler, completed, err) => {
                if (!completed && err != null)
                {
                    Console.WriteLine("error");
                }
            });
        }
    }
}

 

UWP

C#

//Register the UWP implementation of the interface with DependencyService
[assembly: Xamarin.Forms.Dependency(typeof(PrintService))]
 
namespace PDFPrintingSample.UWP
{
    class PrintService : IPrintService
    {
        internal int pageCount;
        internal global::Windows.Data.Pdf.PdfDocument pdfDocument;
        private PrintDocument printDocument;
        private IPrintDocumentSource printDocumentSource;
        string fileName;
        double marginWidth = 0;
 
        double marginHeight = 0;
     private Canvas pdfDocumentPanel = new Canvas();
 
        internal Dictionary<int, UIElement> printPreviewPages = new Dictionary<int, UIElement>();
        private List<string> imagePaths = new List<string>();
        IRandomAccessStream randomStream;
        public async void Print(Stream inputStream, string fileName)
        {
            inputStream.Position = 0;
            MemoryStream ms = new MemoryStream();
            //Copy the input stream to a new MemoryStream
            inputStream.CopyTo(ms);
            ms.Position = 0;
            //Convert the MemoryStream to a stream that allows random access
            randomStream = await ConvertToRandomAccessStream(ms);
            IAsyncOperation<global::Windows.Data.Pdf.PdfDocument> result = null;
            //Create the IAsyncOperation object from the given random stream
            result = global::Windows.Data.Pdf.PdfDocument.LoadFromStreamAsync(randomStream);
 
            result.AsTask().Wait();
            //Get the PdfDocument instance that represents the PDF document that is loaded
            pdfDocument = result.GetResults();
            result = null;
            pageCount = (int)pdfDocument.PageCount;
            fileName = fileName;
            await IncludeCanvas();
            try
            {
                UIDispatcher.Execute(async () =>
                {
                    RegisterForPrint();
                    //Show the UI window with printing options
                    await PrintManager.ShowPrintUIAsync();
                });
            }
            catch
            {
                UIDispatcher.Execute(async () =>
                {
                    RegisterForPrint();
                    //Show the UI window with printing options
                    PrintManager.ShowPrintUIAsync();
                });
            }
        }
 
        //Method to convert the given MemoryStream to a stream that allows random access.
        public async Task<IRandomAccessStream> ConvertToRandomAccessStream(MemoryStream memoryStream)
        {
            var randomAccessStream = new InMemoryRandomAccessStream();
            MemoryStream contentStream = new MemoryStream();
            memoryStream.CopyTo(contentStream);
            using (var outputStream = randomAccessStream.GetOutputStreamAt(0))
            {
                using (var dw = new DataWriter(outputStream))
                {
                    var task = new Task(() => dw.WriteBytes(contentStream.ToArray()));
                    task.Start();
 
                    await task;
                    await dw.StoreAsync();
 
                    await outputStream.FlushAsync();
                    await dw.FlushAsync();
                    outputStream.Dispose();
                    dw.DetachStream();
                    dw.Dispose();
                }
            }
            return randomAccessStream;
        }
        PrintManager printMan;
        private void RegisterForPrint()
        {
            printDocument = new PrintDocument();
 
            // Save the DocumentSource.
            printDocumentSource = printDocument.DocumentSource;
            // Add an event handler which creates preview pages.
            printDocument.Paginate += CreatePrintPreviewPages;
 
            // Add an event handler which provides a specified preview page.
            printDocument.GetPreviewPage += GetPrintPreviewPage;
 
            // Add an event handler which provides all final print pages.
            printDocument.AddPages += AddPrintPages;
 
            // Create a PrintManager and add a handler for printing initialization.
            printMan = PrintManager.GetForCurrentView();
            printMan.PrintTaskRequested += PrintTaskRequested;
        }
        
        Image imageCtrl = new Image();
        private async void AddPrintPages(object sender, AddPagesEventArgs e)
        {
            try
            {
                await PrepareForPrint(0, pageCount);
                PrintDocument printDoc = (PrintDocument)sender;
                printDoc.AddPagesComplete();
            }
            catch
            {
                PrintDocument printDoc = (PrintDocument)sender;
                printDoc.InvalidatePreview();
            }
        }
        private async Task<int> PrepareForPrint(int startIndex, int count)
        {
            StorageFolder tempFolder = ApplicationData.Current.TemporaryFolder;
            int result = await PrepareForPrint(startIndex, count, tempFolder);
            tempFolder = null;
            return result;
        }
        private async Task<int> PrepareForPrint(int p, int count, StorageFolder tempfolder)
        {
            for (int i = p; i < count; i++)
            {
                float zoomfactor = 1;
                //Adjust the zoom factor according to the display properties
                double customZoomFactor = zoomfactor * 96 / DisplayProperties.LogicalDpi;                
                ApplicationLanguages.PrimaryLanguageOverride = CultureInfo.InvariantCulture.TwoLetterISOLanguageName;
                //Get the page from the PDF document with a given index
                var pdfPage = pdfDocument.GetPage(uint.Parse(i.ToString()));
                double pdfPagePreferredZoom = pdfPage.PreferredZoom /** m_pdfViewer.PrinterSettings.QualityFactor*/;
                IRandomAccessStream randomStream = new InMemoryRandomAccessStream();
                global::Windows.Data.Pdf.PdfPageRenderOptions pdfPageRenderOptions = new global::Windows.Data.Pdf.PdfPageRenderOptions();
                Size pdfPageSize = pdfPage.Size;
                //Set the height to which the page is to be printed
                pdfPageRenderOptions.DestinationHeight = (uint)(pdfPageSize.Height * pdfPagePreferredZoom);
                //Set the width to which the page is to be printed
                pdfPageRenderOptions.DestinationWidth = (uint)(pdfPageSize.Width * pdfPagePreferredZoom);
                await pdfPage.RenderToStreamAsync(randomStream, pdfPageRenderOptions);
                //Create a new Image to which the page will be rendered
                imageCtrl = new Image();
                BitmapImage src = new BitmapImage();
                randomStream.Seek(0);
                //Obtain image source from the randomstream
                src.SetSource(randomStream);
                //set the image source to the image
                imageCtrl.Source = src;
                var DisplayInformation = Windows.Graphics.Display.DisplayInformation.GetForCurrentView();
 
                var dpi = DisplayInformation.LogicalDpi/96;
                imageCtrl.Height = src.PixelHeight/dpi;
                imageCtrl.Width = src.PixelWidth/dpi;
                randomStream.Dispose();
                pdfPage.Dispose();
                printDocument.AddPage(imageCtrl);
            }
            return 0;
        }
       private void CreatePrintPreviewPages(object sender, PaginateEventArgs e)
        {
            PrintTaskOptions printingOptions = ((PrintTaskOptions)e.PrintTaskOptions);
            PrintPageDescription pageDescription = printingOptions.GetPageDescription((uint)e.CurrentPreviewPageNumber);
            marginWidth = pageDescription.PageSize.Width;
            marginHeight = pageDescription.PageSize.Height;
            AddOnePrintPreviewPage();
 
            PrintDocument printDoc = (PrintDocument)sender;
            printDoc.SetPreviewPageCount(pageCount, PreviewPageCountType.Final);
        }
        private void AddOnePrintPreviewPage()
        {
            for (int i = pdfDocumentPanel.Children.Count - 1; i >= 0; i--)
            {
                Canvas print = pdfDocumentPanel.Children[i] as Canvas;
                if (print != null)
                {
                    print.Width = marginWidth;
                    print.Height = marginHeight;
                    printPreviewPages.Add(i, print);
 
                }
            }
        }
 
        private async void GetPrintPreviewPage(object sender, GetPreviewPageEventArgs e)
        {
            PrintDocument printDoc = (PrintDocument)sender;
            pdfDocumentPanel.Children.Remove(printPreviewPages[e.PageNumber - 1]);
            printDoc.SetPreviewPage(e.PageNumber, printPreviewPages[e.PageNumber - 1]);
        }
 
        private async Task<int> IncludeCanvas()
        {
            for (int i = 0; i < pageCount; i++)
            {
                int pageIndex = i;
                var pdfPage = pdfDocument.GetPage(uint.Parse(i.ToString()));
                double width = pdfPage.Size.Width;
                double height = pdfPage.Size.Height;
                Canvas page = new Canvas();
                page.Width = width;
                page.Height = height;
                page.VerticalAlignment = global::Windows.UI.Xaml.VerticalAlignment.Top;
                page.HorizontalAlignment = global::Windows.UI.Xaml.HorizontalAlignment.Center;
                page.Background = new Windows.UI.Xaml.Media.SolidColorBrush(global::Windows.UI.Color.FromArgb(255, 255, 255, 255));
                page.Margin = new Thickness(0, 0, 0, 0);
 
                double pdfPagePreferredZoom = pdfPage.PreferredZoom /** m_pdfViewer.PrinterSettings.QualityFactor*/;
                IRandomAccessStream randomStream = new InMemoryRandomAccessStream();
                global::Windows.Data.Pdf.PdfPageRenderOptions pdfPageRenderOptions = new global::Windows.Data.Pdf.PdfPageRenderOptions();
                Size pdfPageSize = pdfPage.Size;
                //Set the height to which the page is to be printed
                pdfPageRenderOptions.DestinationHeight = (uint)(pdfPageSize.Height * pdfPagePreferredZoom);
                //Set the width to which the page is to be printed
                pdfPageRenderOptions.DestinationWidth = (uint)(pdfPageSize.Width * pdfPagePreferredZoom);
                await pdfPage.RenderToStreamAsync(randomStream, pdfPageRenderOptions);
                //Create a new Image to which the page will be rendered
                imageCtrl = new Image();
                BitmapImage src = new BitmapImage();
                randomStream.Seek(0);
                //Obtain image source from the randomstream
                src.SetSource(randomStream);
                //set the image source to the image
                imageCtrl.Source = src;
                var DisplayInformation = Windows.Graphics.Display.DisplayInformation.GetForCurrentView();
 
                var dpi = DisplayInformation.LogicalDpi / 96;
                imageCtrl.Height = src.PixelHeight / dpi;
                imageCtrl.Width = src.PixelWidth / dpi;
                randomStream.Dispose();
                pdfPage.Dispose();
 
                page.Children.Add(imageCtrl);
                pdfDocumentPanel.Children.Add(page);
            }
            return 0;
        }
        PrintTask printTask;
        MessageDialog msgDialog;
 
        private async void PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs e)
        {
 
            printTask = e.Request.CreatePrintTask(fileName, sourceRequested => sourceRequested.SetSource(printDocumentSource));
 
                printTask.Completed += printTask_Completed;
            
        }
 
     
        //Called when the printing operation completes
        private void printTask_Completed(PrintTask sender, PrintTaskCompletedEventArgs args)
        {
            printTask.Completed -= printTask_Completed;
            printMan.PrintTaskRequested -= PrintTaskRequested;
 
 
            UIDispatcher.Execute(async () =>
            {
 
                
                msgDialog = new MessageDialog("Printing operation has been completed");
                await msgDialog.ShowAsync();                
 
            });
        }  
    }
 
    //Helper class to run operations async
    internal class UIDispatcher
    {
        private static CoreDispatcher Dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
        /// <summary>
        /// Executes the action using UIElement.
        /// </summary>
        /// <param name="action">An Action.</param>
        internal static void Execute(Action action)
        {
            if (CoreApplication.MainView.CoreWindow == null
                || Dispatcher.HasThreadAccess)
                action();
            else
                Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()).AsTask().Wait();
        }
    }
}
 

 

Sample link:

https://www.syncfusion.com/downloads/support/directtrac/general/ze/PDFPrintingSample1519956005.zip

Did you find this information helpful?
Yes
No
Help us improve this page
Please provide feedback or comments
Comments
Please sign in to leave a comment
Access denied
Access denied