Back to Home

Paperdoc Library

A zero-dependency PHP library for generating, parsing, and converting documents — PDF, HTML, CSV, DOCX, XLSX, PPTX, Markdown and more. One API for create, read, and convert.

Features

  • Generate documents from scratch (PDF, HTML, CSV, DOCX, XLSX, PPTX, Markdown)
  • Parse existing files into a unified in-memory model
  • Convert between any supported format in one call
  • Rich document model — headings, nested lists, bookmarks, code blocks, blockquotes, images, tables, page breaks, footnotes, metadata
  • Page layout — per-section size and padding, backgrounds, multi-column flow, text zones, headers/footers. See Page layout.
  • Typography — vertical alignment, first-line indent, letter spacing, horizontal rules, per-section header/footer overrides. See Layout & typography.
  • Native rendering — block elements render cleanly to DOCX, PDF, HTML and Markdown
  • Hyperlinks — external URLs and internal anchors, round-tripped across formats
  • Typed exceptions — clear errors for parsers, renderers and unsupported formats
  • Batch processing — open and process multiple files at once
  • Thumbnails — preview images from documents; LibreOffice for Office/CSV, Imagick or Ghostscript for PDF
  • Laravel integration — ServiceProvider, Facade, and Artisan commands
  • OCR & LLM — Tesseract OCR and structured extraction via built-in HTTP providers
  • Core library: PHP + extensions only

Requirements

Paperdoc requires PHP 8.2+ and the following extensions (no external PHP packages):

Dependency Version
PHP ^8.2
ext-dom *
ext-mbstring *
ext-zip *
ext-zlib *

Optional (Laravel): illuminate/support ^11.0 or ^12.0 for the Facade and ServiceProvider.

Thumbnails — required system dependencies

For correct, high-quality thumbnails (fonts and layout):

  • LibreOffice is required for DOCX, XLSX, PPTX, and CSV (headless: libreoffice or soffice in PATH).
  • Imagick or Ghostscript is required for PDF thumbnails with correct rendering (otherwise a fallback text/image preview is used).

Without these, thumbnails fall back to native PHP previews (limited fonts, no real layout).

Installation

Install the package via Composer:

composer require paperdoc-dev/paperdoc-lib

Laravel auto-discovery

The PaperdocServiceProvider and Paperdoc facade are registered automatically. No manual registration needed.

Quick Start

Standalone PHP

Create a document, add content, and save to a file:

use Paperdoc\Support\DocumentManager;
use Paperdoc\Document\Style\TextStyle;

$doc = DocumentManager::create('pdf', 'My Report');

$doc->openSection()
    ->addParagraph('Hello, Paperdoc!', TextStyle::make()->setBold());

DocumentManager::save($doc, 'output/report.pdf');

Laravel (Facade)

Use the Paperdoc facade to create, parse, convert, or render:

use Paperdoc\Facades\Paperdoc;

// Create and save
$doc = Paperdoc::create('docx', 'Invoice #1042');
$doc->openSection()->addParagraph('Amount due: $500');
Paperdoc::save($doc, storage_path('invoices/1042.docx'));

// Parse an existing file
$doc = Paperdoc::open('uploads/report.xlsx');

// Convert directly (file to file)
Paperdoc::convert('report.docx', 'report.pdf', 'pdf');

// Render document to string (e.g. HTML)
$html = Paperdoc::renderAs($doc, 'html');

// Batch open multiple files
$docs = Paperdoc::openBatch([
    'file1.pdf',
    'file2.docx',
    'file3.xlsx',
]);

Supported Formats

Parse existing files or generate new ones for each format. Legacy Office formats (DOC, XLS, PPT) are parse-only.

Format Parse Render / Generate
PDF
HTML
DOCX
XLSX
PPTX
CSV
Markdown
DOC
XLS
PPT

Document Model

Every format uses the same strongly-typed in-memory structure, so you can parse a PDF and render to DOCX without format-specific code. Every renderer supports the full set of first-class block elements — no element is silently dropped (see Rendering).

