Rix is the official package layer for Vix.cpp Browse packages
Skip to content

Text

This example shows how to write headings, paragraphs, and aligned text with rix/pdf.

The example uses the public Rix facade:

cpp
#include <rix.hpp>

and accesses PDF through:

cpp
rix.pdf

Use this example when you want to create a PDF with styled text content.

Create the file

bash
mkdir -p ~/rix-pdf-text-example
cd ~/rix-pdf-text-example
touch text.cpp

Add:

cpp
#include <rix.hpp>

int main()
{
  auto doc = rix.pdf.document();

  doc.set_title("Rix PDF Text Example");
  doc.set_author("Rix");

  auto &page = doc.add_page();

  auto y = page.y_top();

  y = page.heading(
      page.x_left(),
      y,
      "Rix PDF",
      1);

  y -= 10.0F;

  y = page.paragraph(
      page.x_left(),
      y,
      page.content_width(),
      "Rix gives Vix C++ projects a unified userland facade. "
      "The PDF module keeps the public API simple while the writer internals stay hidden.");

  y -= 20.0F;

  page.paragraph(
      page.x_left(),
      y,
      page.content_width(),
      "This paragraph is centered to show text alignment.",
      rixlib::pdf::Align::Center,
      rixlib::pdf::TextStyle{
          rixlib::pdf::Font::Helvetica,
          12.0F,
          rixlib::pdf::Color::blue_color()});

  auto saved = rix.pdf.save(doc, "rix_pdf_text.pdf");

  if (saved.failed())
  {
    rix.debug.eprint(
        "pdf error:",
        rix.pdf.error.to_string(saved.error()),
        saved.error().message());

    return 1;
  }

  rix.debug.print("created:", "rix_pdf_text.pdf");
  return 0;
}

Run it:

bash
vix run text.cpp

If Rix is not available yet for single-file usage:

bash
vix install -g rix/rix
vix run text.cpp

This creates:

txt
rix_pdf_text.pdf

What this example does

The example creates a PDF document:

cpp
auto doc = rix.pdf.document();

It sets document metadata:

cpp
doc.set_title("Rix PDF Text Example");
doc.set_author("Rix");

It adds a page:

cpp
auto &page = doc.add_page();

It draws a heading:

cpp
auto y = page.heading(
    page.x_left(),
    page.y_top(),
    "Rix PDF",
    1);

It draws a wrapped paragraph:

cpp
y = page.paragraph(
    page.x_left(),
    y,
    page.content_width(),
    "Rix gives Vix C++ projects a unified userland facade.");

Then it saves the file:

cpp
auto saved = rix.pdf.save(doc, "rix_pdf_text.pdf");

Text coordinates

PDF coordinates are expressed in points.

One inch is 72 points.

The example uses page helpers instead of hardcoded positions:

cpp
page.x_left()
page.y_top()
page.content_width()

These helpers keep content inside the page margins.

Draw one line of text

Use:

cpp
page.text(
    page.x_left(),
    page.y_top(),
    "Hello from rix.pdf");

This draws one line at the given X and Y position.

Draw a heading

Use:

cpp
auto y = page.heading(
    page.x_left(),
    page.y_top(),
    "Rix PDF",
    1);

The last argument is the heading level.

Common levels are:

txt
1
2
3
4
5
6

heading returns the next Y position after the heading.

This makes it easy to continue below:

cpp
y -= 10.0F;

Draw a paragraph

Use:

cpp
auto y = page.paragraph(
    page.x_left(),
    page.y_top(),
    page.content_width(),
    "This paragraph will wrap inside the available content width.");

The arguments are:

txt
x position
starting y position
available width
text content

paragraph wraps text and returns the Y position after the paragraph.

Continue below a paragraph

Because paragraph returns the next Y position, you can continue drawing below it:

cpp
auto y = page.paragraph(
    page.x_left(),
    page.y_top(),
    page.content_width(),
    "First paragraph.");

y -= 20.0F;

page.paragraph(
    page.x_left(),
    y,
    page.content_width(),
    "Second paragraph.");

This is the normal pattern for multi-section text pages.

Align text

Use Align values:

cpp
rixlib::pdf::Align::Left
rixlib::pdf::Align::Center
rixlib::pdf::Align::Right
rixlib::pdf::Align::Justify

Example:

cpp
page.paragraph(
    page.x_left(),
    y,
    page.content_width(),
    "Centered text",
    rixlib::pdf::Align::Center);

Draw aligned text on one line

Use text_aligned:

cpp
page.text_aligned(
    page.x_left(),
    page.y_top(),
    page.content_width(),
    "Centered title",
    rixlib::pdf::Align::Center);

This is useful for titles, footers, and page labels.

Style text

Use TextStyle when you want to control font, size, color, and line height.

cpp
rixlib::pdf::TextStyle{
    rixlib::pdf::Font::Helvetica,
    12.0F,
    rixlib::pdf::Color::blue_color()}

Example:

cpp
page.paragraph(
    page.x_left(),
    y,
    page.content_width(),
    "Blue paragraph",
    rixlib::pdf::Align::Left,
    rixlib::pdf::TextStyle{
        rixlib::pdf::Font::Helvetica,
        12.0F,
        rixlib::pdf::Color::blue_color()});

Common text styles

Use the built-in factories:

cpp
rixlib::pdf::TextStyle::normal()
rixlib::pdf::TextStyle::heading()
rixlib::pdf::TextStyle::small()

Example:

cpp
page.text(
    page.x_left(),
    page.y_top(),
    "Small note",
    rixlib::pdf::TextStyle::small());

Fonts

Standard PDF fonts are available through rixlib::pdf::Font.

Examples:

cpp
rixlib::pdf::Font::Helvetica
rixlib::pdf::Font::HelveticaBold
rixlib::pdf::Font::Times
rixlib::pdf::Font::Courier

Use them in a text style:

cpp
auto style = rixlib::pdf::TextStyle{
    rixlib::pdf::Font::HelveticaBold,
    14.0F,
    rixlib::pdf::Color::black()};

Colors

Use built-in colors:

cpp
rixlib::pdf::Color::black()
rixlib::pdf::Color::gray()
rixlib::pdf::Color::blue_color()
rixlib::pdf::Color::red_color()
rixlib::pdf::Color::green_color()

Use a hex color:

cpp
auto color = rixlib::pdf::Color::from_hex(0x2C3E50);

Then:

cpp
auto style = rixlib::pdf::TextStyle{
    rixlib::pdf::Font::Helvetica,
    12.0F,
    color};

Complete text page example

cpp
#include <rix.hpp>

int main()
{
  auto doc = rix.pdf.document();

  doc.set_title("Text Page")
      .set_author("Rix");

  auto &page = doc.add_page();

  auto y = page.heading(
      page.x_left(),
      page.y_top(),
      "Text Page",
      1);

  y -= 12.0F;

  y = page.paragraph(
      page.x_left(),
      y,
      page.content_width(),
      "This is a wrapped paragraph. It uses the content width so text stays inside the page margins.");

  y -= 18.0F;

  page.text_aligned(
      page.x_left(),
      y,
      page.content_width(),
      "Centered line",
      rixlib::pdf::Align::Center,
      rixlib::pdf::TextStyle{
          rixlib::pdf::Font::HelveticaBold,
          14.0F,
          rixlib::pdf::Color::blue_color()});

  auto saved = rix.pdf.save(doc, "text-page.pdf");

  if (saved.failed())
  {
    rix.debug.eprint(
        "pdf error:",
        rix.pdf.error.to_string(saved.error()),
        saved.error().message());

    return 1;
  }

  rix.debug.print("created:", "text-page.pdf");
  return 0;
}

Run:

bash
vix run text.cpp

Add a page number

Use:

cpp
page.page_number(1);

With total pages:

cpp
page.page_number(1, 3);

Example:

cpp
page.page_number(
    1,
    1,
    page.y_bottom(),
    rixlib::pdf::TextStyle::small());

Create a simple text PDF with make_text

For the shortest workflow, use:

cpp
auto saved = rix.pdf.make_text(
    "hello.pdf",
    "This file was generated with rix.pdf.make_text.",
    "Rix PDF");

Complete example:

cpp
#include <rix.hpp>

int main()
{
  auto saved = rix.pdf.make_text(
      "hello.pdf",
      "This file was generated with rix.pdf.make_text.",
      "Rix PDF");

  if (saved.failed())
  {
    rix.debug.eprint(
        "pdf error:",
        rix.pdf.error.to_string(saved.error()),
        saved.error().message());

    return 1;
  }

  rix.debug.print("created:", "hello.pdf");
  return 0;
}

Use make_text for simple text-only PDFs.

Use document() when you need headings, multiple paragraphs, styling, tables, drawings, images, or metadata.

Save the document

Use:

cpp
auto saved = rix.pdf.save(doc, "text.pdf");

Check errors:

cpp
if (saved.failed())
{
  rix.debug.eprint(
      "pdf error:",
      rix.pdf.error.to_string(saved.error()),
      saved.error().message());

  return 1;
}

Write bytes instead of saving

Use:

cpp
auto bytes = rix.pdf.write(doc);

Example:

cpp
auto bytes = rix.pdf.write(doc);

if (bytes.failed())
{
  rix.debug.eprint(
      "pdf error:",
      rix.pdf.error.to_string(bytes.error()),
      bytes.error().message());

  return 1;
}

rix.debug.print("pdf bytes:", bytes.value().size());

Use write for HTTP responses or custom output handling.

Use save for direct file output.

Use in a Vix project

Create a project:

bash
vix new rix-pdf-text --app
cd rix-pdf-text

Add Rix:

bash
vix add rix/rix
vix install

Make sure vix.app contains:

txt
deps = [
  "rix/rix",
]

A minimal vix.app can look like this:

txt
name = "rix-pdf-text"
type = "executable"
standard = "c++20"
output_dir = "bin"

sources = [
  "src/main.cpp",
]

include_dirs = [
  "include",
  "src",
]

deps = [
  "rix/rix",
]

packages = [
  "vix",
]

links = [
  "vix::vix",
]

Put the example code in:

txt
src/main.cpp

Build and run:

bash
vix build
vix run

Single-file usage

For examples, tests, and quick experiments:

bash
vix run text.cpp

If needed:

bash
vix install -g rix/rix
vix run text.cpp

For project usage, prefer:

bash
vix add rix/rix
vix install

and keep the dependency in vix.app:

txt
deps = [
  "rix/rix",
]

Use only PDF with the facade

If you want the rix.* facade style but only want PDF mounted, define the feature macro before including rix.hpp:

cpp
#define RIX_ENABLE_PDF
#include <rix.hpp>

int main()
{
  auto doc = rix.pdf.document();

  auto &page = doc.add_page();

  page.text(
      page.x_left(),
      page.y_top(),
      "Hello from rix.pdf");

  auto saved = rix.pdf.save(doc, "text.pdf");

  return saved.ok() ? 0 : 1;
}

When at least one RIX_ENABLE_* macro is defined, only selected modules are mounted.

If you also want debug output:

cpp
#define RIX_ENABLE_PDF
#define RIX_ENABLE_DEBUG
#include <rix.hpp>

int main()
{
  auto doc = rix.pdf.document();

  auto &page = doc.add_page();

  page.text(
      page.x_left(),
      page.y_top(),
      "Hello from rix.pdf");

  auto saved = rix.pdf.save(doc, "text.pdf");

  if (saved.failed())
  {
    rix.debug.eprint(
        "pdf error:",
        rix.pdf.error.to_string(saved.error()),
        saved.error().message());

    return 1;
  }

  rix.debug.print("created:", "text.pdf");
  return 0;
}

Use the independent package

For independent usage, install:

bash
vix add rix/pdf
vix install

In vix.app:

txt
deps = [
  "rix/pdf",
]

Then include:

cpp
#include <rix/pdf.hpp>

Example:

cpp
#include <rix/pdf.hpp>

int main()
{
  auto pdf = rixlib::pdf::module();

  auto doc = pdf.document();

  auto &page = doc.add_page();

  auto y = page.heading(
      page.x_left(),
      page.y_top(),
      "Rix PDF",
      1);

  y -= 10.0F;

  page.paragraph(
      page.x_left(),
      y,
      page.content_width(),
      "Hello from rix/pdf.");

  auto saved = pdf.save(doc, "text.pdf");

  return saved.ok() ? 0 : 1;
}

The examples in this documentation prefer the public facade:

cpp
#include <rix.hpp>

and:

cpp
rix.pdf

Common mistakes

Forgetting to install Rix

If rix.hpp is not found, install Rix first.

For a project:

bash
vix add rix/rix
vix install

For single-file usage:

bash
vix install -g rix/rix

Putting Rix in packages

Wrong:

txt
packages = [
  "rix/rix",
]

Correct:

txt
deps = [
  "rix/rix",
]

deps is for Vix Registry packages.

packages is for CMake package discovery.

Forgetting that Y moves downward by subtraction

To draw lower on the page, subtract from Y:

cpp
y -= 20.0F;

Then draw:

cpp
page.text(
    page.x_left(),
    y,
    "Next line");

Expecting metadata to be visible

This sets document metadata:

cpp
doc.set_title("Rix PDF Text Example");

This draws visible text:

cpp
page.heading(
    page.x_left(),
    page.y_top(),
    "Rix PDF Text Example",
    1);

Use both when you want both metadata and visible content.

Calling value() before checking success

Wrong:

cpp
auto bytes = rix.pdf.write(doc);

rix.debug.print(bytes.value().size());

Correct:

cpp
auto bytes = rix.pdf.write(doc);

if (bytes.failed())
{
  return 1;
}

rix.debug.print(bytes.value().size());

Not checking save errors

Wrong:

cpp
rix.pdf.save(doc, "text.pdf");

Correct:

cpp
auto saved = rix.pdf.save(doc, "text.pdf");

if (saved.failed())
{
  rix.debug.eprint(
      "pdf error:",
      rix.pdf.error.to_string(saved.error()),
      saved.error().message());

  return 1;
}

What you should remember

Create a document:

cpp
auto doc = rix.pdf.document();

Add a page:

cpp
auto &page = doc.add_page();

Draw a heading:

cpp
auto y = page.heading(
    page.x_left(),
    page.y_top(),
    "Rix PDF",
    1);

Draw a paragraph:

cpp
y = page.paragraph(
    page.x_left(),
    y,
    page.content_width(),
    "Text content.");

Save:

cpp
auto saved = rix.pdf.save(doc, "text.pdf");

Check errors:

cpp
if (saved.failed())
{
  rix.debug.eprint(
      "pdf error:",
      rix.pdf.error.to_string(saved.error()),
      saved.error().message());
}

For project usage:

bash
vix add rix/rix
vix install

and keep:

txt
deps = [
  "rix/rix",
]

Next step

Continue with PDF tables.

Next: Tables

Released under the MIT License.