In this short blogpost I want to show you how I’ve used the Windows.Data.Pdf.PdfDocument class in order to render a PDF file inside my UWP app.

In order to open a PDF from a UWP app, you can ofcourse, always use Windows.System.Launcher.LaunchUriAsync like this:

using LauncherOptions Windows.System.LauncherOptions options = new Windows.System.LauncherOptions(); options.ContentType = "application/pdf"; Windows.System.Launcher.LaunchUriAsync(new Uri(fileUrl), options); 1 2 3 Windows . System . LauncherOptions options = new Windows . System . LauncherOptions ( ) ; options . ContentType = "application/pdf" ; Windows . System . Launcher . LaunchUriAsync ( new Uri ( fileUrl ) , options ) ;

This works great, but your file is being opened in an other app. And this might not be what you want. We just want the content of the PDF file being rendered inside our UWP app itself.

And that’s very simple to do!

First we need to load a PDF document in a Windows.Data.Pdf.PdfDocument object. There are two way to do this: From a StorageFile or from a Stream.

LoadFromFileAsync public async void OpenLocal() { StorageFile f = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/pdffile.pdf")); PdfDocument doc = await PdfDocument.LoadFromFileAsync(f); Load(doc); } 1 2 3 4 5 6 7 8 public async void OpenLocal ( ) { StorageFile f = await StorageFile . GetFileFromApplicationUriAsync ( new Uri ( "ms-appx:///Assets/pdffile.pdf" ) ) ; PdfDocument doc = await PdfDocument . LoadFromFileAsync ( f ) ; Load ( doc ) ; }

LoadFromStreamAsync public async void OpenRemote() { HttpClient client = new HttpClient(); var stream = await client.GetStreamAsync(url); var memStream = new MemoryStream(); await stream.CopyToAsync(memStream); memStream.Position = 0; PdfDocument doc = await PdfDocument.LoadFromStreamAsync(memStream.AsRandomAccessStream()); Load(doc); } 1 2 3 4 5 6 7 8 9 10 11 public async void OpenRemote ( ) { HttpClient client = new HttpClient ( ) ; var stream = await client . GetStreamAsync ( url ) ; var memStream = new MemoryStream ( ) ; await stream . CopyToAsync ( memStream ) ; memStream . Position = 0 ; PdfDocument doc = await PdfDocument . LoadFromStreamAsync ( memStream . AsRandomAccessStream ( ) ) ; Load ( doc ) ; }

This PdfDocument object has a method GetPage(int pageIndex) which returns a PdfPage object. This object represents a single page of our PdfDocument and has this interesting method: RenderToStreamAsync. This method accepts a IRandomAccessStream and optionally PdfPageRenderOptions.

Once the page is rendered to the Stream, we can set it to a BitmapImage by using the BitmapImage‘s SetSource(Asyc) method.

var page = pdfDoc.GetPage(0); using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream()) { await page.RenderToStreamAsync(stream); await bitmapImage.SetSourceAsync(stream); } 1 2 3 4 5 6 7 var page = pdfDoc . GetPage ( 0 ) ; using ( InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream ( ) ) { await page . RenderToStreamAsync ( stream ) ; await bitmapImage . SetSourceAsync ( stream ) ; }

This BitmapImage can now be easily bound to the Source property of an Image in XAML. Or, in this case, we can bind our collection of PdfPages to an ItemsControl and display an Image for each item.

Binding <ScrollViewer ZoomMode="Enabled" Background="DarkGray" Grid.Column="1"> <ItemsControl ItemsSource="{Binding PdfPages, ElementName=root}"> <ItemsControl.ItemTemplate> <DataTemplate> <Image Source="{Binding}" Margin="0 2" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </ScrollViewer> 1 2 3 4 5 6 7 8 9 <ScrollViewer ZoomMode = "Enabled" Background = "DarkGray" Grid . Column = "1" > <ItemsControl ItemsSource = "{Binding PdfPages, ElementName=root}" > <ItemsControl.ItemTemplate> <DataTemplate> <Image Source = "{Binding}" Margin = "0 2" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </ScrollViewer>

Complete code-behind:

Code-behind public MainPage() { this.InitializeComponent(); } public async void OpenLocal() { StorageFile f = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/pdffile.pdf")); PdfDocument doc = await PdfDocument.LoadFromFileAsync(f); Load(doc); } public async void OpenRemote() { HttpClient client = new HttpClient(); var stream = await client.GetStreamAsync("http://www.adobe.com/content/dam/Adobe/en/accessibility/products/acrobat/pdfs/acrobat-x-accessible-pdf-from-word.pdf"); var memStream = new MemoryStream(); await stream.CopyToAsync(memStream); memStream.Position = 0; PdfDocument doc = await PdfDocument.LoadFromStreamAsync(memStream.AsRandomAccessStream()); Load(doc); } async void Load(PdfDocument pdfDoc) { PdfPages.Clear(); for (uint i = 0; i < pdfDoc.PageCount; i++) { BitmapImage image = new BitmapImage(); var page = pdfDoc.GetPage(i); using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream()) { await page.RenderToStreamAsync(stream); await image.SetSourceAsync(stream); } PdfPages.Add(image); } } public ObservableCollection<BitmapImage> PdfPages { get; set; } = new ObservableCollection<BitmapImage>(); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 public MainPage ( ) { this . InitializeComponent ( ) ; } public async void OpenLocal ( ) { StorageFile f = await StorageFile . GetFileFromApplicationUriAsync ( new Uri ( "ms-appx:///Assets/pdffile.pdf" ) ) ; PdfDocument doc = await PdfDocument . LoadFromFileAsync ( f ) ; Load ( doc ) ; } public async void OpenRemote ( ) { HttpClient client = new HttpClient ( ) ; var stream = await client . GetStreamAsync ( "http://www.adobe.com/content/dam/Adobe/en/accessibility/products/acrobat/pdfs/acrobat-x-accessible-pdf-from-word.pdf" ) ; var memStream = new MemoryStream ( ) ; await stream . CopyToAsync ( memStream ) ; memStream . Position = 0 ; PdfDocument doc = await PdfDocument . LoadFromStreamAsync ( memStream . AsRandomAccessStream ( ) ) ; Load ( doc ) ; } async void Load ( PdfDocument pdfDoc ) { PdfPages . Clear ( ) ; for ( uint i = 0 ; i < pdfDoc . PageCount ; i ++ ) { BitmapImage image = new BitmapImage ( ) ; var page = pdfDoc . GetPage ( i ) ; using ( InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream ( ) ) { await page . RenderToStreamAsync ( stream ) ; await image . SetSourceAsync ( stream ) ; } PdfPages . Add ( image ) ; } } public ObservableCollection < BitmapImage > PdfPages { get ; set ; } = new ObservableCollection < BitmapImage > ( ) ;

And that’s all there is to it!

UPDATE

I made a PdfViewerControl you can use in order to easily display PDF files in your UWP apps. It’s available, together with the source code in GitHub.

Share this: Twitter

Facebook

Print

More

LinkedIn

Reddit



Tumblr

Pocket





Like this: Like Loading...