Document (format, title, ?Metadata, metadata[])
└── Section[]
    ├── Heading (level 1-6, runs, ?id)
    ├── Paragraph (TextRun[], ?ParagraphStyle)
    │   └── TextRun (text, ?TextStyle, ?TextLink, ?Footnote)
    ├── ListBlock (bullet | ordered, start)
    │   └── ListItem (runs, blocks → nested ListBlock…)
    ├── Blockquote (nested DocumentElement[])
    ├── CodeBlock (code, ?language)
    ├── Bookmark (id) — link target for TextLink anchors
    ├── Table → TableRow[] → TableCell[]
    ├── Image (src | embedded data + mimeType)
    ├── HorizontalRule
    └── PageBreak

All block elements implement Paperdoc\Contracts\BlockElementInterface. Styles live in Document/Style/ (ParagraphStyle, TextStyle, TableStyle), links in Document/Link/TextLink, typed document properties in Document/Metadata.

Build a richly-typed document

use Paperdoc\Document\{Document, Heading, Metadata};
use Paperdoc\Document\Style\TextStyle;

$doc = Document::make('md', 'Release notes')
    ->setProperties(
        Metadata::make()
            ->setAuthor('Alice')
            ->setKeywords('release, changelog, paperdoc')
            ->setLanguage('en-US')
    );

$section = $doc->openSection();

$section->addElement(Heading::make('Getting started', 2, 'intro'));

$section->addBulletList()
    ->addText('Install the library')
    ->addText('Run the quick start')
    ->addText('Read the docs');

$section->addCodeBlock("composer require paperdoc-dev/paperdoc-lib", 'bash');

$section->addBookmark('ready-to-go');

$section->addBlockquote()
    ->addText('You are all set.', TextStyle::make()->setItalic());

Block elements at a glance

Element Purpose Section shortcut
HeadingTyped heading (level 1-6) with optional id for anchorsaddHeading() / addElement(Heading::make(…))
ListBlockOrdered or bullet list; nest another ListBlock inside a ListItem for sub-listsaddBulletList() / addOrderedList()
BlockquoteQuoted block that can contain any nested block elementaddBlockquote()
CodeBlockVerbatim source code with optional language hintaddCodeBlock($code, $language)
BookmarkNamed landmark; target for TextLink internal anchorsaddBookmark($id)
ImageFrom path or in-memory bytes; size auto-detected when omittedaddElement(Image::make(…))
TableRows of cells; cells accept any block elementaddElement(new Table())
PageBreakHard page breakaddPageBreak()
FootnoteNote on a TextRun — see FootnotesTextRun::make(…, Footnote::make(…))
MetadataTyped document properties (author, subject, keywords, dates, language)$doc->setProperties(Metadata::make())

Page layout, text zones, headers & footers

Each Section can declare its own page geometry via PageSetup, place TextZone blocks anywhere on the page, and use a document-level RunningElement for headers and footers. Combine sections with different setups to vary size and background per page.

Configure a page

use Paperdoc\Document\{Image, Section};
use Paperdoc\Document\Style\PageSetup;
use Paperdoc\Enum\PageSize;

$cover = Section::make('cover')->setPageSetup(
    PageSetup::fromSize(PageSize::A4)
        ->setPadding(0)                                // 1, 2, 3 or 4 values (CSS shorthand)
        ->setBackgroundImage(Image::make('cover.jpg')) // full-bleed image
);

$body = Section::make('body')->setPageSetup(
    PageSetup::fromSize(PageSize::A4, PageSetup::ORIENTATION_LANDSCAPE)
        ->setPadding(50)
        ->setBackgroundColor('#F8F5EC')                // solid color
);

$square = Section::make('back-cover')->setPageSetup(
    PageSetup::custom(500, 500)                        // any width × height in pt
        ->setBackgroundImage(Image::make('back.jpg'))
);

Section exposes shortcut setters (setPageSize(), setPageDimensions(), setPagePadding(), setPageBackgroundImage(), setPageBackgroundColor(), setColumnCount(), setColumnGap()) that delegate to a lazily-created PageSetup.

