Partager via


How to generate PDF on Windows Phone in VB or C#

I need to generate PDF from my Windows Phone app.

Unfortunately none of the standard free PDF-generating libraries work on Windows Phone. I've had to generate the PDF myself, by writing to the file format directly. It turned out to be really easy! Source code is at the bottom of this post, and in this link:

  •  Download source code.zip [60k, requires VS2012, includes Console and WP8 apps]

 

Why even generate PDF on Phone?

Some people say that there's no point having PDFs on the phone, since it's not the most efficient use of screen and touch interaction.

Well in my case, I wanted to generate a PDF, upload it to the user's SkyDrive account, and let the user send an email with a "share" link. That's how Microsoft's own PDF-Reader app works when you click the "share" button.

Other people suggest that a Phone has no business generating PDFs because it's such a costly operation, and you should instead upload your document to your PDF-generating webserver. This is wrong. PDF-generation, at least for the kinds of reports I was generating (two pages of non-flowed text), is a very cheap operation. I bet that it costs more battery to upload+download a document than to generate a PDF.

iTextSharp

https://itextpdf.com/ (AGPL license, or you can purchase a commercial license, available on NuGet)

iTextSharp doesn't work on Windows Phone, because it has a runtime dependency on System.Drawing.dll. (There's another experimental port https://itextsharpsl.codeplex.com/ under the MPL license, designed to work on Silverlight and Windows Phone, but I was unable to figure out the references needed to get it work. It's also a huge package, 30mb compressed source code). iTextSharp has superb documentation, including a published book. Here's how its API looks, to generate the PDF at the top of this article:

Imports  iTextSharp.text 

Module  Module1
     Sub  Main()
         Dim  doc  As  New  Document ()
         Using  file  As  New  System.IO. FileStream ( "a.pdf" , System.IO. FileMode .Create),
            writer = pdf. PdfWriter .GetInstance(doc, file)
            doc.Open()

             Dim  titleFont =  FontFactory .GetFont( FontFactory .TIMES, 40,  Font .NORMAL)
             Dim  subtitleFont =  FontFactory .GetFont( FontFactory .TIMES, 20,  Font .ITALIC,  BaseColor .BLUE)
             Dim  column  As  New  pdf. ColumnText (writer.DirectContent)
            column.SetSimpleColumn(230, 600, 400, 400)  ' bounding coords of column
            column.AddText( New  Phrase ( "Hello all" , titleFont))
            column.Go()
            column.AddText( New  Phrase ( "olé" , subtitleFont))
            column.Go()

            doc.Close()
         End  Using
         Process .Start( "a.pdf" )
     End  Sub
End  Module

 

PDFSharp

https://www.pdfsharp.net/ (MIT license, available on NuGet)

PDFSharp doesn't work on Windows Phone, because it has a compiletime dependency on System.Drawing.dll. Here's how its API looks...

Imports  PdfSharp.Drawing

 Module  Module1 
     Sub  Main()
         Dim  document  As  New  PdfSharp.Pdf. PdfDocument 
         Dim  page = document.AddPage
         Dim  gfx =  XGraphics .FromPdfPage(page)
         Dim  titleFont  As  New  XFont ( "Times New Roman" , 40,  XFontStyle .Regular)
         Dim  subtitleFont  As  New  XFont ( "Times New Roman" , 20,  XFontStyle .Italic)
gfx.DrawString( "Hello all" , titleFont,  XBrushes .Black, 230, 400)
         Dim  height = gfx.MeasureString( "olé" , subtitleFont).Height
gfx.DrawString( "olé" , subtitleFont,  XBrushes .Blue, 230, 400 + height)

         Using  stream  As  New  IO. FileStream ( "a.pdf" , IO. FileMode .Create)
document.Save(stream)
         End  Using 

         Process .Start( "a.pdf" )
     End  Sub 
 End  Module

 

PDFJet

https://www.pdfjet.com/os/edition.html (BSD license; not available on NuGet)

PDFJet doesn't work on Windows Phone, because it has a compiletime dependency System.IO.DeflateStream. PDFJet is the most interesting of all these PDF libraries. It's been written from scratch with as few dependencies as possible - no dependencies on System.Drawing, or Winforms. Its only dependency is on DeflateStream. If someone could package it up with a Phone-compatible implementation of DeflateStream then it would work great. I tried to get it to work with DotNetZip and SharpZipLib but didn't succeed. Note that PDFJet is distributed as just a directory full of .cs files, so you have to create a project for it. Easy to do. Anyway, here's how it looks:

