Quickstart

Create your first PDF document in a few lines of C code.

Prerequisites

Install Vanilla.PDF using one of the methods in the installation guide. The simplest option:

vcpkg install vanillapdf

Create a PDF document

The following example creates a PDF document with a single blank page and writes it to disk.

#include <stdio.h>
#include <vanillapdf/c_vanillapdf_api.h>

int main(void) {
    DocumentHandle* document = NULL;
    CatalogHandle* catalog = NULL;
    PageTreeHandle* page_tree = NULL;
    PageObjectHandle* page = NULL;
    error_type rc;

    /* Create a new document bound to an output path */
    rc = Document_Create("output.pdf", &document);
    if (rc != VANILLAPDF_ERROR_SUCCESS) { return 1; }

    /* Navigate to the page tree via the root catalog */
    rc = Document_GetCatalog(document, &catalog);
    if (rc != VANILLAPDF_ERROR_SUCCESS) { goto cleanup; }

    rc = Catalog_GetPages(catalog, &page_tree);
    if (rc != VANILLAPDF_ERROR_SUCCESS) { goto cleanup; }

    /* Create a blank page and append it */
    rc = PageObject_CreateFromDocument(document, &page);
    if (rc != VANILLAPDF_ERROR_SUCCESS) { goto cleanup; }

    rc = PageTree_AppendPage(page_tree, page);
    if (rc != VANILLAPDF_ERROR_SUCCESS) { goto cleanup; }

    /* Write to disk */
    rc = Document_Save(document, "output.pdf");
    if (rc != VANILLAPDF_ERROR_SUCCESS) { goto cleanup; }

    printf("Created output.pdf successfully.\n");

cleanup:
    if (page)      PageObject_Release(page);
    if (page_tree) PageTree_Release(page_tree);
    if (catalog)   Catalog_Release(catalog);
    if (document)  Document_Release(document);

    return (rc == VANILLAPDF_ERROR_SUCCESS) ? 0 : 1;
}

Key patterns to notice:

  • Single header<vanillapdf/c_vanillapdf_api.h> includes the entire C API.

  • Handle-based – Every object is an opaque pointer (DocumentHandle*, CatalogHandle*, etc.). The internal C++ implementation is never exposed.

  • Error codes – Every function returns error_type. Check against VANILLAPDF_ERROR_SUCCESS.

  • Manual cleanup – Each handle obtained from the library must be released. Initialize to NULL and release in reverse order.

Build and run

Create a CMakeLists.txt:

cmake_minimum_required(VERSION 3.20)
project(QuickStart C)

find_package(vanillapdf CONFIG REQUIRED)

add_executable(quickstart main.c)
target_link_libraries(quickstart PRIVATE vanillapdf::vanillapdf)

Build:

cmake -S . -B build
cmake --build build
./build/quickstart    # creates output.pdf

Sign the document

Use the CLI tool to add a digital signature:

vanillapdf-tools sign -s output.pdf -d signed.pdf -k private_key.p12 -p password

Verify it:

vanillapdf-tools verify -f signed.pdf

Query library version

error_type process_library_info() {

    // Misc
    string_type library_author = NULL;

    // Version info
    integer_type library_version_major = 0;
    integer_type library_version_minor = 0;
    integer_type library_version_patch = 0;
    integer_type library_version_build = 0;

    // Build time information
    integer_type library_build_day = 0;
    integer_type library_build_month = 0;
    integer_type library_build_year = 0;

    RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetVersionMajor(&library_version_major));
    RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetVersionMinor(&library_version_minor));
    RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetVersionPatch(&library_version_patch));
    RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetVersionBuild(&library_version_build));
    RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetAuthor(&library_author));

    RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetBuildDay(&library_build_day));
    RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetBuildMonth(&library_build_month));
    RETURN_ERROR_IF_NOT_SUCCESS(LibraryInfo_GetBuildYear(&library_build_year));

    print_text("Library vanillapdf %d.%d.%d.%d by %s\n",
        library_version_major,
        library_version_minor,
        library_version_patch,
        library_version_build,
        library_author
    );

    print_text("Built on %d.%d.%d\n",
        library_build_day,
        library_build_month,
        library_build_year
    );

    return VANILLAPDF_TEST_ERROR_SUCCESS;
}

Retrieve error details

When a function returns an error code, extract the message:

error_type print_last_error() {
    error_type error = 0;
    char* error_message = NULL;
    char* error_code_name = NULL;
    size_type error_code_name_length = 0;
    size_type error_message_length = 0;

    RETURN_ERROR_IF_NOT_SUCCESS(Errors_GetLastError(&error));

    // Last error message
    RETURN_ERROR_IF_NOT_SUCCESS(Errors_GetLastErrorMessageLength(&error_message_length));

    if (error_message_length >= SIZE_MAX) {
        unsigned long long length_converted = error_message_length;
        printf("Buffer size is too big: %llu bytes\n", length_converted);
        return VANILLAPDF_TEST_ERROR_FAILURE;
    }

    error_message = (char*) calloc(error_message_length, sizeof(char));
    if (NULL == error_message) {
        unsigned long long length_converted = error_message_length;
        printf("Could not allocate memory: %llu bytes\n", length_converted);
        return VANILLAPDF_TEST_ERROR_FAILURE;
    }

    RETURN_ERROR_IF_NOT_SUCCESS(Errors_GetLastErrorMessage(error_message, error_message_length));

    // error code name
    RETURN_ERROR_IF_NOT_SUCCESS(Errors_GetPrintableErrorTextLength(error, &error_code_name_length));

    if (error_code_name_length >= SIZE_MAX) {
        unsigned long long length_converted = error_code_name_length;
        printf("Buffer size is too big: %llu bytes\n", length_converted);
        return VANILLAPDF_TEST_ERROR_FAILURE;
    }

    error_code_name = (char*) calloc(error_code_name_length, sizeof(char));
    if (NULL == error_code_name) {
        unsigned long long length_converted = error_code_name_length;
        printf("Could not allocate memory: %llu bytes\n", length_converted);
        return VANILLAPDF_TEST_ERROR_FAILURE;
    }

    RETURN_ERROR_IF_NOT_SUCCESS(Errors_GetPrintableErrorText(error, error_code_name, error_code_name_length));

    if (error_message_length == 0) {
        printf("Error %u (%s)\n", error, error_code_name);
    } else {
        printf("Error %u (%s): %s\n", error, error_code_name, error_message);
    }

    free(error_message);
    free(error_code_name);

    return VANILLAPDF_TEST_ERROR_SUCCESS;
}

Next steps

  • C API Guide – Handle system, memory management, error handling, debugging

  • Examples – Signing, merging, encryption, content stream processing

  • Signature Verification Guide – Verify digital signatures with trust stores

  • CLI Tools – All CLI commands: sign, verify, merge, extract, encrypt, decrypt

  • PDF Format Guide – Understand PDF syntax: objects, XRef tables, trailers