Building documents

Of course, you need to generate a PDF document with your data. But often enough, you also want to encrypt the PDF file with passwords. And you usually want to add PDF metadata to the output file.

Keep reading to know how to instruct the generator to encrypt PDF files. How to specify document author and keywords.

This article is part of a series about Layout API for PDF generation. If you are new to the API, read the Getting Started with Layout API part first.

Building PDF documents

Create & Generate

The entry point of Layout API is the PdfDocumentBuilder class. You start by creating an instance of the class with the Create method. To generate a PDF, you call the Generate method of the class.

The Generate can save the output to a file or a stream. Either version of the method requires a delegate of the Action<Document> type as the second parameter. In the delegate, you describe the document you want to get. The library will generate a PDF based on the description.

Docotic.Pdf library 9.5.17615-dev Layout add-on 9.5.17615-dev
Regression tests 14,813 passed Total NuGet downloads 4,924,084

Encryption

To encrypt the output PDF, call the Encryption method before the Generate method.

You would need to create and provide an encryption handler. To encrypt PDF with passwords, use a handler of the PdfStandardEncryptionHandler type.

PdfDocumentBuilder.Create()
    .Encryption(new PdfStandardEncryptionHandler("owner", "user"))
    .Generate("encrypted-with-password.pdf", doc => doc.Pages(_ => { }));

You can also encrypt PDF with certificates. Check the Encrypt PDF documents article. It contains detailed information about encryption handlers and PDF permissions.

PDF Metadata

In some workflows, it is very important to specify proper PDF keywords and PDF author in the output PDF. Layout API provides an easy way for this. Call the Info method before the Generate method and provide the metadata values in the delegate.

PdfDocumentBuilder.Create()
    .Info(info =>
    {
        info.Author = $"{Environment.UserName}";
        info.Title = "Generate encrypted PDF with custom metadata";
        info.Keywords = "Metadata keywords encryption";
    })
    .Generate("metadata.pdf", doc => doc.Pages(_ => { }));

Options

For the same content, the library can create PDF files with different internal structure. These options will affect the output PDF.

Version

Use the Version method to set the minimum PDF format version for the output PDF.

PdfDocumentBuilder.Create()
    .Version(PdfVersion.Pdf17)
    .Generate("version.pdf", doc => doc.Pages(_ => { }));

Please note that the library can create a PDF with a larger version than specified. It happens when the document contents requires a newer version. To put it differently: when the document uses features not available in the specified version of the PDF standard.

Object streams

By default, the library uses objects streams in generated PDFs. This helps to produce smaller, better compressed files.

You can instruct the API to create PDF files without object streams using the ObjectStreams method.

PdfDocumentBuilder.Create()
    .ObjectStreams(false)
    .Generate("no-object-streams.pdf", doc => doc.Pages(_ => { }));

I suggest you keep using object streams unless there are some regulatory requirements. Or when some other parts of your workflow can not process documents with object streams.

Stream provider

The library uses streams as the intermediate storage. When generating a PDF, it does so for images and other large objects. The library gets streams through the stream provider. There is always one associated with the current PdfDocumentBuilder instance.

The library uses the PdfMixedStorageStreamProvider by default. This stream provider implementation provides streams that keep data in memory. These streams flush their contents to temporary files when there is too much data. This allows to reduce memory consumption and avoid LOH fragmentation.

You can use your own implementation of the IPdfStreamProvider interface when generating PDF files. One reason for the change might be a slow and/or expensive disk operations. Cloud environments might fit into this description.

This code shows how to generate PDF completely in memory, without temporary files. Please note that this will require a lot more memory than with the default options.

using (var memoryOnlyProvider = new PdfMemoryStreamProvider())
{
    PdfDocumentBuilder.Create()
        .StreamProvider(memoryOnlyProvider)
        .Generate("created-without-temp-files.pdf", doc => doc.Pages(_ => { }));
}

The library eventually calls the Dispose for every stream it gets through the stream provider. You must dispose of the stream provider instance yourselves.