Setter / Factory Purpose
PageSetup::fromSize(PageSize, $orientation = 'portrait')Use a standard format (A3/A4/A5/A6/Letter/Legal/Tabloid/Executive)
PageSetup::custom($width, $height)Any dimensions in PDF points (1 pt = 1/72 inch)
landscape() / portrait()Flip the active orientation
setPadding(...) (1–4 values)CSS-style shorthand for top/right/bottom/left padding
setBackgroundColor($hex)Solid full-bleed background color
setBackgroundImage(Image)Full-bleed image — on-disk or Image::fromData()
setBackgroundSize(string)cover (default), contain, auto, stretch, or any CSS-valid string
setBackgroundPosition(string)Default 'center center'
setBackgroundRepeat(string)Default 'no-repeat'
setColumnCount(int) / setColumnGap(float)Multi-column body layout (gap in points)

Multi-column layout

Text flows down each column, then onto the next page. Tables and full-width images still use the full content width. Supported in PDF, HTML and DOCX.

$section->setPageSetup(
    PageSetup::fromSize(PageSize::A4)
        ->setColumnCount(2)
        ->setColumnGap(18.0)
);

// Or:
$section->setColumnCount(3)->setColumnGap(12.0);

Background image fit

PDF and HTML share the same modes. cover and auto clip overflow.

use Paperdoc\Document\Style\PageSetup;

$page->setPageSetup(
    PageSetup::fromSize(PageSize::A4)
        ->setBackgroundImage(Image::make('hero.jpg'))
        ->setBackgroundSize(PageSetup::BG_SIZE_COVER)   // default
);
Constant CSS equivalent Behaviour
BG_SIZE_COVERcoverFills the page, preserves aspect ratio, overflow is clipped (default)
BG_SIZE_CONTAINcontainFits inside the page, preserves aspect ratio (may leave empty bands)
BG_SIZE_AUTOautoImage at its natural size, centred, clipped if larger than the page
BG_SIZE_STRETCH100% 100%Stretches to fill the page; aspect ratio is not preserved (legacy)

Any other CSS-valid string ('50% auto', '300pt 200pt', …) is accepted as-is in HTML output.

Place text precisely with TextZone

A TextZone places text in an absolutely-positioned rectangle. Coordinates use the top-left convention (x=0, y=0 is the top-left of the page) for both PDF and HTML — the PdfRenderer flips to PDF's bottom-left origin internally.

use Paperdoc\Document\TextZone;
use Paperdoc\Document\Style\{ParagraphStyle, TextStyle};
use Paperdoc\Enum\Alignment;

$cover->addTextZone(x: 40, y: 40, width: 515, height: 90)
    ->setBackgroundColor('#0B1437')
    ->setBorder('#FFFFFF', 0.8)
    ->setPadding(16)
    ->addText(
        'Paperdoc — Cover title',
        TextStyle::make()->setBold()->setFontSize(20)->setColor('#FFFFFF'),
        ParagraphStyle::make()->setAlignment(Alignment::LEFT),
    );

// Long lorem with the ellipsis strategy: text is truncated to fit
// exactly the visible height and the last visible line ends with "…".
$cover->addTextZone(x: 40, y: 160, width: 250, height: 260)
    ->setPadding(12)
    ->setBackgroundColor('#FFFFFF')
    ->setBorder('#1F2937', 0.5)
    ->setOverflow(TextZone::OVERFLOW_ELLIPSIS)
    ->addText($veryLongText,
        TextStyle::make()->setFontSize(10)->setColor('#111827'),
        ParagraphStyle::make()->setLineSpacing(1.25),
    );
Overflow strategy Behaviour
TextZone::OVERFLOW_CLIP(Default) Silently truncates content that doesn't fit
TextZone::OVERFLOW_ELLIPSISTruncates and ends the last visible line with (PDF: native; HTML: pseudo-element)
TextZone::OVERFLOW_VISIBLENo clipping — content may flow outside the box (parity with CSS)

Per-paragraph alignment

Each paragraph in a TextZone can use its own ParagraphStyle (centred title, justified body, right-aligned signature, …):

use Paperdoc\Enum\Alignment;

