2X faster development
The ultimate Xamarin UI toolkit to boost your development speed.
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
|
2X faster development
The ultimate Xamarin UI toolkit to boost your development speed.
This page will automatically be redirected to the sign-in page in 10 seconds.
hi, for ios it is fine.but coming to android ,at the time of calling dependency services ,i got null reference error.can u please help me out from this.
Hi Bharathi,
We can able to print the PDF documents properly with the sample available in this KB. Kindly provide the following details to analyze more on your issue.
Hi , i didnt register the dedepnacy service.so that is the reason for my error.now running properly with out faceing any errors.
i found the printer device name in my mobile(using above your printer code).after choosing printer asked enter the password which gives printer device.later in printer device shows as "connected".but print is not coming (for android).
could you please point to me right direction to print the pdf file.
and in ios ,even if i connected same networks ,it is showing "no airprint printers found".
Thanks
Bharathi.
Hi Bharathi,
Can you please share the following details to analyze more on the issue?
These details will be helpful for us to analyze more on your and assist you with better solution.
Regards, Sathish
Thank you for the solution. I used it for UWP. I can print documents successfully, but the preview never ends loading. Could you please help?
Hi Dmitriy,
We have modified the code changes to resolve the reported issue. Please try the sample refreshed in the KB and let us know if you still facing the same issue.
Regards, Sathish
Hi,
I am trying to print the pdf document in physical device via wifi using the above mentioned code. Here when i run the code,my device is detected in printer as well as in my phone also got printer name.once selected the printer,it is asking password which is generated by printer.after entering password , in printer i found that is "connected". but pdf file is not printed.
Please help me out.i have been trying from long time.
Thanks Bharathi.
Hi Bharathi,
Printing the PDF document doesn’t depend on SfPdfViewerControl, we need to contact the Xamarin forum members to check your issue and get the solution. Please raise your question in the below forum to get the solution.
https://forums.xamarin.com/categories/xamarin-forms
Regards, Sathish
If I print on Android, it will say "Failed to change the settings. Try again." and on the notification of the device, it says "Print services not enable.".. How to fix this? Please help. Thanks!
Hi White,
Printing the PDF document doesn’t depend on SfPdfViewerControl, we need to contact the Xamarin forum members to check your issue and get the solution. Please raise your question in the below forum to get the solution.
https://forums.xamarin.com/categories/xamarin-forms
Regards, Sathish