Use when turning a rendered pdfium-render PdfBitmap into a PNG or JPEG file, into an image crate DynamicImage, or into raw pixel bytes, and when the exported colors look wrong with red and blue swapped. Prevents the BGRA-versus-RGBA channel-swap bug and the removed as_bytes method, and prevents image-crate version mismatches. Covers as_image, as_rgba_bytes, as_raw_bytes, bytes_required_for_size, saving via DynamicImage with ImageFormat, and the image_025 feature coupling. Keywords: pdfium-render save PDF as PNG, export PDF page to JPEG, PdfBitmap as_image, as_rgba_bytes, as_raw_bytes, DynamicImage, image crate, ImageFormat, save_with_format, BGRA RGBA channel swap, red and blue swapped, colors wrong, image looks blue, as_bytes removed, how do I export a PDF page as an image
Use when turning a rendered pdfium-render PdfBitmap into a PNG or JPEG file, into an image crate DynamicImage, or into raw pixel bytes, and when the exported colors look wrong with red and blue swapped. Prevents the BGRA-versus-RGBA channel-swap bug and the removed as_bytes method, and prevents image-crate version mismatches. Covers as_image, as_rgba_bytes, as_raw_bytes, bytes_required_for_size, saving via DynamicImage with ImageFormat, and the image_025 feature coupling. Keywords: pdfium-render save PDF as PNG, export PDF page to JPEG, PdfBitmap as_image, as_rgba_bytes, as_raw_bytes, DynamicImage, image crate, ImageFormat, save_with_format, BGRA RGBA channel swap, red and blue swapped, colors wrong, image looks blue, as_bytes removed, how do I export a PDF page as an image
license
MIT
compatibility
Designed for Claude Code. Requires pdfium-render 0.8,0.9.
metadata
{"author":"OpenAEC-Foundation","version":"1.0"}
pdfium-impl-output-formats
Rendering a page produces a PdfBitmap. This skill turns that bitmap into a
deliverable: a PNG or JPEG file, an image crate DynamicImage, or raw pixel
bytes for a downstream pipeline. The one trap that dominates this area is byte
order: a PDFium bitmap is BGRA-family, the image crate expects RGBA, and
mixing them swaps red and blue.
Scope: bitmap-to-output conversion. For producing the PdfBitmap (the
PdfRenderConfig builder, render_with_config) see pdfium-syntax-rendering.
Quick Reference
The output API (0.9.x)
You want
Call
Returns
an image crate image
bitmap.as_image()
Result<DynamicImage, PdfiumError>
normalized RGBA8 bytes
bitmap.as_rgba_bytes()
Vec<u8>
native-order raw bytes
bitmap.as_raw_bytes()
Vec<u8>
pixel width / height
bitmap.width() / bitmap.height()
Pixels
the source pixel format
bitmap.format()
Result<PdfBitmapFormat, _>
buffer size for a size
PdfBitmap::bytes_required_for_size(w, h)
usize
The byte-order rule
A native PdfBitmap buffer is BGRA-ordered (PdfBitmapFormat::BGRA, BGRx,
BGR, or Gray). The image crate expects RGBA / RGB order.
ALWAYS use as_image() to get a DynamicImage: it performs the correct
channel conversion internally.
ALWAYS use as_rgba_bytes() when you need raw bytes for the image crate
or any RGBA consumer: it normalizes to RGBA8 regardless of source format.
NEVER feed as_raw_bytes() output to an RGBA consumer: those bytes are in
the bitmap's native BGRA order, so red and blue come out swapped (issue #50).
Use as_raw_bytes() only when the consumer expects the exact native format
reported by bitmap.format().
Core rules
NEVER call as_bytes(): it was removed in 0.9.0. Use as_raw_bytes() or
as_rgba_bytes().
ALWAYS keep the pdfium-renderimage_* feature matched to the image
crate version in Cargo.toml, or as_image() returns a DynamicImage your
code cannot use.
ALWAYS convert to RGB with into_rgb8() before saving JPEG: JPEG has no
alpha channel.
Decision Trees
Which accessor do I use?
What does the consumer expect?
An image file (PNG / JPEG) -> as_image(), then save (see Patterns)
An image crate DynamicImage -> as_image()
Raw RGBA8 bytes (web canvas, GPU,
another RGBA library) -> as_rgba_bytes()
Raw bytes in the exact native
PDFium format -> as_raw_bytes() + check format()
Which file format do I save?
Does the output need transparency or lossless pixels?
YES -> PNG. save_with_format(path, ImageFormat::Png). Alpha is preserved.
NO, it is a photo-like page and size matters
-> JPEG. into_rgb8() first (drops alpha), then
save_with_format(path, ImageFormat::Jpeg).
Patterns
These examples assume bitmap is a PdfBitmap from
page.render_with_config(&config)? (see pdfium-syntax-rendering). Functions
return Result<(), Box<dyn std::error::Error>> because saving mixes
PdfiumError and the image crate's ImageError.
Pattern 1: Save a page as PNG
use pdfium_render::prelude::*;
fnsave_png(bitmap: &PdfBitmap, path: &str)
->Result<(), Box<dyn std::error::Error>> {
// as_image() converts BGRA to the correct channel order.
bitmap.as_image()?.save_with_format(path, image::ImageFormat::Png)?;
Ok(())
}
as_image() returns a Result<DynamicImage, PdfiumError>. The ? propagates
the error; DynamicImage::save_with_format handles PNG encoding.
Pattern 2: Save a page as JPEG
use pdfium_render::prelude::*;
fnsave_jpeg(bitmap: &PdfBitmap, path: &str)
->Result<(), Box<dyn std::error::Error>> {
bitmap
.as_image()? // DynamicImage, correct color order
.into_rgb8() // drop the alpha channel: JPEG has none
.save_with_format(path, image::ImageFormat::Jpeg)?;
Ok(())
}
This is the canonical shape from the pdfium-render export.rs example.
into_rgb8() is required for JPEG; skipping it on an image with alpha is an
error.
Pattern 3: Raw RGBA bytes for a pipeline
use pdfium_render::prelude::*;
/// Hand pixels to a consumer that expects tightly packed RGBA8 rows.fnrgba_pixels(bitmap: &PdfBitmap) -> (Vec<u8>, Pixels, Pixels) {
// as_rgba_bytes() normalizes to RGBA8 regardless of the source format.letbytes = bitmap.as_rgba_bytes();
(bytes, bitmap.width(), bitmap.height())
}
For a web canvas, a GPU texture upload, or another RGBA library, this is the
correct accessor. NEVER substitute as_raw_bytes() here.
Pattern 4: Native bytes and buffer sizing
use pdfium_render::prelude::*;
fnnative_buffer(bitmap: &PdfBitmap)
->Result<(Vec<u8>, PdfBitmapFormat), PdfiumError> {
letformat = bitmap.format()?; // BGRA / BGRx / BGR / Grayletbytes = bitmap.as_raw_bytes(); // bytes in exactly that formatOk((bytes, format))
}
fnexpected_size(width: Pixels, height: Pixels) ->usize {
// The buffer length a bitmap of this size needs.
PdfBitmap::bytes_required_for_size(width, height)
}
Use as_raw_bytes() only when the consumer is told the exact
PdfBitmapFormat; otherwise the BGRA order will be misread.
Pattern 5: Match the image crate feature
Cargo.toml must keep the image crate version and the pdfium-renderimage_* feature in step:
[dependencies]pdfium-render = { version = "0.9", features = ["image_025"] }
image = "0.25"
image_025 pairs with image 0.25, image_024 with 0.24, image_023 with
0.23. image_latest tracks the newest. A mismatch makes as_image() return a
DynamicImage from a different image version than the one your code imports,
which is a distinct, incompatible type.
Version Notes: 0.8.x vs 0.9.x
PdfBitmap::as_bytes() was deprecated in 0.8.16 and REMOVED in 0.9.0.
Replace it with as_raw_bytes() (native order) or as_rgba_bytes()
(normalized RGBA8).
as_rgba_bytes() was added in 0.8.16. On older versions only as_raw_bytes
and the now-removed as_bytes existed.
The image_023 / image_024 / image_025 feature family was introduced in
0.8.26. Before that the image crate version was fixed by the crate.
0.9.2 changed PdfBitmap::empty() and from_bytes(): the bindings
argument was dropped, from_bytes() became safe, and an unsafefrom_bytes_unchecked() was added. On 0.9.1 and earlier from_bytes() is
unsafe and both take a bindings argument.
Anti-Patterns (summary)
Anti-pattern
Why it fails
Fix
as_raw_bytes() into an RGBA consumer
native bytes are BGRA: red and blue swap
as_rgba_bytes() or as_image()
as_bytes()
removed in 0.9.0
as_raw_bytes() / as_rgba_bytes()
saving an RGBA image as JPEG without into_rgb8()
JPEG has no alpha channel
into_rgb8() before save_with_format
image crate version not matching the image_* feature
as_image() yields an incompatible DynamicImage type
align Cargo.toml
Full failure transcripts and fixes are in references/anti-patterns.md.
Reference Files
references/methods.md: exact verified signatures for PdfBitmap,
PdfBitmapFormat, and the image crate methods used here.
references/examples.md: complete, verified Rust programs for PNG export,
JPEG export, raw-byte handoff, and feature configuration.
references/anti-patterns.md: each output failure with the cause and the
corrected code.
Related Skills
pdfium-syntax-rendering: producing the PdfBitmap with PdfRenderConfig
and render_with_config.
pdfium-errors-runtime: the PdfiumError variants, including the
byte-order bug class.
pdfium-core-coordinates: Pixels versus PdfPoints and rendered raster
dimensions.