$zone = $page->addTextZone(40, 80, 515, 380)
    ->setBackgroundColor('#FFFFFF')
    ->setOverflow(TextZone::OVERFLOW_ELLIPSIS);

$zone->addText('Quarterly report',
    TextStyle::make()->setBold()->setFontSize(18),
    ParagraphStyle::make()->setAlignment(Alignment::CENTER));

$zone->addText($longLorem,
    TextStyle::make()->setFontSize(11),
    ParagraphStyle::make()->setAlignment(Alignment::JUSTIFY)->setLineSpacing(1.3));

$zone->addText('— J. Doe',
    TextStyle::make()->setItalic(),
    ParagraphStyle::make()->setAlignment(Alignment::RIGHT));

In the PDF, justification is implemented with the native PDF word-spacing operator (Tw); the last line of a paragraph is intentionally left-aligned to avoid stretched short lines.

Document-wide headers and footers

use Paperdoc\Document\Style\{RunningElement, TextStyle};
use Paperdoc\Enum\Alignment;
use Paperdoc\Support\DocumentManager;

$doc = DocumentManager::create('pdf', 'Quarterly report');

$doc->setHeader(
    RunningElement::make('{title}')
        ->setAlignment(Alignment::LEFT)
        ->setStyle(TextStyle::make()->setFontSize(9)->setItalic()->setColor('#FFFFFF'))
);

$doc->setFooter(
    RunningElement::make('Page {page} / {pages}  ·  {date}')
        ->setAlignment(Alignment::CENTER)
        ->setStyle(TextStyle::make()->setFontSize(9)->setColor('#FFFFFF'))
);

Supported placeholders in the template: {page} (1-indexed current page), {pages} (total pages), {title} (the document title), {date} (Y-m-d) and {datetime} (Y-m-d H:i). The renderer resolves them per page so you don't need to update the template between pages.

Note. The HTML renderer adds a translucent rgba(255, 255, 255, 0.85) backdrop with a backdrop-filter: blur(2px) behind the running elements so they remain legible on top of any background image. The library does not automatically reserve vertical space for the header/footer — keep that in mind when positioning a TextZone close to a page edge.

Footnotes

Attach a Footnote to any TextRun. An inline marker [n] appears next to the text; the note body is placed according to the format.

use Paperdoc\Document\{Footnote, Paragraph, TextRun};

$paragraph = Paragraph::make();
$paragraph->addRun(TextRun::make(
    'See the specification',
    null,
    null,
    Footnote::make('ISO 32000-1:2008, §7.5'),
));
Format Where the note goes
PDFBottom of the page where the marker appears
HTMLOrdered list at the end of the section
MarkdownCommonMark definitions ([^n]: …) at section end
DOCXNotes block at the end of the document

Layout & typography

Extra layout helpers for headers, vertical placement, padding and typography. Existing documents keep the same output when these APIs are unused.

Per-section header / footer override

Hide or replace document-level headers and footers on specific sections (useful for covers and full-bleed pages):

use Paperdoc\Document\Style\RunningElement;

$doc->setFooter(RunningElement::make('Page {page} / {pages}'));

$cover = $doc->openSection('cover')->hideFooter();
$body  = $doc->openSection('body'); // inherits document footer
$end   = $doc->openSection('colophon')
    ->setFooter(RunningElement::make('— Fin —'));

hideHeader() / hideFooter() win; otherwise a section override is used; otherwise the document-level value is drawn.

Vertical alignment

Anchor section content to the top, centre or bottom (chapter openers, colophons):

use Paperdoc\Enum\VerticalAlignment;

$opener = $doc->openSection('chapter-1-opener')
    ->setPageSize(PageSize::A5)
    ->setVerticalAlignment(VerticalAlignment::CENTER);
$opener->addText('CHAPTER 1', TextStyle::make()->setFontSize(10)->setColor('#888'));
$opener->addText('The Signal', TextStyle::make()->setFontSize(28)->setBold());

$colophon = $doc->openSection('colophon')
    ->setVerticalAlignment(VerticalAlignment::BOTTOM);
$colophon->addText('© 2026 — All rights reserved.');

