Combine everything in a folder — images, PDFs and Word documents — into a single PDF.
Drop the tool into a folder and run it. It collects every file it recognises, including those in subfolders, sorts them alphabetically by path, and writes one combined.pdf in the same folder. Each source file gets a PDF bookmark named after it, so a 200-page result stays navigable.
| Input | Extensions | Result |
|---|---|---|
| Images | .png .jpg .jpeg .bmp .tif .tiff .gif .webp |
one page each, sized to the image at 300 DPI |
| PDFs | .pdf |
all their pages, at their original size and rotation |
| Word documents | .docx .doc |
as converted (see below) |
Everything else is ignored, along with entries whose name starts with . and the output file itself.
A standalone executable; no Python or any other runtime is needed on the machine where it runs.
| Dependency | Version | Purpose |
|---|---|---|
| Rust toolchain | 1.88+ (edition 2024) | build only |
| printpdf | 0.12 | PDF generation and image decoding |
| lopdf | 0.45 | merging existing PDFs |
| roxmltree | 0.21 | reading word/document.xml |
| zip | 8 | opening .docx archives |
All crates are fetched automatically by Cargo; you only need the Rust toolchain installed.
git clone https://github.com/alexprotom/everything_to_pdf
cd everything_to_pdf
cargo build --releaseThe finished binary is at target/release/everything_to_pdf.exe.
Copy everything_to_pdf.exe into the folder with your files and double-click it, or run it from a terminal in that folder. It prints each file as it is added, writes combined.pdf next to them, lists anything that needed attention, and waits for Enter before closing.
everything_to_pdf [OPTIONS] [FOLDER]
-o, --output <FILE> Write to <FILE> instead of combined.pdf
--flat Only this folder; do not descend into subfolders
-h, --help Show usage
A relative --output is written inside the folder being combined, so -o report.pdf lands next to the inputs.
Word's own format is far too large to reimplement, so the tool hands .docx and .doc files to a converter if one is installed, and falls back to reading the text itself if not. It reports which route it took before it starts.
- LibreOffice —
soffice --headless --convert-to pdf. Full layout, handles both.docxand legacy.doc. Tried first: it never opens a window or a dialog, and it runs against a private profile directory, so it will not disturb a LibreOffice session you already have open. Found automatically inC:\Program Files\LibreOffice\program\soffice.exe, the usual Linux and macOS locations, or anywhere onPATH. - Microsoft Word — driven through COM by a short PowerShell script, opening the document read-only. Same fidelity, Windows only, and used only when LibreOffice is absent.
- The built-in reader — a last resort, used when neither is installed. It pulls the text out of the
.docxitself: headings, paragraphs, list items and table rows, laid out as plain A4 pages in Helvetica. There is no styling, no images and no real table layout, and because the built-in PDF fonts are limited to the WinAnsi (CP1252) character set, anything outside Latin script — Cyrillic, Greek, CJK — is drawn as?. The tool says so per file and lists the characters it could not draw. Legacy.docfiles cannot be read this way at all and are skipped with a message.
If you regularly combine Word documents, install LibreOffice: the difference in output is large.
The code deliberately overrides printpdf's default save options. The library's PdfSaveOptions::default() caps every image at ~2 MB of raw pixel data, downscaling anything larger than roughly 950×700 px with nearest-neighbour resampling before re-encoding at JPEG quality 0.85, which visibly degrades photos and scans. This tool saves with no size cap and JPEG quality 0.95, so images keep their original resolution. For fully lossless (but much larger) output, see the comment in src/image_page.rs about ImageCompression::Flate.
Pages are copied across as they are: no scaling to a common paper size, no re-encoding of their content. Attributes a page inherits from its parent node in the source document — page size, rotation, resources — are written onto the page before the source's page tree is discarded, so pages do not silently lose their size or their fonts. PDFs that are readable but restricted (an owner password only) are opened; ones that need a password to read are reported and skipped.
A file that cannot be read never aborts the run: it is reported and the rest are combined.
| File | Contains |
|---|---|
src/main.rs |
options, the run, and what is printed |
src/scan.rs |
finding the input files and putting them in order |
src/image_page.rs |
one image → a one-page PDF |
src/word.rs |
converter detection, LibreOffice, Word, fallback |
src/docx.rs |
pulling the text out of a .docx |
src/text_page.rs |
laying that text out as PDF pages |
src/winansi.rs |
WinAnsi coverage and Helvetica metrics |
src/merge.rs |
concatenating PDFs, with bookmarks |
cargo test # unit tests for each of the above
cargo clippy --all-targetsMIT © 2026 Alexander Pryanichnikov