Imports  PDFjet.NET

 Module  Module1 

     Sub  Main()
         Using  stream  As  New  IO. FileStream ( "a.pdf" , IO. FileMode .Create)
             Dim  pdf  As  New  PDF (stream)
             Dim  page  As  New  Page (pdf,  Letter .PORTRAIT)
             Dim  titleFont  As  New  Font (pdf,  CoreFont .TIMES_ROMAN)
titleFont.SetSize(40)
             Dim  subtitleFont  As  New  Font (pdf,  CoreFont .TIMES_ITALIC)
subtitleFont.SetSize(20)
             Dim  text1  As  New  TextLine (titleFont,  "Hello all" )
text1.SetPosition(230, 400)
text1.DrawOn(page)
             Dim  text2  As  New  TextLine (subtitleFont,  "olé" )
text2.SetPosition(230, 400 + text2.GetHeight)
text2.SetColor( Color .blue)
text2.DrawOn(page)
pdf.Flush()
         End  Using 

         Process .Start( "a.pdf" )
     End  Sub 

 End  Module 

 

PDFClown

https://pdfclown.wordpress.com/ (LGPL license; not available on NuGet)

PDFClown doesn't work on Windows Phone, because it has a compiletime dependency System.Drawing and Winforms. PDFClown aggressively uses Java rather than .NET conventions. Its API is an exact mirror of the PDF file format structure. In my view it doesn't offer much benefit beyond just writing the file format structure manually. Here's how it looks:

Imports  org.pdfclown
Imports  org.pdfclown.documents.contents

 Module  Module1 

     Sub  Main()
         Using  stream  As  New  IO. FileStream ( "a.pdf" , IO. FileMode .Create),
pdfstream  As  New  org.pdfclown.bytes. Stream (stream),
pdf  As  New  files. File ()

             Dim  document = pdf.Document
             Dim  page  As  New  documents. Page (document)
document.Pages.Add(page)
             Dim  titleFont =  New  fonts. StandardType1Font (document, fonts. StandardType1Font . FamilyEnum .Times,  False ,  False )
             Dim  subtitleFont =  New  fonts. StandardType1Font (document, fonts. StandardType1Font . FamilyEnum .Times,  False ,  True )
             Dim  composer  As  New  composition. PrimitiveComposer (page)
             Dim  blockcomposer  As  New  composition. BlockComposer (composer)
blockcomposer.Begin( New  Drawing. RectangleF (230, 400, 200, 200), composition. XAlignmentEnum .Left, composition. YAlignmentEnum .Top)
composer.SetFont(titleFont, 40)
blockcomposer.ShowText( "Hello all"  & vbCrLf)
composer.SetFont(subtitleFont, 20)
composer.SetFillColor( New  colorSpaces. DeviceRGBColor (0, 0, 1))
blockcomposer.ShowText( "olé"  & vbCrLf)
blockcomposer.End()
composer.Flush()

pdf.Save(pdfstream, files. SerializationModeEnum .Standard)
         End  Using 

         Process .Start( "a.pdf" )

     End  Sub 

 End  Module 

 

Write the PDF file format yourself

https://acroeng.adobe.com/wp/?page_id=321 (documentation of PDF file format; I used the 1.2 version of the PDF spec)

This code works great on Windows Phone. Frankly, the PDF file format is very simple if all you want to do is create simple reports - with text, charts &c. What we need is sample code for that show how to create PDFs, not just libraries that encapsulate how to create PDFs. So here's my sample code! Note that I make use of one extra function "enc" which translates non-ASCII from Unicode (used in .NET) into WinAnsiEncoding (the encoding I chose to use for the PDF) - full source code is downloadable from the link at the top of this article.

 

Private  Async  Sub  Button1_Click(sender  As  Object , e  As  RoutedEventArgs )  Handles  Button1.Click

     Dim  file =  Await ApplicationData .Current.LocalFolder.CreateFileAsync("a.pdf" , Windows.Storage. CreationCollisionOption .ReplaceExisting)
     Using  stream =  Await  System.IO. WindowsRuntimeStorageExtensions .OpenStreamForWriteAsync(file),
writer  As  New  IO. StreamWriter (stream, Text. Encoding .UTF8)

         Dim  xrefs  As  New  List ( Of  Long )()

         ' PDF-HEADER 
writer.WriteLine( "%PDF-1.2" )

         ' PDF-BODY. Convention is to start with a 4-byte binary comment 
         ' so everyone recognizes the pdf as binary. Then the file has 
         ' a load of numbered objects, #1..#7 in this case 
writer.Write( "%" ) : writer.Flush()
stream.Write({&HC7, &HEC, &H8F, &HA2}, 0, 4) : stream.Flush()
writer.WriteLine( "" )

         ' #1: catalog - the overall container of the entire PDF 