Supported in PDF and HTML. Multi-page sections fall back to top alignment.

First-line indent & letter-spacing

use Paperdoc\Document\Style\{ParagraphStyle, TextStyle};

$body = ParagraphStyle::make()
    ->setLineSpacing(1.4)
    ->setFirstLineIndent(18.0);

$paragraph->setStyle($body);

$eyebrow = TextStyle::make()
    ->setFontSize(10)->setBold()->setColor('#888')
    ->setLetterSpacing(2.0);

$paragraph->addRun(new TextRun('CHAPTER ONE', $eyebrow));

setFirstLineIndent() shifts only the first line (negative values hang). setLetterSpacing() is supported in PDF and HTML.

Horizontal rules

use Paperdoc\Enum\Alignment;

$section->addRule();
$section->addRule()
    ->setWidth('50%')
    ->setThickness(0.75)
    ->setColor('#aaaaaa')
    ->setAlignment(Alignment::CENTER)
    ->setMargins(8.0, 12.0);

Rendered in PDF, HTML, Markdown and DOCX.

Rendering

Every block element of the document model is rendered natively by all four built-in renderers. No element is silently dropped — what you build in PHP is what you get in DOCX, PDF, HTML and Markdown.

Element DOCX PDF HTML Markdown
Heading <w:pStyle w:val="Heading1..6"/> Sized 24/20/16/14/13/12pt <h1>…<h6> (with id) ####### (Pandoc {#id})
Paragraph <w:p> with styled runs Wrapped runs (font/size/color) <p> with styled spans **bold** / _italic_ / `code`
ListBlock (nested) <w:numPr> + numbering.xml Bullet / number markers, indented <ul> / <ol start="…"> - / 1. with indent
Blockquote Indented Quote w:pStyle Indented italic block <blockquote> > prefix per line
CodeBlock Code w:pStyle (monospaced) Monospaced block <pre><code class="language-…"> ```lang … ```
Bookmark <w:bookmarkStart/> + <w:bookmarkEnd/> (also on Heading id) Invisible target (link annotations planned) <a id="…" class="paperdoc-bookmark"> <a id="…"> (HTML fallback)
TextLink (hyperlinks) <w:hyperlink> + relationship (or anchor) Inline text only (PDF link annotations planned) <a href … target/rel for external> [text](url "title")
Image <w:drawing> + word/media/ part + relationship; auto-detected dimensions, capped to content width JPEG XObject (PNG/GIF/WebP re-encoded via GD) Bare <img src="data:…"> (no <figure> wrapper) — safe inside <td>/<li> ![alt](data:…) or ![alt](path)
Table (cells accept any block element) <w:tbl> with required <w:tblGrid>, per-cell <w:tcW> from Table::getColumnWidths() Drawn grid with cell padding; bold/italic/colour preserved when all cell runs share a style <table> / <tr> / <td> — every block dispatcher runs inside cells Pipe table (| … |) — multi-line cell content (lists, code, quotes) flattened to one line
PageBreak <w:br w:type="page"/> New PDF page <div class="page-break"> ---
Metadata docProps/core.xml + app.xml Author → PDF Creator

DOCX output is a complete OOXML package ([Content_Types].xml, _rels/, word/styles.xml, word/numbering.xml, word/_rels/document.xml.rels, embedded media). PDF is generated by a native zero-dependency engine (Paperdoc\Support\Pdf\PdfEngine) with built-in fonts and JPEG image XObjects.

Conversion & rendering

Convert a file to another format in one call, or render a document to a string (e.g. HTML or Markdown) without writing to disk.

File-to-file conversion

// Standalone
DocumentManager::convert('input.docx', 'output.pdf', 'pdf');

// Laravel
Paperdoc::convert('reports/data.xlsx', storage_path('reports/data.pdf'), 'pdf');

Render to string

Useful for web preview, APIs, or further processing:

$doc = Paperdoc::open('document.pdf');
$html = Paperdoc::renderAs($doc, 'html');
$markdown = Paperdoc::renderAs($doc, 'md');

Generate thumbnails

