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. ThanksAnonymous
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.comAnonymous
October 18, 2013
Can pictures also be added to the pdfAnonymous
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 helpAnonymous
March 20, 2014
find the problem, the coordinate are relative not absolute thanks againAnonymous
May 13, 2014
Hi , I need to use above code in wp8 . There's two problem with the code :
- Download link of code is not working.
- enc function is not give here. Plz provide that too.
- 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 fineAnonymous
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 advanceAnonymous
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.htmlAnonymous
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/.../10154965812750154Anonymous
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.1Anonymous
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
Anonymous
January 17, 2016
Ca you plz send me code for windows 7.1 at shasankha@yahoo.comAnonymous
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 postAnonymous
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