Looking for the legacy python package?
PdfItDown is a Rust-based tool and library that converts text-based files, images, office documents, and markup files to PDF. It is built on top of markdown2pdf, office2pdf, and image crates to carry out fast, reliable conversions. Visit us on our documentation website!
PdfItDown is applicable to the following file formats:
- Markdown (
.md) - HTML (
.html,.htm) - PowerPoint (
.pptx) - Word (
.docx) - Excel (
.xlsx) - Text-based formats (
.txt,.csv,.xml,.json, and more) - Image files (
.png,.jpg,.jpeg,.webp,.tiff,.tif,.bmp,.svg) - PDF (pass-through)
PdfItDown works in a very simple way:
- From markdown / HTML to PDF
graph LR
2(Input File) --> 3[Markdown content]
3[Markdown content] --> 4[markdown2pdf]
4[markdown2pdf] --> 5(PDF file)
- From image to PDF
graph LR
2(Input File) --> 3[Bytes]
3[Bytes] --> 4[image crate]
4[image crate] --> 5(PDF file)
- From Office documents to PDF
graph LR
2(Input File) --> 3[office2pdf]
3[office2pdf] --> 4(PDF file)
- From other text-based file formats to PDF
graph LR
2(Input File) --> 3[Text content]
3[Text content] --> 4[markdown2pdf]
4[markdown2pdf] --> 5(PDF file)
PdfItDown is distributed as a Rust crate, a standalone CLI binary, and bindings for Python, TypeScript/Node.js, and WebAssembly.
# Install from crates.io
cargo install pdfitdown
# Or build from source
git clone https://github.com/AstraBert/PdfItDown.git
cd PdfItDown
cargo install --path crates/pdfitdownNote: The CLI requires the
clifeature (enabled by default). To install the library only without CLI support, usecargo install pdfitdown --no-default-features.
You can now use the command line tool:
Usage: pdfitdown [OPTIONS]
PdfItDown CLI: convert any file format to PDF
Options:
-i, --inputfile <INPUTFILE> Path to the input file(s) that need to be converted to PDF. Can be used multiple times.
-o, --outputfile <OUTPUTFILE> Path to the output PDF file(s). If more than one input file is provided, you should provide an equal number of output files.
-d, --directory <DIRECTORY> Directory whose files you want to bulk-convert to PDF. If `--inputfile` is also provided, this option will be ignored.
--no-overwrite Do not overwrite existing PDF files
--recursive Recursively go through a directory when converting files to PDFs
-h, --help Print help
-V, --version Print version
An example usage can be:
pdfitdown -i README.md -o README.pdfOr you can use it inside your Rust projects:
use pdfitdown::{PdfItDownConverter, types::Converter};
let converter = PdfItDownConverter::new();
let pdf_bytes = converter.convert("business_growth.md")?;
std::fs::write("business_growth.pdf", pdf_bytes)?;You can also convert multiple files at once:
- In the CLI:
# with custom output paths
pdfitdown -i test0.png -i test1.md -o testoutput0.pdf -o testoutput1.pdf- In the Rust API:
use pdfitdown::{PdfItDownConverter, types::Converter};
let converter = PdfItDownConverter::new();
converter.convert_multiple_files(
vec!["business_growth.md", "logo.png"],
vec!["business_growth.pdf", "logo.pdf"],
true, // overwrite
)?;You can bulk-convert all the files in a directory:
- In the CLI:
# non-recursive
pdfitdown -d tests/data/testdir
# recursive
pdfitdown -d tests/data/testdir --recursive- In the Rust API:
use pdfitdown::{PdfItDownConverter, types::Converter};
let converter = PdfItDownConverter::new();
converter.convert_directory("tests/data/testdir", true, true)?; // overwrite, recursivePython bindings are available via PyPI, built with PyO3:
uv add pdfitdownOr build from source with Maturin:
git clone https://github.com/AstraBert/PdfItDown.git
cd PdfItDown/crates/pdfitdown-python
maturin build --release
uv pip install target/wheels/pdfitdown-*.whlUsage:
from pdfitdown.pdfconversion import Converter
# Convert a single file
converter = Converter()
converter.convert("README.md", "README.pdf", overwrite=False)
# Convert multiple files
converter.multiple_convert(["business.md", "report.docx"])
# Bulk convert a directory
converter.convert_directory("docs/", overwrite=True, recursive=True)The Python package also installs a CLI entry point:
pdfitdown -i README.md -o README.pdfTypeScript/Node.js bindings are available on npm, built with NAPI-RS:
npm install @cle-does-things/pdfitdownPrebuilt binaries are available for macOS, Linux, and Windows (x86_64 and arm64).
Usage:
import { PdfItDownConverter } from '@cle-does-things/pdfitdown'
const converter = new PdfItDownConverter()
// Convert a single file
converter.convertFile('input.docx', 'output.pdf', true)
// Convert multiple files
converter.convertMultipleFiles(
['file1.docx', 'file2.pptx'],
['file1.pdf', 'file2.pdf'],
true,
)
// Convert a directory
converter.convertDirectory('./documents', true, true)
// Convert from memory (Buffer → Buffer)
import { readFileSync, writeFileSync } from 'fs'
const input = readFileSync('input.docx')
const output = converter.convertBytes(input)
writeFileSync('output.pdf', output)A WebAssembly build is published on npm as @cle-does-things/pdfitdown-wasm and can also be built from source:
# Install from npm
npm install @cle-does-things/pdfitdown-wasm
# Or build from source
cd PdfItDown/packages/wasm
npm run build # web target
npm run build:bundler # bundler target
npm run build:nodejs # Node.js targetUsage (via CDN in a browser):
<script type="module">
import init, { convert } from 'https://cdn.jsdelivr.net/npm/@cle-does-things/pdfitdown-wasm@4.0.0/pdfitdown_wasm.js';
await init('https://cdn.jsdelivr.net/npm/@cle-does-things/pdfitdown-wasm@4.0.0/pdfitdown_wasm_bg.wasm');
const fileInput = document.querySelector('input');
fileInput.addEventListener('change', async (e) => {
const bytes = new Uint8Array(await e.target.files[0].arrayBuffer());
const result = convert(bytes);
console.log('output bytes:', result);
});
</script>
<input type="file" />Usage (in a bundler or Deno/Bun):
import init, { convert, convertImage, convertMarkup, convertOffice, convertText } from '@cle-does-things/pdfitdown-wasm'
await init()
// Auto-detect format
const pdfBytes = convert(new Uint8Array(await file.arrayBuffer()))
// Or use specific converters
const imagePdf = convertImage(imageBytes)
const markupPdf = convertMarkup(markdownBytes)
const docxPdf = convertOffice(docxBytes)PdfItDown uses Cargo features to let you choose which converters to include:
| Feature | Description | Default |
|---|---|---|
cli |
Enables the command-line interface and clap dependency |
✅ |
image |
Enables image-to-PDF conversion (png, jpg, etc.) |
✅ |
office |
Enables Office document conversion (docx, xlsx, pptx) |
✅ |
markup |
Enables Markdown/HTML conversion and text-based formats | ✅ |
rayon |
Enables parallelized batch conversion | ❌ |
Examples:
# Library only, no CLI
[dependencies]
pdfitdown = { version = "4.0", default-features = false, features = ["markup", "image"] }
# All converters + parallelization
[dependencies]
pdfitdown = { version = "4.0", features = ["rayon"] }# Install CLI with all features
cargo install pdfitdown --features rayon
# Install library only (e.g. for WASM or embedded use)
cargo install pdfitdown --no-default-features --features markupLooking for the legacy Python package (v3, pure Python)? It is available on the v3 branch and on PyPI as pdfitdown<4.0. The current v4 Python bindings are a Rust-based rewrite and are the recommended way to use PdfItDown in Python.
This project is open-source and is provided under an MIT License.