Paperdoc can generate thumbnails from documents or from any supported file. Thumbnails are computed on the fly (no file is written unless you do it yourself). For in-memory documents, the thumbnail reflects the first image in the document, or falls back to the first page of the source file if the document was opened from disk.

LibreOffice is required for DOCX, XLSX, PPTX, and CSV to get thumbnails with correct fonts and layout. For PDF, Imagick or Ghostscript is required for proper rendering. See Requirements.

From a document (in-memory)

Use getThumbnail() for raw binary data (width, height, mimeType, data) or getThumbnailDataUri() for a data:image/…;base64,… string suitable for <img src="…">:

$doc = Paperdoc::open('report.pdf');

// Array: ['data' => '…', 'mimeType' => 'image/jpeg', 'width' => 300, 'height' => 200]
$thumb = $doc->getThumbnail(300, 200, 85);
if ($thumb) {
    file_put_contents('preview.jpg', base64_decode($thumb['data']));
}

// Data URI — use directly in HTML
$dataUri = $doc->getThumbnailDataUri(300, 200);
// <img src="<?php echo $dataUri; ?>" alt="Preview">

Via DocumentManager or Facade

Same API without holding the document instance:

// Standalone
$thumb = DocumentManager::thumbnail($document, 300, 300, 85);
$dataUri = DocumentManager::thumbnailDataUri($document, 300, 300);

// Laravel
$dataUri = Paperdoc::thumbnailDataUri($doc, 200, 200);

From a file path (any format)

ThumbnailGenerator can create a thumbnail directly from a file. Images use GD; PDF uses Imagick or Ghostscript (required for correct rendering); Office and CSV use LibreOffice headless (required) → PDF → first page. Without LibreOffice/Imagick/Ghostscript, a fallback text or grid preview is used.

use Paperdoc\Support\ThumbnailGenerator;

// Array or data URI
$thumb = ThumbnailGenerator::fromFile('document.docx', 300, 300, 85);
$dataUri = ThumbnailGenerator::fromFileDataUri('report.pdf', 400, 300, 90, 0); // page 0 = first page

Defaults: ThumbnailGenerator::DEFAULT_WIDTH / DEFAULT_HEIGHT = 300, DEFAULT_QUALITY = 85. For PDF and Office files, the optional $page argument (0-based) selects which page to thumbnail.

Opening options (OCR, LLM)

When opening a file with open() or openBatch(), you can pass options to enable OCR and/or LLM augmentation:

// Force OCR on a scanned PDF
$doc = Paperdoc::open('scan.pdf', ['ocr' => true]);

// Skip OCR even if auto-detect would run it
$doc = Paperdoc::open('mixed.pdf', ['ocr' => false]);

// Enable LLM augmentation (summaries, structure, correction)
$doc = Paperdoc::open('scan.pdf', ['ocr' => true, 'llm' => true]);

// OCR language (e.g. 'fra', 'eng')
$doc = Paperdoc::open('document.pdf', ['language' => 'fra']);

Options: ocr (true / false / 'auto'), llm (bool), language (OCR language code). Defaults come from config/paperdoc.php.

OCR

Paperdoc uses Tesseract for text extraction from scanned documents and images. OCR can run automatically when opening a PDF (auto-detect) or be forced/skipped via open($path, ['ocr' => true|false]).

  • Post-processing — character substitution (0→O, rn→m), optional spell correction, n-gram correction, pattern recognition (dates, amounts), structure detection (headings, lists).
  • Parallel processing — multiple pages processed in parallel (pool size configurable).
  • Laravel Artisanpaperdoc:build-dictionary to build a spell-check dictionary; paperdoc:train-ngram to train an n-gram model for better correction.

Config: config/paperdoc.phpocr (enabled, driver, language, pool_size, tesseract binary) and ocr.post_processing.

LLM / AI

LLM augmentation improves OCR output and enables summaries, translations, and structured extraction. Paperdoc uses Neuron AI to connect to multiple providers.

  • LlmAugmenter — post-process OCR text (correction, structure).
  • PaperdocAgent — document Q&A, summaries, and structured data extraction.
  • Providers — OpenAI, Anthropic, Gemini, Ollama (and others supported by Neuron AI).

