Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Pdf To Markdown Parser Laravel Package

iamgerwin/php-pdf-to-markdown-parser

A PHP package that converts PDF files into clean Markdown, extracting text and structure for documentation, notes, and LLM workflows. Works with Laravel and standalone PHP projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer:

composer require iamgerwin/php-pdf-to-markdown-parser

Look at the README first for the exact entry-point class name (it has shifted across early releases — usually something like Iamgerwin\PdfToMarkdownParser\Parser or PdfToMarkdown) and the parse()/convert() method signature. The typical call looks like:

use Iamgerwin\PdfToMarkdownParser\Parser;

$parser = new Parser();
$markdown = $parser->parse(storage_path('app/docs/sample.pdf'));

Storage::put('docs/sample.md', $markdown);

The package is a thin wrapper around a pure-PHP PDF text extractor (the smalot/pdfparser ecosystem) with a heuristic layer that re-infers structure — headings from font size, lists from bullet glyphs, code from monospace fonts — into Markdown.

First use case to validate against: a vendor manual, README, or internal wiki export that you actually want converted. Drop it in, eyeball the output for heading levels and bullet nesting. If those two come out sane, the rest of the pipeline will usually work; if they don't, you're better off running smalot/pdfparser directly and doing your own structuring.

Implementation Patterns

Wrap it in a dedicated service, not inline. The parser is stateful-ish and the conversion is I/O heavy; hide it behind a small class so you can swap implementations later:

final class PdfMarkdownConverter
{
    public function __construct(private Parser $parser) {}

    public function convert(string $absolutePath): string
    {
        return $this->parser->parse($absolutePath);
    }
}

Queue big files. Conversion of anything above a few hundred KB can take seconds and eat memory. Dispatch a job:

class ConvertPdfToMarkdown implements ShouldQueue
{
    public function __construct(public string $path) {}

    public function handle(PdfMarkdownConverter $converter)
    {
        $md = $converter->convert(Storage::path($this->path));
        Storage::put(str_replace('.pdf', '.md', $this->path), $md);
    }
}

Bulk-convert with an Artisan command. Iterate a directory, skip already-converted files, log failures per file, and write .md alongside the source. This is the most common day-to-day shape — a one-off migration of a document dump to a docs repo or knowledge base.

Chain OCR before parsing when needed. For any PDF that looks scanned (or parses to near-empty output), pipe through ocrmypdf or pdftotext first, then feed the text-layer PDF into the parser. Do not try to bolt OCR into the parser itself.

Pair with a Markdown validator in your pipeline — league/commonmark round-trip or markdownlint in CI — because the heuristic output occasionally produces orphan headings or broken list nesting.

Gotchas and Tips

  • No OCR. Scanned/image-only PDFs return empty or garbage. Detect this early: if strlen($markdown) < 200 for a multi-page doc, route to OCR.
  • Heading levels are a guess. They're inferred from font size deltas, so two-column academic papers, resumes, and invoices will produce wrong or inconsistent #/## levels. Post-process if your corpus matters.
  • Tables are not really supported. The description lists headings, lists, and code blocks — tables are not on that list. Expect table content to come out as flattened lines. Split them out manually or with a separate tool.
  • Code blocks are font-based. Only reliable when the source actually used a monospace font and the extractor preserved that signal. Syntax highlighting won't survive; the fence language will be empty unless you add heuristics.
  • Multi-column layouts break reading order. Text is extracted roughly in the order the PDF content stream presents it, which is not always visual order. Test with real samples from your corpus before committing to the approach.
  • Memory. Large PDFs (100+ MB) will blow PHP's default memory_limit during extraction. Set memory_limit=-1 or raise it per job.
  • Encoding. Non-UTF-8 or font-subset PDFs (common in older Chinese, Arabic, or scanned-with-CID-font documents) can produce mojibake. Sanitize output with mb_convert_encoding(..., 'UTF-8', 'UTF-8') and check for replacement characters.
  • Project maturity. At 9 stars and 0 dependents, treat this as a small, single-maintainer package. Pin the version in composer.json, and if you depend on it long-term, vendor the class locally or fall back to smalot/pdfparser + your own structuring — the wrapper logic is not much code and you'll want control over the heuristics anyway.
  • Config quirks. If the package exposes options (e.g., ->withHeadings(), ->withCodeBlocks()), they're usually method-chained before parse(), not constructor args. Read the README's method list — the fluent API has changed between minor versions.
  • Extension point: if you need custom rules (e.g., detect callouts by a specific font, drop headers/footers by Y-coordinate), you'll likely need to subclass or bypass the package and work directly against smalot/pdfparser's Page/Text objects. The wrapper exposes few hooks for that.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource