# Pdfium Syntax Rendering

> Use when rendering a PDF page to a raster image with pdfium-render: building a PdfRenderConfig, calling render_with_config or the lower-level render, sizing the output, controlling rotation, or turning a PdfBitmap into an image crate DynamicImage or a raw byte buffer. Prevents the top rendering mistakes: reaching for the PdfBitmapConfig and PdfPage::get_bitmap names that were removed in 0.9.0, and reading as_raw_bytes as if it were RGBA when PDFium bitmaps are stored in BGRA order, which swaps the red and blue channels. Covers PdfRenderConfig, render_with_config, render, PdfBitmap, PdfBitmapFormat, PdfPageRenderRotation, byte order, and the 0.8.x to 0.9.x upgrade traps. Keywords: pdfium-render rendering, PdfRenderConfig, render_with_config, render, PdfBitmap, as_image, as_rgba_bytes, as_raw_bytes, PdfBitmapFormat, BGRA, RGBA, set_reverse_byte_order, PdfPageRenderRotation, PdfBitmapConfig removed, get_bitmap removed, page to image, render PDF page to PNG, blank rendered image, colors look wrong, red and blue s

- Skill: `impertio-studio/pdfium-syntax-rendering` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add impertio-studio/pdfium-syntax-rendering`
- Raw SKILL.md: https://api.skillmd.com/api/skills/impertio-studio/pdfium-syntax-rendering/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- License: MIT
- Author: Impertio-Studio (https://skillmd.com/u/impertio-studio)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/impertio-studio/pdfium-syntax-rendering

---


# pdfium-syntax-rendering

## What this skill covers

Rendering turns a `PdfPage` into a raster image. The pipeline is fixed:

```
PdfPage
  -> render_with_config(&PdfRenderConfig)   (or render(width, height, rotation))
  -> PdfBitmap
  -> as_image()        -> image::DynamicImage
     as_rgba_bytes()   -> Vec<u8>  (RGBA, normalized)
     as_raw_bytes()    -> Vec<u8>  (native PDFium byte order)
```

This skill covers the `PdfRenderConfig` builder, both render entry points,
`PdfBitmap` output, pixel format and byte order, and the 0.8.x to 0.9.x traps.
For writing the result to PNG / JPEG / WebP files see
`pdfium-impl-output-formats`. For `PdfPoints` vs `Pixels` see
`pdfium-core-coordinates`. Default API surface here is 0.9.x.

## Quick reference

| Step | Call | Returns |
|------|------|---------|
| Configure | `PdfRenderConfig::new().set_target_width(2000)...` | `PdfRenderConfig` |
| Render (config) | `page.render_with_config(&config)` | `Result<PdfBitmap, PdfiumError>` |
| Render (direct) | `page.render(w, h, rotation)` | `Result<PdfBitmap, PdfiumError>` |
| To image crate | `bitmap.as_image()` | `Result<DynamicImage, PdfiumError>` |
| To RGBA bytes | `bitmap.as_rgba_bytes()` | `Vec<u8>` |
| To native bytes | `bitmap.as_raw_bytes()` | `Vec<u8>` |

`PdfRenderConfig` is a **consuming builder**: every setter takes `self` and
returns `Self`. ALWAYS chain the calls or rebind the result. NEVER call a
setter and discard its return value.

## Choosing a render entry point

```
Need rotation, form rendering, a specific format, or sizing rules?
  YES -> render_with_config(&PdfRenderConfig)   (the normal choice)
  NO, just a plain pixel size  -> render(width, height, rotation)
```

ALWAYS prefer `render_with_config`. The `render(width, height, rotation)`
function is the lower-level path for a one-off plain raster with no other
options.

## Building a PdfRenderConfig

`PdfRenderConfig::new()` starts an empty builder. Apply setters by chaining:

```rust
use pdfium_render::prelude::*;

let config = PdfRenderConfig::new()
    .set_target_width(2000)
    .set_maximum_height(2000)
    .rotate_if_landscape(PdfPageRenderRotation::Degrees90, true);
```

### Sizing setters

| Setter | Effect |
|--------|--------|
| `set_target_width(Pixels)` / `set_target_height(Pixels)` | scale the page toward this dimension, aspect ratio preserved |
| `set_maximum_width(Pixels)` / `set_maximum_height(Pixels)` | cap a dimension; the page is scaled down to stay within it |
| `set_fixed_width(Pixels)` / `set_fixed_height(Pixels)` / `set_fixed_size(Pixels, Pixels)` | force an exact pixel dimension (added 0.8.37) |
| `scale_page_by_factor(f32)` | scale relative to the page's natural size |

`Pixels` is the integer pixel-dimension type alias, so plain integer literals
work. ALWAYS set at least one sizing rule. A config with no sizing renders at
the page's natural pixel size.

### Rotation setters

`rotate`, `rotate_if_landscape`, and `rotate_if_portrait` each take a
`PdfPageRenderRotation` and a `bool`. The `PdfPageRenderRotation` variants are
`None`, `Degrees90`, `Degrees180`, `Degrees270`. The `bool` controls whether
the sizing constraints rotate along with the page.

### Other setters

| Setter | Effect |
|--------|--------|
| `render_form_data(bool)` | render interactive form field appearances |
| `set_format(PdfBitmapFormat)` | choose the backing pixel format |
| `set_reverse_byte_order(bool)` | swap the channel order at render time |
| `use_print_quality(bool)` | render at print quality instead of screen quality |
| `highlight_text_form_fields(PdfColor)` | tint text form fields |

ALWAYS call `render_form_data(true)` when the PDF has interactive form fields
that must appear in the output. Without it, filled fields render blank.

## PdfBitmap output

`render_with_config` and `render` both return a `PdfBitmap`. The bitmap borrows
its page: it cannot outlive the `PdfPage` it came from.

| Method | Returns | Use |
|--------|---------|-----|
| `width()` / `height()` | `Pixels` | output dimensions |
| `format()` | `Result<PdfBitmapFormat, PdfiumError>` | the backing pixel format |
| `as_image()` | `Result<DynamicImage, PdfiumError>` | hand off to the `image` crate |
| `as_rgba_bytes()` | `Vec<u8>` | RGBA bytes, normalized from any source format |
| `as_raw_bytes()` | `Vec<u8>` | the raw backing buffer in its native order |

## Pixel format and byte order

`PdfBitmapFormat` has four variants: `Gray`, `BGR`, `BGRx`, `BGRA`. PDFium
stores rendered pixels in a **BGR-family** order. There is NO RGBA variant: a
PDFium bitmap is never natively RGBA.

This matters because most Rust image tooling expects RGBA:

- `as_image()` produces a correct `image::DynamicImage`. ALWAYS use it when the
  target is the `image` crate.
- `as_rgba_bytes()` returns RGBA bytes regardless of the source `PdfBitmapFormat`.
  ALWAYS use it when you need a raw RGBA buffer.
- `as_raw_bytes()` returns the buffer in its native order (BGRA by default).
  NEVER treat the result of `as_raw_bytes()` as RGBA: the red and blue channels
  are swapped. This is the cause of the reversed-color bug (issue #50).

If a downstream consumer truly needs RGBA from the raw buffer, call
`set_reverse_byte_order(true)` on the config so PDFium emits RGBA-order pixels
directly. See `references/anti-patterns.md`.

## Version traps: 0.8.x to 0.9.x

The 0.9.0 cleanup release removed the entire old rendering API. This is the
most common upgrade break in the crate.

| Removed name (deprecated 0.7.12 to 0.8.16) | 0.9.x replacement |
|--------------------------------------------|-------------------|
| `PdfBitmapConfig` | `PdfRenderConfig` |
| `PdfPage::get_bitmap()` / `get_bitmap_with_config()` | `render()` / `render_with_config()` |
| `PdfBitmap::as_bytes()` | `as_raw_bytes()` / `as_rgba_bytes()` |
| `PdfBitmapRotation` enum | `PdfPageRenderRotation` |

NEVER write `PdfBitmapConfig` or `get_bitmap` for a 0.9.x target: these names
do not exist and the compile fails.

0.9.2 also changed the `PdfBitmap` constructors: `empty()` and `from_bytes()`
dropped their `bindings` argument, `from_bytes()` became safe, and a new
`unsafe from_bytes_unchecked()` was added. On 0.9.0 and 0.9.1, `empty()` and
`from_bytes()` still take a `bindings: &dyn PdfiumLibraryBindings` argument and
`from_bytes()` is `unsafe`. See `references/methods.md`.

## Common failures (quick triage)

| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| compile error: `PdfBitmapConfig` not found | removed 0.8.x name | use `PdfRenderConfig` |
| compile error: `get_bitmap` not found | removed 0.8.x name | use `render_with_config` |
| red and blue swapped in output | `as_raw_bytes()` read as RGBA | use `as_rgba_bytes()` or `as_image()` |
| config setter has no effect | return value of a consuming setter discarded | chain the setters |
| form fields render blank | `render_form_data` not enabled | add `.render_form_data(true)` |
| slow rendering of many pages | a fresh `PdfRenderConfig` per page | build the config once, reuse it |

## Reference files

- `references/methods.md`: complete signatures for `PdfRenderConfig`,
  `PdfBitmap`, the render functions, and the format and rotation enums, with
  version annotations.
- `references/examples.md`: verified rendering code, from a single page to a
  full document export.
- `references/anti-patterns.md`: real rendering failures, why each fails, and
  the fix.

## Companion skills

- `pdfium-impl-output-formats`: writing the rendered bitmap to PNG, JPEG, WebP.
- `pdfium-core-coordinates`: `PdfPoints` vs `Pixels`, page geometry.
- `pdfium-syntax-pages`: obtaining the `PdfPage` to render.
- `pdfium-errors-runtime`: handling render-time `PdfiumError` values.

