Convert a color PDF to greyscale in Rust

Remap all color space operations in a PDF to DeviceGray to produce a greyscale-only file.

rust
use pdfluent::{Document, color::GreyscaleOptions};

fn main() -> pdfluent::Result<()> {
    let mut doc = Document::open("input.pdf")?;

    doc.convert_to_greyscale(GreyscaleOptions::default())?;
    doc.save("greyscale.pdf")?;
    Ok(())
}
Install:cargo add pdfluentDownload SDK →

Step by step

1

Open the source PDF

Load the color PDF into a mutable Document.

rust
let mut doc = Document::open("color_input.pdf")?;
2

Configure greyscale options

GreyscaleOptions controls the luminance formula and whether images are converted in place.

rust
use pdfluent::color::GreyscaleOptions;

let opts = GreyscaleOptions::default()
    .convert_images(true)       // downsample color images to greyscale
    .luminance_formula(pdfluent::color::LuminanceFormula::Bt709); // standard TV luminance
3

Run the color conversion

convert_to_greyscale rewrites all color operators (rg, RG, k, K, cs, CS) and converts embedded images to /DeviceGray.

rust
doc.convert_to_greyscale(opts)?;
4

Verify no color resources remain

Inspect the color spaces in the output to confirm conversion.

rust
for page in doc.pages() {
    for cs in page.color_spaces() {
        println!("page color space: {:?}", cs);
    }
}
5

Save the greyscale output

Write the converted document. File size typically decreases because image data is smaller without color channels.

rust
doc.save("greyscale.pdf")?;

Notes and tips

  • The BT.709 luminance formula (0.2126R + 0.7152G + 0.0722B) matches standard display rendering. Use BT.601 for legacy compatibility.
  • CMYK colors are first converted to RGB via a linear approximation before applying the luminance formula. For precise CMYK greyscale use an ICC-based path.
  • Spot colors (Separation and DeviceN) are not converted by default. Pass convert_spot_colors(true) to remap them.
  • Converting images to greyscale resamples the color channel; the resolution and compression of the image is preserved.

Why PDFluent for this

Pure Rust

No JVM, no runtime, no DLL dependencies. Ships as a single native binary or WASM module.

Memory safe

Rust's ownership model prevents buffer overflows and use-after-free. No segfaults in PDF parsing.

Runs anywhere

Same code runs server-side, in Docker, on AWS Lambda, on Cloudflare Workers, or in the browser via WASM.

Frequently asked questions