writer.Flush() : stream.Flush() : xrefs.Add(stream.Position)
writer.WriteLine( "1 0 obj" )
writer.WriteLine( "<<" )
writer.WriteLine( " /Type /Catalog" )
writer.WriteLine( " /Pages 2 0 R" )
writer.WriteLine( ">>" )
writer.WriteLine( "endobj" )

         ' #2: page-list - we have only one child page 
writer.Flush() : stream.Flush() : xrefs.Add(stream.Position)
writer.WriteLine( "2 0 obj" )
writer.WriteLine( "<<" )
writer.WriteLine( " /Type /Pages" )
writer.WriteLine( " /Kids [3 0 R]" )
writer.WriteLine( " /Count 1" )
writer.WriteLine( ">>" )
writer.WriteLine( "endobj" )

         ' #3: page - this is our page. We specify size, font resources, and the contents 
writer.Flush() : stream.Flush() : xrefs.Add(stream.Position)
writer.WriteLine( "3 0 obj" )
writer.WriteLine( "<<" )
writer.WriteLine( " /Type /Page" )
writer.WriteLine( " /Parent 2 0 R" )
writer.WriteLine( " /MediaBox [0 0 612 792]" )  ' Default userspace units: 72/inch, origin at bottom left 
writer.WriteLine( " /Resources" )
writer.WriteLine( " <<" )
writer.WriteLine( " /ProcSet [/PDF/Text]" )  ' This PDF uses only the Text ability 
writer.WriteLine( " /Font" )
writer.WriteLine( " <<" )
writer.WriteLine( " /F0 4 0 R" )  ' I will define three fonts, #4, #5 and #6 
writer.WriteLine( " /F1 5 0 R" )
writer.WriteLine( " /F2 6 0 R" )
writer.WriteLine( " >>" )
writer.WriteLine( " >>" )
writer.WriteLine( " /Contents 7 0 R" )
writer.WriteLine( ">>" )
writer.WriteLine( "endobj" )

         ' #4, #5, #6: three font resources, all using fonts that are built into all PDF-viewers 
         ' We're going to use WinAnsi character encoding, defined below. 
writer.Flush() : stream.Flush() : xrefs.Add(stream.Position)
writer.WriteLine( "4 0 obj" )
writer.WriteLine( "<<" )
writer.WriteLine( " /Type /Font" )
writer.WriteLine( " /Subtype /Type1" )
writer.WriteLine( " /Encoding /WinAnsiEncoding" )
writer.WriteLine( " /BaseFont /Times-Roman" )
writer.WriteLine( ">>" )
writer.Flush() : stream.Flush() : xrefs.Add(stream.Position)
writer.WriteLine( "5 0 obj" )
writer.WriteLine( "<<" )
writer.WriteLine( " /Type /Font" )
writer.WriteLine( " /Subtype /Type1" )
writer.WriteLine( " /Encoding /WinAnsiEncoding" )
writer.WriteLine( " /BaseFont /Times-Bold" )
writer.WriteLine( ">>" )
writer.Flush() : stream.Flush() : xrefs.Add(stream.Position)
writer.WriteLine( "6 0 obj" )
writer.WriteLine( "<<" )
writer.WriteLine( " /Type /Font" )
writer.WriteLine( " /Subtype /Type1" )
writer.WriteLine( " /Encoding /WinAnsiEncoding" )
writer.WriteLine( " /BaseFont /Times-Italic" )
writer.WriteLine( ">>" )

         ' #7: contents of page. This is written in postscript, fully described in 
         ' chapter 8 of the PDF 1.2 reference manual. 
writer.Flush() : stream.Flush() : xrefs.Add(stream.Position)
         Dim  sb  As  New  Text. StringBuilder 
sb.AppendLine( "BT" )              ' BT = begin text object, with text-units the same as userspace-units 
sb.AppendLine( "/F0 40 Tf" )       ' Tf = start using the named font "F0" with size "40" 
sb.AppendLine( "40 TL" )           ' TL = set line height to "40" 
sb.AppendLine( "230.0 400.0 Td" )  ' Td = position text point at coordinates "230.0", "400.0" 
sb.AppendLine( "(Hello all) '" )   ' Apostrophe = print the text, and advance to the next line 
sb.AppendLine( "/F2 20 Tf" )       ' 
sb.AppendLine( "20 TL" )           ' 
sb.AppendLine( "0.0 0.2 1.0 rg" )  ' rg = set fill color to RGB("0.0", "0.2", "1.0") 
sb.AppendLine( "(ol"  & enc( "é" ) &  ") '" )
sb.AppendLine( "ET" )              ' 
         ' 