Enable via open($path, ['llm' => true]) or in config: llm.enabled, llm.provider, llm.model, llm.api_key (or PAPERDOC_LLM_* env vars).

Laravel

Use the Paperdoc facade for the same API as DocumentManager: Paperdoc::create(), Paperdoc::open(), Paperdoc::save(), Paperdoc::convert(), Paperdoc::renderAs(), Paperdoc::openBatch().

Artisan commands (when the package is installed in a Laravel app):

  • php artisan paperdoc:build-dictionary <path> — build a dictionary from text files for OCR spell correction.
  • php artisan paperdoc:train-ngram <path> — train an n-gram model from text files for OCR post-processing.

Configuration

Laravel only. Publish the config file:

php artisan vendor:publish --tag=paperdoc-config

This creates config/paperdoc.php. Main options:

  • Default format — default output when creating documents
  • Typography — fonts and sizes applied to documents
  • Storage paths — where to read/write files
  • OCR — Tesseract and post-processing settings
  • LLM — AI extraction and augmentation (Neuron AI)

Typed Exceptions

All library errors extend a single base (Paperdoc\Exceptions\PaperdocException) so consumers can catch them uniformly.

Exception Thrown when…
PaperdocExceptionBase class (extends RuntimeException)
ParserExceptionA parser cannot read or decode a file — use ParserException::forFile($path, $reason, $previous)
RendererExceptionA renderer cannot serialise a document — use RendererException::forFormat($fmt, $reason, $previous)
UnsupportedFormatExceptionUnknown format or extension — ::forFormat() / ::forExtension()
InvalidDocumentExceptionDocument is used in an invalid state (e.g. invalid heading level)
use Paperdoc\Exceptions\PaperdocException;

try {
    $doc = Paperdoc::open('report.docx');
} catch (PaperdocException $e) {
    // Any Paperdoc error ends up here.
}

API reference

Main entry point: DocumentManager (standalone) or Paperdoc facade (Laravel).

Method Description
create($format, $title = '')Create a new empty document (format: pdf, docx, html, csv, etc.).
open($filename, $options = [])Parse a file. Options: ocr, llm, language.
save($document, $path)Write document to a file.
renderAs($document, $format)Render document to string (e.g. 'html', 'md').
convert($source, $destination, $format)Open source file and save as destination in given format.
openBatch($filenames, $options = [])Open multiple files; returns array of documents. Same options as open().
thumbnail($document, $maxWidth, $maxHeight, $quality)Get thumbnail array (data, mimeType, width, height) for a document. See Thumbnails.
thumbnailDataUri($document, $maxWidth, $maxHeight, $quality)Get thumbnail as a data:image/…;base64,… string for <img src="…">.
thumbnailBase64($document, $maxWidth, $maxHeight, $quality)Get the raw base64-encoded thumbnail bytes (no data: prefix) — handy for JSON APIs.
registerRenderer($format, $rendererClass)Register a custom renderer class for a given format (must implement RendererInterface).
registerParser($parser)Register a custom ParserInterface instance — extend Paperdoc with new formats.

Architecture

High-level layout of the package source:

src/
├── Concerns/          # Shared traits
├── Console/           # Artisan commands
├── Contracts/         # DocumentInterface, ParserInterface, BlockElementInterface…
├── Document/          # Core model (Document, Section, Paragraph, Heading, ListBlock, Bookmark, CodeBlock, Blockquote, Metadata…)
├── Enum/              # Format enums
├── Exceptions/        # PaperdocException + typed exceptions
├── Facades/           # Laravel Facade
├── Factory/           # Document/Parser factories
├── Llm/               # AI/LLM integration (Neuron AI)
├── Ocr/               # OCR integration
├── Parsers/           # Format-specific parsers
├── Renderers/         # Format-specific renderers
├── Support/           # DocumentManager and helpers
└── PaperdocServiceProvider.php

Testing

Run the test suite from the library directory:

composer test
# or
./vendor/bin/phpunit

Integration tests are in tests/Integration/, unit tests in tests/Unit/.