How to create a simple PDF document in .NET 61

When we first designed the XFINIUM.PDF library for .NET 2 years ago one of the design targets was an easy learning curve. Although it was released first in a controlled corporate environment we still had to make it easy to use.

We used simple and clear abstractions that relate to real world and also to PDF specification: PdfFixedDocument class represents a PDF document which has a fixed layout by its nature, PdfPage class represents a page in a PDF document, the page drawing surface is represented by a PdfGraphics object. The pen is used to stroke a path outline while the brush is used to fill the path interior. An annotation is represented by a specific instance of PdfAnnotation class, a form field by PdfField class and so on. We tried to match the objects in PDF specification with classes in our object model so if you are looking for more advanced PDF features you can easily find them in our API. For example optional content objects are represented by PdfOptionalContentGroup class in our API.

Creating a PDF document with XFINIUM.PDF is a simple task, an empty PDF document requires only 3 lines of code: create the document, create one page and save the document.

Adding text content to the document above requires 3 more lines of code: font creation for drawing the text, brush creation for setting the text color and drawing the actual text on page graphics.

Our object model follows the PDF specification quite closely. This lets you build complex abstractions, such as flow documents, on top of it without problems.

61 thoughts on “How to create a simple PDF document in .NET

  1. Reply Ernst Kugler Apr 25,2014 6:46 am

    The basic question when creating a page is the page size.
    Cannot find any information on how to set the page size.

    The documentation seems to be very poor ???

  2. Reply DeveloperX Aug 16,2014 10:19 am

    Is it possible to set up tables or columns?

    I’m trying to set up two columns, with number values in the second column that need to be right aligned.

  3. Reply DeveloperX Aug 22,2014 8:12 am

    What’s the best way to write out content to pages.

    I currently have:(I build a PdfFormattedContent fc and add all my paragraphs to this, dunno if this is the correct way to do).

    private void DrawFormattedContent(PdfFormattedContent fc) {
    double leftMargin, topMargin, rightMargin, bottomMargin;
    leftMargin = topMargin = rightMargin = bottomMargin = 36;

    var page = _doc.Pages.Add();
    PdfFormattedContent fragment = fc.SplitByBox(page.Width – leftMargin – rightMargin, (page.Height * 1.8) – topMargin – bottomMargin);
    while (fragment != null) {
    page.Graphics.DrawFormattedContent(fragment,
    leftMargin, topMargin, page.Width – leftMargin – rightMargin, (page.Height * 1.8) – topMargin – bottomMargin);
    page.Graphics.CompressAndClose();

    fragment = fc.SplitByBox(page.Width – leftMargin – rightMargin, (page.Height * 1.8) – topMargin – bottomMargin);
    if (fragment != null) {
    page = _doc.Pages.Add();
    }
    }
    }

    Problem is the content is still going off the end of my first page.

    • Reply xfinium.pdf Aug 22,2014 8:21 am

      Can you send us (support at xfiniumpdf dot com) a small sample project that we can run and reproduce this problem?
      Thank you.

    • Reply Benito Aug 5,2015 9:58 am

      Don’t apply 1.8 factor to calculate de SplitByBox size. Just use something like that:

      SplitByBox(page.Width – leftMargin – rightMargin, page.Height – topMargin – bottomMargin);

  4. Reply Med Amin Jul 7,2015 4:24 pm

    If I want to enter a “paragraph“, and I need to return to next line

    string paragraph = "azj aeiajiahfioe foiehfioehfiehfie feifjaepfjaepofjaepo fpaejfpeafjaefaefhevpzevje vjepzvihzev zep";
    // Draw the text on the page.
    page.Graphics.DrawString(paragraph, helvetica, brush, 100, 100);

    what is the solution?

    • Reply xfinium.pdf Jul 8,2015 3:37 pm

      If you want the text to wrap automatically at a specified width you can do this:

      PdfStringAppearanceOptions sao = new PdfStringAppearanceOptions();
      sao.Brush = brush;
      sao.Font = helvetica;

      // Height is not set, text has no vertical limit.
      PdfStringLayoutOptions slo = new PdfStringLayoutOptions();
      slo.HorizontalAlign = PdfStringHorizontalAlign.Justified;
      slo.VerticalAlign = PdfStringVerticalAlign.Top;
      slo.X = 20;
      slo.Y = 70;
      slo.Width = 280;
      string text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
      "Sed vel euismod risus. Fusce viverra, nisi auctor ullamcorper porttitor, " +
      "ipsum lacus lobortis metus, sit amet dictum lacus velit nec diam. " +
      "Morbi arcu diam, euismod a auctor nec, aliquam in lectus." +
      "Ut ultricies iaculis augue sit amet adipiscing. Aenean blandit tortor a nisi " +
      "dignissim fermentum id adipiscing mauris. Aenean libero turpis, varius nec ultricies " +
      "faucibus, pretium quis lectus. Morbi mollis lorem vel erat condimentum mattis mollis " +
      "nulla sollicitudin. Nunc ut massa id felis laoreet feugiat eget at eros.";
      page.Graphics.DrawString(text, sao, slo);

  5. Reply Benito Aug 7,2015 9:58 am

    Hi, I’m trying to generate a pdf with some foreign characters.

    For chinese and japanese works fine, simply using a different PdfStandardFont, for example, PdfStandardFontFace.MonotypeSungLight for chinese.

    But i can’t write text in russian. Could you help me?

    Thanks.

    • Reply xfinium.pdf Aug 7,2015 8:12 pm

      The CJK fonts included in PdfStandardFontFace enumeration are based on Adobe’s CJK language packs. Not all PDF viewers might display them correctly because the fonts are not embedded (smaller PDF file size).
      For any Unicode characters (chinese, russian, etc) you can use Unicode True Type fonts. You just have to make sure the font supports the language you want. The PdfUnicodeTrueTypeFont class implements Unicode True Type fonts. The Fonts and Text samples show how to use this class.

  6. Reply jaye Feb 2,2016 10:41 am

    I can’t save the document to (sample.pdf), it has an error of: cannot convert ‘string’ to ‘System.IO.Stream’. How am I going to fix this?

    • Reply xfinium.pdf Feb 2,2016 11:59 am

      I assume you use the PCL version of XFINIUM.PDF which does not support file paths. You have to create either a MemoryStream or a FileStream and save the document to the stream.

      • Reply jaye Feb 2,2016 4:19 pm

        I use the CROSS PLATFORM PROFESSIONAL EDITION 5.5.0 of XFINIUM.PDF, and after that I add the uwp dll file to the references.

        • Reply xfinium.pdf Feb 2,2016 5:07 pm

          For UWP the part that creates a stream for writing the PDF file is a bit verbose, here it is the full code (the storage related classes are located in Windows.Storage namespace):

          PdfFixedDocument document = new PdfFixedDocument();
          PdfPage page = document.Pages.Add();
          // Create a standard font with Helvetica face and 24 point size
          PdfStandardFont helvetica = new PdfStandardFont(PdfStandardFontFace.Helvetica, 24);
          // Create a solid RGB red brush.
          PdfBrush brush = new PdfBrush(PdfRgbColor.Red);
          // Draw the text on the page.
          page.Graphics.DrawString("Hello World", helvetica, brush, 100, 100);

          // Get a local folder for the application.
          StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
          // Create the helloworld.pdf file and open it as a random access stream.
          StorageFile pdfFile = await storageFolder.CreateFileAsync("helloworld.pdf", CreationCollisionOption.ReplaceExisting);
          var pdfStream = await pdfFile.OpenAsync(FileAccessMode.ReadWrite);

          // Convert the random access stream to a .NET Stream and save the document.
          using (Stream stm = pdfStream.AsStream())
          {
          document.Save(stm);
          await stm.FlushAsync();
          }
          pdfStream.Dispose();

          • Reply jaye Feb 2,2016 7:37 pm

            Thank You! But where can I find the .pdf file?

          • Reply xfinium.pdf Feb 3,2016 8:04 am

            If you run the code in debug mode, you can inspect the Path property of the pdfFile object, it will give you the location on disk of the PDF file. It looks something like this: C:\Users\<yourusername>\AppData\Local\Packages\<packageid-guid>\LocalState\helloworld.pdf

          • Reply jaye Feb 9,2016 2:11 pm

            Can I put it to somewhere else? Like Desktop or in Document folder?

          • Reply xfinium.pdf Feb 9,2016 2:31 pm

            You can use the FileOpenPicker class to select the path where you want to save the file, here are more details about this class: https://msdn.microsoft.com/library/windows/apps/br207847

          • Reply jaye Feb 9,2016 2:53 pm

            nothing happened.. its not working

          • Reply xfinium.pdf Feb 9,2016 3:47 pm

            My mistake, it is the FileSavePicker class. Here it is the full code:
            PdfFixedDocument document = new PdfFixedDocument();
            PdfPage page = document.Pages.Add();
            // Create a standard font with Helvetica face and 24 point size
            PdfStandardFont helvetica = new PdfStandardFont(PdfStandardFontFace.Helvetica, 24);
            // Create a solid RGB red brush.
            PdfBrush brush = new PdfBrush(PdfRgbColor.Red);
            // Draw the text on the page.
            page.Graphics.DrawString("Hello World", helvetica, brush, 100, 100);

            FileSavePicker savePicker = new FileSavePicker();
            // Dropdown of file types the user can save the file as
            savePicker.FileTypeChoices.Add("PDF files", new List() { ".pdf" });
            // Default file name if the user does not type one in or select a file to replace
            savePicker.SuggestedFileName = "helloworld.pdf";

            StorageFile pdfFile = await savePicker.PickSaveFileAsync();
            if (pdfFile != null)
            {
                var pdfStream = await pdfFile.OpenAsync(FileAccessMode.ReadWrite);

                // Convert the random access stream to a .NET Stream and save the document.
                using (Stream stm = pdfStream.AsStream())
                {
                    document.Save(stm);
                    await stm.FlushAsync();
                }
                pdfStream.Dispose();
            }

          • Reply jaye Feb 9,2016 4:37 pm

            There’s a problem in this code:
            savePicker.FileTypeChoices.Add(“PDF files”, new List() { “.pdf” });

            the List() has an error.

          • Reply xfinium.pdf Feb 9,2016 4:42 pm

            What’s the error? The code compiles just fine in our project.

          • Reply jaye Feb 9,2016 5:01 pm

            it states that: Using the generic type ‘List’ requires 1 type arguments

          • Reply jaye Feb 9,2016 5:27 pm

            It’s working now! Thanks for everything 😀

          • Reply kunjan May 30,2017 5:36 am

            FileSavePicker is for UWP but what can be used in PCL aiming for ios?

          • Reply xfinium.pdf May 30,2017 6:26 am

            iOS does not let you select a folder for saving a document, usually you save it to your documents folder:
            pdfDocument.Save(Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments) + “/file.pdf”);

  7. Reply hanash Feb 25,2016 9:26 am

    How can I add/include new font style?

    • Reply xfinium.pdf Feb 25,2016 12:03 pm

      The PdfAnsiTrueTypeFont and PdfUnicodeTrueTypeFont classes let you use external TrueType fonts in PDF files. The code below shows how to use a TrueType font:
      // ttfStream is a stream that contains the TrueType font.
      PdfAnsiTrueTypeFont ttf = new PdfAnsiTrueTypeFont(ttfStream, 16, true);
      page.Graphics.DrawString("TrueType font", ttf, blackBrush, 20, 150);

      The Fonts sample included in the install kit will give you more details about the supported fonts in XFINIUM.PDF library.

  8. Reply Chris Shearer Cooper Aug 10,2016 7:48 pm

    Can you give details on how to create a simple PDF in Xamarin? I’m following your sample up to the point of creating the file, when I do this:

    using (Stream stream = new FileStream (pdfPath, FileMode.Create))
    doc.Save (stream);

    But the resulting PDF can’t be opened, both OSX Preview and Acrobat Reader say it’s invalid (although it looks good internally).

  9. Reply Bohdan Sep 2,2016 11:37 am

    Hello. I have one paged PDF doc where only image is placed (nothing more, just 1 image). How can I draw a line on this image? I’m interested in drawing it on the “image level” (this means that pixels of the image will be changed with that line).

    In samples there are some examples, but all of them are drawing lines and other objects above the image, on the new layer, so the original image is not changed.

    Thanks for the help 🙂

    • Reply xfinium.pdf Sep 2,2016 12:30 pm

      Your requirement can be implemented like this: extract the image from the PDF file (using XFINIUM.PDF), modify it (add a line, etc) using a 3rd party imaging toolkit or GDI and insert back the image in the PDF file (using XFINIUM.PDF). XFINIUM.PDF does not include image editing capabilities.

  10. Reply Bohdan Sep 2,2016 12:59 pm

    Okay, thnx for the quick reply.

    And is it possible to draw lines using mouse not hardcoded coordinates?

    • Reply xfinium.pdf Sep 2,2016 1:08 pm

      It is possible, but you have to implement this in your application. You have to display the extracted image and implement the drawing functionality on the image. When the user saves the changes you insert back in the PDF the modified image.

  11. Reply Bohdan Sep 21,2016 10:25 am

    Hi. Can you please tell the difference in next 2 methods:

    RedactArea(new PdfVisualRectangle(left,top,width,height)) – here area with written coordinates will be edited

    RedactArea(new PdfVisualRectangle()) – what will be done in this way?

    Thanks in advance

    • Reply xfinium.pdf Sep 21,2016 11:00 am

      First line will redact the specified area while the second line will have no effect because the area to be redacted has 0 size. The default PdfVisualRectangle constructor creates a rectangle with left = top = width = height = 0.

  12. Reply Bohdan Sep 26,2016 6:13 am

    Hi. Is it possible to do undo action after the rectangle is drawn? I mean this:

    page.Graphics.DrawRectangle(brush, x, y, w, h);

    after this what need I do to remove that drawn rectangle?

    Thanks in advance

  13. Reply Bohdan Oct 7,2016 1:49 pm

    Hi. I’m having troubles during a saving process. Problem that the size is growing too fast. Here is what I’m doing:

    PdfFile = await StorageLocalCacheFolder.GetFileAsync("test.pdf");
    var pdfStream = await PdfFile.OpenAsync(FileAccessMode.ReadWrite);
    MemoryStream memoryStream = new MemoryStream();
    using (Stream stm = pdfStream.AsStream())
    {
    await stm.CopyToAsync(memoryStream);

    document.Save(stm);
    await stm.FlushAsync();
    }

    Above my comment, on 9th of February you suggested this approach of doing Save action.

    So, how to do it correctly, to fix that growing size?

    P.S. if I will do “Discard Private Data of other applications” on the saved document its size become much smaller. So maybe during a Save() method such data is adding to a document?

    • Reply xfinium.pdf Oct 10,2016 7:22 am

      XFINIUM.PDF does not add any additional data to the PDF file. Can you send us a sample PDF file that its size you consider to be too large? Also you copy the test.pdf to a memory stream. This causes the stream pointer to move to the end of the stream so when you save the PDF document you actually add it at the end of the existing file and this increases the file size. I suggest to comment this line “await stm.CopyToAsync(memoryStream);” and also generate a unique file name for the output file.
      Repeated saves on the same file can create invalid files if the new file is smaller than the initial one. The operation above does not truncate the input file, it just writes in it so you could end up with the new file and garbage content at its end.

      • Reply Bohdan Oct 10,2016 8:36 am

        Hi. Where I can send you that test PDF which I think it’s too large?

        And one more question. For example, I have multiple pages in my document. Can I detect on which I’m currently in and draw exactly on the 2nd page (for example)?

        Thanks in advance

        • Reply xfinium.pdf Oct 10,2016 8:48 am

          Our support email address is here: http://xfiniumpdf.com/xfinium-pdf-contact-us.html
          The document has the Pages property which is the collection of pages in the PDF file. You can select the desired page by index (0 is first page, 1 is send page etc) and draw on it.

          • Reply Bohdan Oct 10,2016 8:56 am

            I’ve just sent a letter with attached file.

            Yes, I saw that property. But is it a way to know current page, not setting it by index? For example smth like such property:

            PdfFixedDocument.CurrentSelectedPage – this would be great 🙂

          • Reply xfinium.pdf Oct 10,2016 9:10 am

            The file you sent contains 76 PDF files in it.
            This happens because you always append the new file at the end of an existing file.
            You have to generate a unique file name when saving or first you have to truncate the input PDF file in which you want to save the new PDF document.
            The PdfFixedDocument does not have the concept of current page. You have all the pages at your disposal and you can draw on any of them in any order.

  14. Reply Bohdan Oct 17,2016 6:26 am

    Hello. Can you please tell what can be the reason of getting such error:

    “Root object is missing in Pdf file.”? And how to solve it?

    Thanks in advance

  15. Reply Mayank Jan 6,2017 11:44 am

    Hello,
    Where do PDF gets saved? Save method is accepting Stream object and not file path. Also, two solutions suggested in above comments one with StorageFolder and FilePicker are not available in .Net Core. Please suggest. Thanks.

    • Reply xfinium.pdf Jan 6,2017 12:16 pm

      With .NET Core you create a FileStream object and save the document to that stream. After the document is saved, you flush and close the stream. The .NET Core samples included in Cross Platform package show this functionality.

  16. Reply Bala Mar 24,2017 9:56 pm

    HI,

    I am trying to fill a Pdf form using xfinium, It has two pages of form and populated the value for the fields and trying to save the Document. It saves the first page with populated data and the second page saves with out populated data.

    Please let me know is there anything I missed or it is a BUG in Xfinium.

    I am using XFINIUM.PDF 6.5.0.

    Thanks

  17. Reply Pete M Sep 22,2017 8:14 pm

    Hi,

    Is there any way to add an image to the PDF once then draw it on multiple pages? The sort of thing I’m thinking of is a company logo that you might put at the top of every page in a PDF with many pages, so if you draw it separately on each page you will be adding the size of the image to the PDF file many times over. Some other libraries I have used let you add an image to the file as a resource then draw it from the resource so the image only gets stored once in the PDF, which keeps the size down.

    FYI, I am using version 6.9.0. Thanks in advance.

    • Reply xfinium.pdf Sep 23,2017 1:49 pm

      Yes, this is the default behavior. When you create a PdfImage object for your image and use that image object to draw it on multiple pages the actual image data will be embedded only once in the PDF file.

      • Reply Pete M Sep 24,2017 5:19 pm

        Thanks for the reply. I thought that might be the default behaviour as it would make sense, but when I had tested it the file size still went up if the same PdfImage was drawn multiple times. However, that was quite a small image and after your reply it struck me that it would be hard to tell how much of the increase was the image content itself possibly being repeated and how much was the inevitable instructions to draw it at each point, so I tried it with a larger image and the file is much smaller if you redraw the same PdfImage than it is if you create a new PdfImage each time from a source file, which confirms that as you said, it does only add the image content once if you reuse the same PdfImage!

        What I will still need to do is to keep a dictionary of PdfImage instances that were already drawn, as my use case is that image drawing on each page could include many different images, so my code will need to detect that an image file that was used before is being used again and therefore reuse the existing PdfImage to draw it rather than creating a new PdfImage again for the same file. That will be pretty simple to do.

        Many thanks for your help. FYI, I’m currently replacing another PDF library with yours, and it’s noticeable how much simpler many of the calls are to make with Xfinium, so the new routines in my application are often half the size with Xfinium that they were with the other library. There’s still some way to go yet, but so far I haven’t found anything Xfinium can’t do or that doesn’t work, and one thing you just couldn’t do with the other library that Xfinium can do (different border and fill transparency settings on a shape), which is obviously good!

  18. Reply Pete M Sep 25,2017 3:25 pm

    Hi,

    I have another question, this time regarding TrueType fonts. I can see from the examples how to add a TrueType font, but to do that it appears that you have to know what the font filename is, which my application won’t normally know. All it does know is the name of the font, as seen in for example System.Windows.Media.FontFamily.Source. After a lot of googling I can’t see any reliable way to to find the name of the font file when given only the name of the font, as it doesn’t seem to be available through .NET or the Windows API as far as I can see, and it’s not simple as there can be multiple font files for the same font with different characteristics (bold, italic, etc) and there doesn’t seem to be any way to tell which is which even if you knew it was one of those files (which my code won’t know anyway as it won’t have even the root of the filename).

    Starting from a font name, do you know of a way to find the font filename so I can open a stream to the file, or is there some other way to add a TrueType font to the PDF using Xfinium but supplying only the font name rather than the font filename?

    Many Thanks.

    • Reply xfinium.pdf Sep 25,2017 3:52 pm

      From the FontFamily you retrieve the list of available typefaces (regular, bold, italic, etc) using GetTypefaces() method. You select your desired typeface and call TryGetGlyphTypeface(GlyphTypeface) method to get a GlyphTypeface object. A GlyphTypeface is font face that directly corresponds to a font file on the disk. On the GlyphTypeface object you call the GetFontStream method to retrieve a Stream that contains the actual font file. You can build your PdfAnsiTrueTypeFont object from this stream.

      • Reply Pete M Sep 26,2017 2:03 am

        That’s great, thanks, I have implemented that approach and it does now work with all the TrueType fonts I’ve tried so far. There’s some more testing to do, and the vertical positioning of the text isn’t quite right yet but that’s probably a minor issue in my code somewhere which I’ll track down. Thanks again.

Leave a Reply