writer.WriteLine( "7 0 obj" )
writer.WriteLine( "<<" )
writer.WriteLine( " /Length "  & sb.Length)
writer.WriteLine( ">>" )
writer.WriteLine( "stream" )
writer.Write(sb.ToString())
writer.WriteLine( "endstream" )
writer.WriteLine( "endobj" )

         ' PDF-XREFS. This part of the PDF is an index table into every object #1..#7 
         ' that we defined. 
writer.Flush() : stream.Flush() :  Dim  xref_pos = stream.Position
writer.WriteLine( "xref" )
writer.WriteLine( "1 "  & xrefs.Count)
         For  Each  xref  In  xrefs
writer.WriteLine( "{0:0000000000} {1:00000} n" , xref, 0)
         Next 

         ' PDF-TRAILER. Every PDF ends with this trailer. 
writer.WriteLine( "trailer" )
writer.WriteLine( "<<" )
writer.WriteLine( " /Size "  & xrefs.Count)
writer.WriteLine( " /Root 1 0 R" )
writer.WriteLine( ">>" )
writer.WriteLine( "startxref" )
writer.WriteLine(xref_pos)
writer.WriteLine( "%%EOF" )
     End  Using 

     Await  Windows.System. Launcher .LaunchFileAsync(file)

 End  Sub

