Convert DOCX, Excel, PowerPoint, images, HTML, and Markdown to PDF in Laravel. One package, 20+ formats, no cloud API, no microservice. Works with Docker, Google Cloud Run, and Azure.
Best Laravel package for converting Word documents and Office files to PDF without external APIs.
Author: Mohit Anand | Contact: admin@veoksha.com | mohitanand540@gmail.com
use Veoksha\LaravelUniversalConverter\Converter;
$pdfPath = Converter::toPdf('path/to/document.docx');Install with composer require veoksha/pdfit. The package auto-installs Python tooling via uv—no manual setup. Everything runs on your server; no SaaS, no API keys.
Laravel/PHP is weak at document conversion. Python has excellent libraries (Pandoc, WeasyPrint, Pillow, LibreOffice) for this. Pdfit bridges them:
- You write Laravel code
- Pdfit runs Python via uv (auto-installed)
- The result is a PDF
Everything runs locally. Supports Azure, Google Cloud Run, Docker.
| Category | Formats | Engine |
|---|---|---|
| Office | docx, doc, pptx, ppt, xlsx, xls, odt, ods, odp | LibreOffice / pypandoc |
| Web & Text | html, htm, md, markdown, txt, rtf, csv | weasyprint / pypandoc |
| Images | png, jpg, jpeg, gif, bmp, tiff, tif, webp | Pillow |
| Other | epub, zip | pypandoc / ebooklib / merge |
A ZIP is treated as a bundle: the package extracts supported files inside, converts each to PDF, and merges them into one PDF. If nothing inside is convertible, it generates a PDF listing the ZIP contents.
| Pdfit | DOMPDF / Spatie | Doxswap | |
|---|---|---|---|
| DOCX → PDF | ✅ LibreOffice/pypandoc | ❌ HTML only | ✅ LibreOffice |
| Excel, PowerPoint | ✅ | ❌ | |
| Images → PDF | ✅ Pillow | ❌ | ❌ |
| HTML, Markdown | ✅ WeasyPrint | ✅ DOMPDF | ❌ |
| Python setup | Auto (uv) | N/A | N/A |
| Single API | Converter::toPdf() |
Varies | Yes |
Use Pdfit when you need to convert user uploads (Office, images, HTML) to PDF in one package, without cloud APIs.
| Requirement | Notes |
|---|---|
| PHP 8.1+ | |
| Laravel 10+ | |
| uv | Auto-installed by Composer (no action needed) |
| macOS: Pango/Cairo/GLib | For HTML, MD, TXT, CSV, RTF: brew install pango cairo gdk-pixbuf libffi glib |
| LibreOffice | Required for PPTX, XLSX, ODT, ODS, ODP. See Installation |
- requires:
php: ^8.1,illuminate/support: ^10.0|^11.0|^12.0,symfony/process: ^6.0|^7.0 - requires-dev: None
- suggests: None
- provides: None
- conflicts: None
- replaces: None
composer require veoksha/pdfitThis will:
- Install the package
- Attempt to install uv (a fast Python runner) if not present
- uv then manages Python and conversion libraries
Required for HTML, Markdown, TXT, CSV, RTF, EPUB, and ZIP conversion on macOS. WeasyPrint needs Pango, Cairo, and GLib.
brew install pango cairo gdk-pixbuf libffi glibThe package sets DYLD_LIBRARY_PATH automatically so Python can find these libraries. Without them, you may see:
Error: cannot load library 'libgobject-2.0-0'
Linux (Ubuntu/Debian):
sudo apt install libpango-1.0-0 libpangocairo-1.0-0 libcairo2 libgdk-pixbuf2.0-0 libffi-dev shared-mime-infoRequired only if you need to convert PPTX, XLSX, ODT, ODS, or ODP.
macOS:
brew install --cask libreoffice
echo 'export PATH="/Applications/LibreOffice.app/Contents/MacOS:$PATH"' >> ~/.zshrc
source ~/.zshrcUbuntu/Debian:
sudo apt install libreofficeDocker / Cloud: Use a custom image with LibreOffice and WeasyPrint deps; see Cloud & Server Deployment.
- Package (veoksha/pdfit): Provides PHP code +
convert.pyscript. No Python runtime included. - Your server/container: Must have
uv(Python runner) and system libs. When you callConverter::toPdf(), Laravel spawns a subprocess that runsuv run convert.py, so Python executes on your server.
exec() and proc_open must be enabled in PHP. Shared hosting that blocks these will not work.
Example Dockerfile for a Laravel app using pdfit:
FROM php:8.4-cli-bookworm
# System deps: LibreOffice + WeasyPrint (Pango/Cairo)
RUN apt-get update && apt-get install -y --no-install-recommends \
unzip libzip-dev curl libreoffice \
libpango-1.0-0 libpangocairo-1.0-0 libcairo2 libgdk-pixbuf2.0-0 libffi-dev shared-mime-info \
&& docker-php-ext-install zip pcntl \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Install uv (Python runner)
RUN curl -LsSf https://astral.sh/uv/install.sh | sh \
&& mv /root/.local/bin/uv /usr/local/bin/
# ... copy app, composer install, etc.Tested and working. Use the Docker approach above. Set CMD php artisan serve --host=0.0.0.0 --port=${PORT}. First conversion may take 60–90s while uv fetches Python and deps; later ones are faster.
| Environment | Works? | Notes |
|---|---|---|
| Azure VM | ✅ | Install uv, LibreOffice, and WeasyPrint deps via apt; add uv to PATH |
| Azure Container Apps / AKS | ✅ | Use a custom Docker image (same pattern as Cloud Run) |
| Azure App Service (Linux) | ✅ | Use a custom Docker image with the required packages |
| Restricted hosting | ❌ | If exec() is disabled or you cannot install system packages, pdfit will not run |
| Component | In package? | On server? |
|---|---|---|
PHP code, convert.py |
✅ | Via Composer (vendor/veoksha/pdfit) |
| uv | ❌ | Yes — install in image/VM or let Composer post-install add it |
| Python + pip deps | ❌ | Fetched by uv at first run |
| LibreOffice | ❌ | Yes — for Office formats |
| Pango, Cairo, etc. | ❌ | Yes — for HTML/MD/TXT/CSV/RTF |
use Veoksha\LaravelUniversalConverter\Converter;
// Convert any file to PDF (output: same directory, .pdf extension)
$pdfPath = Converter::toPdf('path/to/document.docx');
// Specify output path
Converter::toPdf('input.pptx', 'storage/app/output/report.pdf');use Veoksha\LaravelUniversalConverter\Converter;
class ExportController extends Controller
{
public function export(Converter $converter)
{
$pdf = $converter->toPdf(storage_path('uploads/report.xlsx'));
return response()->download($pdf);
}
}$pdfPaths = Converter::batch([
'file1.docx',
'file2.png',
'file3.html',
]);
// Returns: ['file1.pdf', 'file2.pdf', 'file3.pdf']use Illuminate\Support\Facades\Storage;
$inputPath = Storage::path('docs/report.docx');
$outputPath = storage_path('app/pdf/report.pdf');
Converter::toPdf($inputPath, $outputPath);
return Storage::download('pdf/report.pdf');Publish the config file:
php artisan vendor:publish --tag=converter-configconfig/converter.php:
| Option | Default | Description |
|---|---|---|
uv_path |
null |
Path to uv binary. null = auto-detect |
timeout |
120 |
Max seconds per conversion |
Environment variables:
CONVERTER_UV_PATH=/custom/path/to/uv
CONVERTER_TIMEOUT=180php artisan converter:checkChecks that uv and the Python script are available. Use this after deploy or when troubleshooting.
Laravel (PHP)
│
▼
Converter::toPdf($file)
│
▼
Symfony Process runs:
uv run convert.py input.pdf output.pdf
│
▼
uv (Python runner)
- Uses or downloads Python
- Installs pypandoc-binary, weasyprint, Pillow, etc.
- Runs the conversion script
│
▼
Python convert.py
- Detects file extension
- Chooses engine (weasyprint, pypandoc, Pillow, LibreOffice)
- Writes output PDF
│
▼
Process exits, PHP gets path to PDF
| Engine | Formats | System dependency |
|---|---|---|
| weasyprint | html, md, txt, csv | macOS: Homebrew; Linux: apt — see Installation |
| pypandoc | docx, rtf, epub | None (bundles Pandoc) |
| Pillow | png, jpg, gif, etc. | None |
| LibreOffice | pptx, xlsx, odt, ods, odp | Must be installed — see Installation |
- No prior Python install needed
- Installs Python and deps on demand
- Fast (Rust-based)
- Single
uv runcall; no virtualenv management
pdfit/
├── config/
│ └── converter.php
├── python/
│ └── convert.py # Conversion logic
├── scripts/
│ └── install-uv.php
├── src/
│ ├── ConversionException.php
│ ├── Converter.php
│ ├── ConverterServiceProvider.php
│ ├── Scripts.php
│ └── Console/
│ └── ConverterCheckCommand.php
├── tests/
│ ├── run_all.sh # Format tests
│ └── output/ # Generated PDFs
├── composer.json
└── README.md
Install manually:
curl -LsSf https://astral.sh/uv/install.sh | shEnsure ~/.local/bin is in your PATH.
Install LibreOffice and add it to PATH (see Installation).
Install WeasyPrint's system dependencies: brew install pango cairo gdk-pixbuf libffi glib. See Installation.
- Check
php artisan converter:check - Ensure
exec()is allowed (shared hosting may block it) - Increase
config/converter.phptimeout for large files
Most shared hosts restrict exec() and installing binaries. Use a VPS, cloud VM, or Docker for reliable conversions.
Yes. Use a Docker image with LibreOffice and WeasyPrint deps. Tested on Google Cloud Run. See Cloud & Server Deployment.
No. Pdfit runs locally on your server. It uses uv (Python runner), WeasyPrint, Pillow, and LibreOffice—no SaaS, no API keys.
Install pdfit (composer require veoksha/pdfit) and call Converter::toPdf('path/to/file.docx'). LibreOffice must be installed for Office formats.
Yes. Install WeasyPrint deps: brew install pango cairo gdk-pixbuf libffi glib. The package sets DYLD_LIBRARY_PATH automatically.
Office (DOCX, XLSX, PPTX, ODT), images (PNG, JPG, etc.), web (HTML, Markdown, TXT, CSV, RTF), EPUB, and ZIP (merged PDF).
Mohit Anand — Developer of Pdfit
Contact: admin@veoksha.com | mohitanand540@gmail.com
MIT