Comments

  • Anonymous
    August 22, 2013
    Hello, thanks for this post. I want to generate a PDF file in my Windows Phone app, but I have some problems in understanding the VB code, because I'm a C# developer. Can you provide your sample also in C# code? Thanks.

  • Anonymous
    August 29, 2013
    Same here!! I need the code in C#, please. Thanks

  • Anonymous
    September 05, 2013
    This code is not working for Windows Store App.

  • Anonymous
    September 09, 2013
    If you don't understand this, you are not going to understand it in C# either.

  • Anonymous
    September 19, 2013
    Worked great in c# as well Thanks If you want in c# kindly email me techloverr@outlook.com

  • Anonymous
    October 18, 2013
    Can pictures also be added to the pdf

  • Anonymous
    October 31, 2013
    I wish I'd seen this two weeks ago.  There's so many applications of creating a PDF on the phone, not least to generate invoices in a mobile quoting/invoicing app.  Which is exactly what I've just tried to do. This would have made it much easier.

  • Anonymous
    October 31, 2013
    Sorry, I don't have a C# version. But it should be very easy to do. The C# code will be almost identical to the VB code. Can pictures be added? I guess so, but it'll require work. I didn't even start to look at how pictures are stored in PDF files. I focused on just the text that I needed for my reports :)

  • Anonymous
    December 04, 2013
    Thanks for this helpful post :)

  • Anonymous
    March 06, 2014
    How can we fill out an already existing PDF document?

  • Anonymous
    March 06, 2014
    @Anam, sorry, I have no idea.

  • Anonymous
    March 20, 2014
    How to display pdf file in windows phone app and select some text to highlight or copy ?

  • Anonymous
    March 20, 2014
    great idea, but i have a question, I can not able to print multi line, but just one, there is some error in y code?   Dim sb As New Text.StringBuilder            sb.AppendLine("BT")              ' BT = begin text object, with text-units the same as userspace-units            sb.AppendLine("/F0 20 Tf")       ' Tf = start using the named font "F0" with size "40"            sb.AppendLine("20 TL")           ' TL = set line height to "40"            sb.AppendLine("56.0 708.0 Td")  ' Td = position text point at coordinates "230.0", "400.0"            sb.AppendLine("(" & db_articoli(10) & ") '")   ' Apostrophe = print the text, and advance to the next line            sb.AppendLine("/F0 20 Tf")            sb.AppendLine("20 TL")           ' TL = set line height to "40"            sb.AppendLine("68.0 708.0 Td")  ' Td = position text point at coordinates "230.0", "400.0"            sb.AppendLine("(DATA) '")   ' Apostrophe = print the text, and advance to the next line            sb.AppendLine("20 TL")           ' TL = set line height to "40"            sb.AppendLine("56.0 595.0 Td")  ' Td = position text point at coordinates "230.0", "400.0"            sb.AppendLine("(INTERVENTO DI) '")   ' Apostrophe = print the text, and advance to the next line            sb.AppendLine("20 TL")           ' TL = set line height to "40"            sb.AppendLine("56.0 538.0 Td")  ' Td = position text point at coordinates "230.0", "400.0"            sb.AppendLine("(MODELLO DI MACCHINA) '")   ' Apostrophe = print the text, and advance to the next line            sb.AppendLine("20 TL")           ' TL = set line height to "40"            sb.AppendLine("225.0 538.0 Td")  ' Td = position text point at coordinates "230.0", "400.0"            sb.AppendLine("(MARCA) '")   ' Apostrophe = print the text, and advance to the next line            sb.AppendLine("20 TL")           ' TL = set line height to "40"            sb.AppendLine("396.0 538.0 Td")  ' Td = position text point at coordinates "230.0", "400.0"            sb.AppendLine("(MATRICOLA) '")   ' Apostrophe = print the text, and advance to the next line            sb.AppendLine("20 TL")           ' TL = set line height to "40"            sb.AppendLine("56.0 481.0 Td")  ' Td = position text point at coordinates "230.0", "400.0"            sb.AppendLine("ET")              '            '            writer.WriteLine("7 0 obj")            writer.WriteLine("<<")            writer.WriteLine("  /Length " & sb.Length)            writer.WriteLine(">>")            writer.WriteLine("stream")            writer.Write(sb.ToString())            writer.WriteLine("endstream")            writer.WriteLine("endobj") the other parts are the same like yours thanks for your help

  • Anonymous
    March 20, 2014
    find the problem, the coordinate are relative not absolute thanks again

  • Anonymous
    May 13, 2014
    Hi , I need to use above code in wp8 . There's two problem with the code :

  1. Download link of code is not working.
  2. enc function is not give here. Plz provide that too.
  3. Can I render Bitmap with your code. Regards,
  • Anonymous
    May 13, 2014
    @Pardeep89, the download link works fine for me! Please try again. It includes a WP8 project, and includes the enc function. As for bitmaps, I never tried them. You'll have to do more research to figure out the PDF file format for bitmaps.

  • Anonymous
    May 13, 2014
    Hi Lucian , I mean by your pdf reference : www.pdf-tools.com/.../pdfreference12.pdf Link has web page containing error message. Please provide your reference doc. containing mnemonic for Pdf rendering. Regards,

  • Anonymous
    May 16, 2014
    @Pardeep89, I see, thanks. I updated the link.

  • Anonymous
    July 09, 2014
    Can you post the code in C#? I am not being able to generate in C#. VB works fine

  • Anonymous
    August 10, 2014
    is it possible to add image in PDF by this way ! plz help me out in adding image to PDF document that is already available Thanks in advance

  • Anonymous
    August 31, 2014
    @Karthikeyan   For your request ,this article may be helpful, check it out  www.e-iceblue.com/.../How-to-Create-a-PDF-Document-and-Insert-an-Image.html

  • Anonymous
    September 11, 2014
    Hi, Would you happen to know if it's possible to also extract the text in the PDF by decoding the FlateDecode filter and then rendering the text into a string?

  • Anonymous
    September 11, 2014
    Thanks for providing the code for creating a PDF BTW, didn't know it could be so simple!

  • Anonymous
    December 08, 2014
    Somebody plz tell me how to add image in pdf.

  • Anonymous
    December 19, 2014
    Hola guys i just rewrite it in c# and would like to share it with you :D Thanks a lot for the original poster, you are awesome www.facebook.com/.../10154965812750154

  • Anonymous
    December 28, 2014
    Hello guys, PDF is much more complex than writing a few strings using standard font. PDF is not simple otherwise 700+ pages spec wouldn't exist.

  • Anonymous
    March 03, 2015
    There is a library available, designed for PDF manipulation on all platforms and is called Apitron PDF Kit. Works on windows phone, windows store, xamarin and other platforms.

  • Anonymous
    March 31, 2015
    XFINIUM.PDF library handles PDF files and supports all .NET and Xamarin platforms. http://www.xfiniumpdf.com/

  • Anonymous
    June 11, 2015
    Can anybody send me the link to download Itextsharp dll for windows 8.1

  • Anonymous
    January 04, 2016
    The comment has been removed

    • Anonymous
      October 25, 2016
      Hi, everyone, if someone did R&D on how to add image and make fonts Bold ? i am using @Uday Oleti's C# Code here is the linkhttp://www.c-sharpcorner.com/UploadFile/a55f4c/registration-form-and-login-after-registration-with-same-cre/
  • Anonymous
    January 17, 2016
    Ca you plz send me code for windows 7.1 at shasankha@yahoo.com

  • Anonymous
    February 02, 2016
    Hi Lucian, acroeng.adobe.com/wp link has been expire. Do you have any updated link for the same. If you have please post

  • Anonymous
    May 05, 2018
    ZetPDF.com is the best PDF library in the market. I have tried many of others and they either aren't as simple or simply don't have the features like ZetPDF.com