PageSourceSearch

https://lightningpdf.dev/blog

html lightningpdf.dev collected 2026-10-02 06:26:59 UTC 43,177 bytes, 124 lines download raw bytes

1<!doctype html><html lang="en" class="h-full"><head><!-- TO THE GOD OF ABRAHAM, ISAAC AND JACOB. I DEDICATE THIS WORK TO YOU MAY YOU BLESS IT
2			AND MAY IT BLESS THOSE YOU USE IT, MORESO MAY THEY KNOW YOU BY NAME, REPENT AND BE LED TO YOUR WILL AND KINGDOM.
3			Our Father who is in the heavens, let Your Name be set-apart, let Your reign come,
4			let Your desire be done on earth as it is in heaven. Give us today our daily bread.
5			And forgive us our debts, as we forgive our debtors. And do not lead us into trial,
6			but deliver us from the wicked one because Yours is the reign and the power and the esteem, forever. Amen. --><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Blog - PDF Generation Tutorials &amp; Guides | LightningPDF</title><meta name="description" content="Tutorials, guides, and news about PDF generation, APIs, and document automation."><meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1"><meta name="googlebot" content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1"><!-- Open Graph --><meta property="og:title" content="Blog - PDF Generation Tutorials &amp; Guides | LightningPDF"><meta property="og:description" content="Tutorials, guides, and news about PDF generation, APIs, and document automation."><meta property="og:type" content="website"><meta property="og:site_name" content="LightningPDF"><meta property="og:url" content="https://lightningpdf.dev/blog"><link rel="canonical" href="https://lightningpdf.dev/blog"><meta property="og:image" content="https://lightningpdf.dev/static/images/og-default.png"><meta property="og:image:alt" content="LightningPDF - PDF Generation API"><meta property="og:image:width" content="1200"><meta property="og:image:height" content="630"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:site" content="@lightningpdf"><meta name="twitter:title" content="Blog - PDF Generation Tutorials &amp; Guides | LightningPDF"><meta name="twitter:description" content="Tutorials, guides, and news about PDF generation, APIs, and document automation."><meta name="twitter:image" content="https://lightningpdf.dev/static/images/og-default.png"><!-- Google Analytics -->
vendor: 63 bytes, line 6
6<script async src="https://www.googletagmanager.com/gtag/js?id=
6G-X4WHTYX9DF
vendor: 11 bytes, line 6
6"></script>
6<script>
7				
vendor: 139 bytes, lines 7-10
7window.dataLayer = window.dataLayer || [];
8				function gtag(){dataLayer.push(arguments);}
9				gtag('js', new Date());
10				gtag('config', '
10G-X4WHTYX9DF
vendor: 7 bytes, lines 10-11
10');
11			
11</script>
11<!-- Favicon --><link rel="icon" href="/favicon.svg" type="image/svg+xml"><link rel="icon" href="/favicon.ico" sizes="48x48"><!-- Compiled Tailwind CSS (includes custom theme + input.css) --><link rel="preload" href="/static/css/output.css" as="style"><style>[x-cloak]{display:none!important}</style><link rel="stylesheet" href="/static/css/output.css"><!-- Fonts served locally from /static/fonts/ (defined in input.css @font-face) --><!-- Alpine.js (local) - needed on all pages for nav/interactions -->
11<script defer src="/static/js/alpine-persist.min.js"></script>
11<script defer src="/static/js/alpine.min.js"></script>
11<!-- Monaco Code Editor - only on designer page (served locally for speed) --></head><body class="flex flex-col bg-document-50 min-h-full" hx-ext="response-targets,loading-states,preload"><nav class="bg-white/95 backdrop-blur-sm border-b border-document-200 sticky top-0 z-40" x-data="{ mobileOpen: false, userOpen: false, solutionsOpen: false }"><div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"><div class="flex items-center justify-between h-14 sm:h-16"><!-- Left: Logo + Nav links --><div class="flex items-center min-w-0"><a href="/" class="flex items-center gap-2 flex-shrink-0" aria-label="LightningPDF home"><div class="w-8 h-8 sm:w-9 sm:h-9 bg-gradient-to-br from-primary-500 to-primary-700 rounded-xl flex items-center justify-center shadow-sm"><svg class="w-4 h-4 sm:w-5 sm:h-5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"></path></svg></div><span class="hidden sm:inline text-lg font-bold text-document-800">Lightning<span class="text-primary-600">PDF</span></span></a><!-- Desktop nav --><div class="hidden lg:flex items-center ml-8 space-x-1"><!-- Solutions dropdown (logged-out only) --> <div class="relative" @click.away="solutionsOpen = false"><button @click="solutionsOpen = !solutionsOpen" class="inline-flex items-center gap-1.5 px-3 py-2 rounded-md text-sm font-medium transition-colors text-document-600 hover:text-document-900 hover:bg-document-100 inline-flex items-center gap-1" aria-haspopup="true" :aria-expanded="solutionsOpen ? 'true' : 'false'">Solutions <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg></button><div x-show="solutionsOpen" x-transition:enter="transition ease-out duration-100" x-transition:enter-start="transform opacity-0 scale-95" x-transition:enter-end="transform opacity-100 scale-100" x-transition:leave="transition ease-in duration-75" x-transition:leave-start="transform opacity-100 scale-100" x-transition:leave-end="transform opacity-0 scale-95" x-cloak class="absolute left-0 mt-1 w-72 rounded-lg border border-document-200 bg-white shadow-lg z-50 py-1"><a href="/saas-invoicing-pdf" class="block px-4 py-2.5 text-sm text-document-700 hover:bg-document-50 transition-colors"><div class="font-medium text-document-900">Shopify &amp; WooCommerce invoicing</div><div class="text-xs text-document-500 mt-0.5">Branded order PDFs for storefronts</div></a> <a href="/logistics-pdf-api" class="block px-4 py-2.5 text-sm text-document-700 hover:bg-document-50 transition-colors"><div class="font-medium text-document-900">Logistics &amp; fulfillment</div><div class="text-xs text-document-500 mt-0.5">Pick lists, BOLs, packing slips at warehouse speed</div></a> <a href="/healthcare-reporting-pdf" class="block px-4 py-2.5 text-sm text-document-700 hover:bg-document-50 transition-colors"><div class="font-medium text-document-900">Multilingual clinics</div><div class="text-xs text-document-500 mt-0.5">Patient invoices in every language they read</div></a></div></div><a href="/playground" class="inline-flex items-center gap-1.5 px-3 py-2 rounded-md text-sm font-medium transition-colors text-document-600 hover:text-document-900 hover:bg-document-100">Playground</a> <a href="/docs" class="inline-flex items-center gap-1.5 px-3 py-2 rounded-md text-sm font-medium transition-colors text-document-600 hover:text-document-900 hover:bg-document-100">Docs</a> <a href="/pricing" class="inline-flex items-center gap-1.5 px-3 py-2 rounded-md text-sm font-medium transition-colors text-document-600 hover:text-document-900 hover:bg-document-100">Pricing</a></div></div><!-- Right: Auth / User menu (desktop) --><div class="hidden lg:flex items-center gap-3 flex-shrink-0"><a href="/auth/login" class="text-sm font-medium text-document-600 hover:text-document-900 transition-colors">Sign in</a> <a href="/auth/register" class="pbolt-cta inline-flex items-center px-4 py-2 text-sm font-semibold text-white bg-primary-600 rounded-lg hover:bg-primary-700 transition-colors shadow-sm">Get Started Free</a></div><!-- Hamburger: visible below lg (phones + tablets) --><button @click="mobileOpen = !mobileOpen" class="lg:hidden p-2 rounded-md text-document-500 hover:text-document-900 hover:bg-document-100 transition-colors" aria-label="Toggle menu"><svg x-show="!mobileOpen" class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
11<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path></svg> <svg x-show="mobileOpen" x-cloak class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg></button></div></div><!-- Mobile/tablet menu: visible below lg --><div x-show="mobileOpen" x-transition x-cloak class="lg:hidden border-t border-document-200 bg-white max-h-[calc(100vh-3.5rem)] sm:max-h-[calc(100vh-4rem)] overflow-y-auto"><div class="px-4 py-3 space-y-1"><!-- Public links --><p class="px-3 pt-1 pb-2 text-xs font-semibold text-document-500 uppercase tracking-wider">Explore</p><a href="/playground" class="flex items-center gap-3 px-3 py-2.5 rounded-md text-sm font-medium transition-colors text-document-600 hover:text-document-900 hover:bg-document-100"><svg class="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg> Playground</a> <a href="/docs" class="flex items-center gap-3 px-3 py-2.5 rounded-md text-sm font-medium transition-colors text-document-600 hover:text-document-900 hover:bg-document-100"><svg class="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path></svg> Docs</a> <a href="/pricing" class="flex items-center gap-3 px-3 py-2.5 rounded-md text-sm font-medium transition-colors text-document-600 hover:text-document-900 hover:bg-document-100"><svg class="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path></svg> Pricing</a> <div class="border-t border-document-200 my-2"></div><p class="px-3 pt-1 pb-2 text-xs font-semibold text-document-500 uppercase tracking-wider">Solutions</p><a href="/saas-invoicing-pdf" class="flex items-center gap-3 px-3 py-2.5 rounded-md text-sm font-medium transition-colors text-document-600 hover:text-document-900 hover:bg-document-100"><svg class="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path></svg> Shopify &amp; Woo invoicing</a> <a href="/logistics-pdf-api" class="flex items-center gap-3 px-3 py-2.5 rounded-md text-sm font-medium transition-colors text-document-600 hover:text-document-900 hover:bg-document-100"><svg class="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17a2 2 0 11-4 0 2 2 0 014 0zM19 17a2 2 0 11-4 0 2 2 0 014 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16V6a1 1 0 00-1-1H4a1 1 0 00-1 1v10a1 1 0 001 1h1m8-1a1 1 0 01-1 1H9m4-1V8a1 1 0 011-1h2.586a1 1 0 01.707.293l3.414 3.414a1 1 0 01.293.707V16a1 1 0 01-1 1h-1m-6-1a1 1 0 001 1h1M5 17a2 2 0 104 0m-4 0a2 2 0 114 0m6 0a2 2 0 104 0m-4 0a2 2 0 114 0"></path></svg> Logistics &amp; fulfillment</a> <a href="/healthcare-reporting-pdf" class="flex items-center gap-3 px-3 py-2.5 rounded-md text-sm font-medium transition-colors text-document-600 hover:text-document-900 hover:bg-document-100"><svg class="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
11<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path></svg> Multilingual clinics</a> <!-- Account section --><div class="border-t border-document-200 my-2"></div><a href="/auth/login" class="flex items-center gap-3 px-3 py-2.5 rounded-md text-sm font-medium text-document-600 hover:text-document-900 hover:bg-document-100 transition-colors">Sign in</a> <a href="/auth/register" class="pbolt-cta block rounded-lg bg-primary-600 px-4 py-2.5 text-sm font-semibold text-white hover:bg-primary-700 transition-colors text-center mt-2">Get Started Free</a></div></div></nav><div x-data="{ dismissed: localStorage.getItem('shopify_launch_dismissed') === '1' }" x-show="!dismissed" x-cloak class="bg-nature-50 border-b border-nature-200"><div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-2"><div class="flex items-center justify-between gap-4"><div class="flex items-center gap-2 min-w-0 text-sm"><span class="hidden sm:inline-flex items-center text-[10px] font-mono uppercase tracking-widest bg-nature-100 text-nature-800 px-2 py-0.5 rounded">NEW</span> <span class="text-nature-800 truncate">Paperbolt is now live on the Shopify App Store</span> <a href="https://apps.shopify.com/paperbolt-pdf-invoices" target="_blank" rel="noopener noreferrer" class="inline-flex items-center gap-1 text-nature-700 hover:text-nature-900 font-semibold underline underline-offset-2 decoration-nature-300 hover:decoration-nature-600 transition-colors flex-shrink-0">Browse the listing <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path></svg></a></div><button @click="dismissed = true; localStorage.setItem('shopify_launch_dismissed', '1')" class="text-nature-500 hover:text-nature-700 p-1 flex-shrink-0" aria-label="Dismiss announcement"><svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg></button></div></div></div><main class="flex-grow">
11<script type="application/ld+json">{"@context":"https://schema.org","@type":"Blog","name":"LightningPDF Blog","description":"Tutorials, guides, and insights about PDF generation","url":"https://lightningpdf.dev/blog","publisher":{"@type":"Organization","name":"LightningPDF"}}</script>
vendor: 1 bytes, line 11
11
12<script type="application/ld+json">{"@context":"https://schema.org","@type":"ItemList","numberOfItems":9,"itemListElement":[{"@type":"ListItem","position":1,"url":"https://lightningpdf.dev/blog/lightningpdf-vs-lightpdf","name":"LightningPDF vs LightPDF: Two Different Products, One Confusing Letter"},{"@type":"ListItem","position":2,"url":"https://lightningpdf.dev/blog/indic-script-shaping-in-pdf","name":"Indic script shaping in PDF: why most PDF tools render Hindi as boxes"},{"@type":"ListItem","position":3,"url":"https://lightningpdf.dev/blog/why-two-engines","name":"Why our PDF API uses two engines"},{"@type":"ListItem","position":4,"url":"https://lightningpdf.dev/blog/validator-passing-peppol-bis-3","name":"Validator-passing Peppol BIS 3.0 without an enterprise SDK"},{"@type":"ListItem","position":5,"url":"https://lightningpdf.dev/blog/wordpress-7-pdf-plugin-compatibility","name":"WordPress 7.0 Is Here. Will Your PDF Invoice Plugin Survive It?"},{"@type":"ListItem","position":6,"url":"https://lightningpdf.dev/blog/extract-tables-from-pdf","name":"Extract Tables from PDFs: 5 Methods That Actually Work"},{"@type":"ListItem","position":7,"url":"https://lightningpdf.dev/blog/kreuzberg-vs-pymupdf-vs-pdfplumber","name":"Kreuzberg vs PyMuPDF vs pdfplumber: Which PDF Parser Should You Use?"},{"@type":"ListItem","position":8,"url":"https://lightningpdf.dev/blog/document-pipeline-python","name":"Build a Document Pipeline in Python: From Database to PDF"},{"@type":"ListItem","position":9,"url":"https://lightningpdf.dev/blog/pdf-to-json-extract-structured-data","name":"PDF to JSON: How to Extract Structured Data from PDFs"}]}</script>
12 <div class="min-h-screen bg-gradient-to-b from-document-50 to-white"><div class="max-w-4xl mx-auto px-4 py-16 sm:px-6 lg:px-8"><div class="text-center mb-12"><h1 class="text-4xl font-display text-primary-600 mb-4">Blog</h1><p class="text-xl text-document-600">Tutorials, guides, and insights about PDF generation</p></div><div class="space-y-8"><article class="bg-white rounded-2xl p-6 shadow-soft hover:shadow-float transition-all duration-300"><a href="/blog/lightningpdf-vs-lightpdf" class="block"><h2 class="text-xl font-semibold text-document-800 mb-2 hover:text-primary-600 transition-colors">LightningPDF vs LightPDF: Two Different Products, One Confusing Letter</h2><p class="text-document-600 text-sm mb-3">LightningPDF is a developer API for generating PDFs from HTML. LightPDF is an end-user PDF editor. Here is how to tell which one you are looking for.</p><div class="flex items-center gap-4 text-xs text-document-500"><span>By LightningPDF Team</span> <span>Aug 13, 2026</span> <span>2 min read</span></div></a> <div class="flex flex-wrap gap-1 mt-3"><a href="/blog/tag/&#34;pdf&#34;" aria-label="View posts tagged &#34;pdf&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;pdf&#34;</a><a href="/blog/tag/&#34;api&#34;" aria-label="View posts tagged &#34;api&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;api&#34;</a><a href="/blog/tag/&#34;comparison&#34;" aria-label="View posts tagged &#34;comparison&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;comparison&#34;</a></div></article><article class="bg-white rounded-2xl p-6 shadow-soft hover:shadow-float transition-all duration-300"><a href="/blog/indic-script-shaping-in-pdf" class="block"><h2 class="text-xl font-semibold text-document-800 mb-2 hover:text-primary-600 transition-colors">Indic script shaping in PDF: why most PDF tools render Hindi as boxes</h2><p class="text-document-600 text-sm mb-3">The reason Hindi, Bengali, Tamil, and other Indic scripts come out as tofu boxes in DOMPDF, mPDF, TCPDF, and most other PDF libraries is not a font problem. It is a text-shaping problem. Here is what the shaping does, why HarfBuzz exists, and what running Chromium gets you for free.</p><div class="flex items-center gap-4 text-xs text-document-500"><span>By LightningPDF</span> <span>Jun 4, 2026</span> <span>5 min read</span></div></a> <div class="flex flex-wrap gap-1 mt-3"><a href="/blog/tag/internationalization" aria-label="View posts tagged internationalization" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">internationalization</a><a href="/blog/tag/indic" aria-label="View posts tagged indic" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">indic</a><a href="/blog/tag/harfbuzz" aria-label="View posts tagged harfbuzz" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">harfbuzz</a><a href="/blog/tag/pdf" aria-label="View posts tagged pdf" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">pdf</a></div></article><article class="bg-white rounded-2xl p-6 shadow-soft hover:shadow-float transition-all duration-300"><a href="/blog/why-two-engines" class="block"><h2 class="text-xl font-semibold text-document-800 mb-2 hover:text-primary-600 transition-colors">Why our PDF API uses two engines</h2><p class="text-document-600 text-sm mb-3">A single-engine PDF API forces a trade-off between speed and capability. Splitting the engine into a Go-native fast path and a Chromium fallback removes the trade-off for the most common shapes. Here is how we route, what we measured, and what we got wrong.</p><div class="flex items-center gap-4 text-xs text-document-500"><span>By LightningPDF</span> <span>Jun 4, 2026</span> <span>5 min read</span></div></a> <div class="flex flex-wrap gap-1 mt-3"><a href="/blog/tag/architecture" aria-label="View posts tagged architecture" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">architecture</a><a href="/blog/tag/performance" aria-label="View posts tagged performance" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">performance</a><a href="/blog/tag/pdf" aria-label="View posts tagged pdf" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">pdf</a></div></article><article class="bg-white rounded-2xl p-6 shadow-soft hover:shadow-float transition-all duration-300"><a href="/blog/validator-passing-peppol-bis-3" class="block"><h2 class="text-xl font-semibold text-document-800 mb-2 hover:text-primary-600 transition-colors">Validator-passing Peppol BIS 3.0 without an enterprise SDK</h2><p class="text-document-600 text-sm mb-3">How we built a Peppol BIS Billing 3.0 emitter that passes the official Schematron in around 200 lines of Go. The schema is shorter than the integration guide. The integration guide is short.</p><div class="flex items-center gap-4 text-xs text-document-500"><span>By LightningPDF</span> <span>Jun 3, 2026</span> <span>4 min read</span></div></a> <div class="flex flex-wrap gap-1 mt-3"><a href="/blog/tag/e-invoicing" aria-label="View posts tagged e-invoicing" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">e-invoicing</a><a href="/blog/tag/peppol" aria-label="View posts tagged peppol" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">peppol</a><a href="/blog/tag/belgium" aria-label="View posts tagged belgium" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">belgium</a><a href="/blog/tag/ubl" aria-label="View posts tagged ubl" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">ubl</a><a href="/blog/tag/go" aria-label="View posts tagged go" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">go</a></div></article><article class="bg-white rounded-2xl p-6 shadow-soft hover:shadow-float transition-all duration-300"><a href="/blog/wordpress-7-pdf-plugin-compatibility" class="block"><h2 class="text-xl font-semibold text-document-800 mb-2 hover:text-primary-600 transition-colors">WordPress 7.0 Is Here. Will Your PDF Invoice Plugin Survive It?</h2><p class="text-document-600 text-sm mb-3">WordPress 7.0 dropped PHP 7.2/7.3, moved the editor into an iframe, and shipped a new admin theme. Here is what actually breaks invoice plugins, and why cloud-rendered PDFs do n
12ot care.</p><div class="flex items-center gap-4 text-xs text-document-500"><span>By LightningPDF Team</span> <span>May 21, 2026</span> <span>4 min read</span></div></a> <div class="flex flex-wrap gap-1 mt-3"><a href="/blog/tag/wordpress" aria-label="View posts tagged wordpress" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">wordpress</a><a href="/blog/tag/woocommerce" aria-label="View posts tagged woocommerce" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">woocommerce</a><a href="/blog/tag/compatibility" aria-label="View posts tagged compatibility" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">compatibility</a><a href="/blog/tag/invoice" aria-label="View posts tagged invoice" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">invoice</a><a href="/blog/tag/plugin" aria-label="View posts tagged plugin" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">plugin</a></div></article><article class="bg-white rounded-2xl p-6 shadow-soft hover:shadow-float transition-all duration-300"><a href="/blog/extract-tables-from-pdf" class="block"><h2 class="text-xl font-semibold text-document-800 mb-2 hover:text-primary-600 transition-colors">Extract Tables from PDFs: 5 Methods That Actually Work</h2><p class="text-document-600 text-sm mb-3">A hands-on comparison of five ways to extract tables from PDFs in Python: pdfplumber, Camelot, Tabula, AWS Textract, and manual regex. With code, benchmarks, and honest pros and cons.</p><div class="flex items-center gap-4 text-xs text-document-500"><span>By LightningPDF Team</span> <span>Apr 1, 2026</span> <span>5 min read</span></div></a> <div class="flex flex-wrap gap-1 mt-3"><a href="/blog/tag/&#34;pdf&#34;" aria-label="View posts tagged &#34;pdf&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;pdf&#34;</a><a href="/blog/tag/&#34;python&#34;" aria-label="View posts tagged &#34;python&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;python&#34;</a><a href="/blog/tag/&#34;tables&#34;" aria-label="View posts tagged &#34;tables&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;tables&#34;</a><a href="/blog/tag/&#34;extraction&#34;" aria-label="View posts tagged &#34;extraction&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;extraction&#34;</a><a href="/blog/tag/&#34;data&#34;" aria-label="View posts tagged &#34;data&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;data&#34;</a></div></article><article class="bg-white rounded-2xl p-6 shadow-soft hover:shadow-float transition-all duration-300"><a href="/blog/kreuzberg-vs-pymupdf-vs-pdfplumber" class="block"><h2 class="text-xl font-semibold text-document-800 mb-2 hover:text-primary-600 transition-colors">Kreuzberg vs PyMuPDF vs pdfplumber: Which PDF Parser Should You Use?</h2><p class="text-document-600 text-sm mb-3">A head-to-head comparison of Kreuzberg, PyMuPDF, and pdfplumber for Python PDF parsing. Benchmarks, architecture differences, and code examples to help you pick the right tool.</p><div class="flex items-center gap-4 text-xs text-document-500"><span>By LightningPDF Team</span> <span>Apr 1, 2026</span> <span>6 min read</span></div></a> <div class="flex flex-wrap gap-1 mt-3"><a href="/blog/tag/&#34;python&#34;" aria-label="View posts tagged &#34;python&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;python&#34;</a><a href="/blog/tag/&#34;pdf&#34;" aria-label="View posts tagged &#34;pdf&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;pdf&#34;</a><a href="/blog/tag/&#34;extraction&#34;" aria-label="View posts tagged &#34;extraction&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;extraction&#34;</a><a href="/blog/tag/&#34;comparison&#34;" aria-label="View posts tagged &#34;comparison&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;comparison&#34;</a><a href="/blog/tag/&#34;kreuzberg&#34;" aria-label="View posts tagged &#34;kreuzberg&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;kreuzberg&#34;</a><a href="/blog/tag/&#34;pymupdf&#34;" aria-label="View posts tagged &#34;pymupdf&#34;
12" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;pymupdf&#34;</a><a href="/blog/tag/&#34;pdfplumber&#34;" aria-label="View posts tagged &#34;pdfplumber&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;pdfplumber&#34;</a></div></article><article class="bg-white rounded-2xl p-6 shadow-soft hover:shadow-float transition-all duration-300"><a href="/blog/document-pipeline-python" class="block"><h2 class="text-xl font-semibold text-document-800 mb-2 hover:text-primary-600 transition-colors">Build a Document Pipeline in Python: From Database to PDF</h2><p class="text-document-600 text-sm mb-3">A complete tutorial for building a Python document pipeline that queries a database, formats data with Jinja2, generates PDFs via API, and delivers them via email or S3.</p><div class="flex items-center gap-4 text-xs text-document-500"><span>By LightningPDF Team</span> <span>Apr 1, 2026</span> <span>3 min read</span></div></a> <div class="flex flex-wrap gap-1 mt-3"><a href="/blog/tag/&#34;python&#34;" aria-label="View posts tagged &#34;python&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;python&#34;</a><a href="/blog/tag/&#34;tutorial&#34;" aria-label="View posts tagged &#34;tutorial&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;tutorial&#34;</a><a href="/blog/tag/&#34;automation&#34;" aria-label="View posts tagged &#34;automation&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;automation&#34;</a><a href="/blog/tag/&#34;pipeline&#34;" aria-label="View posts tagged &#34;pipeline&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;pipeline&#34;</a><a href="/blog/tag/&#34;database&#34;" aria-label="View posts tagged &#34;database&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;database&#34;</a></div></article><article class="bg-white rounded-2xl p-6 shadow-soft hover:shadow-float transition-all duration-300"><a href="/blog/pdf-to-json-extract-structured-data" class="block"><h2 class="text-xl font-semibold text-document-800 mb-2 hover:text-primary-600 transition-colors">PDF to JSON: How to Extract Structured Data from PDFs</h2><p class="text-document-600 text-sm mb-3">Three practical approaches to extracting structured data from PDFs into JSON: regex on raw text, template-based extraction, and AI-powered extraction with code for each.</p><div class="flex items-center gap-4 text-xs text-document-500"><span>By LightningPDF Team</span> <span>Apr 1, 2026</span> <span>4 min read</span></div></a> <div class="flex flex-wrap gap-1 mt-3"><a href="/blog/tag/&#34;pdf&#34;" aria-label="View posts tagged &#34;pdf&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;pdf&#34;</a><a href="/blog/tag/&#34;json&#34;" aria-label="View posts tagged &#34;json&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;json&#34;</a><a href="/blog/tag/&#34;python&#34;" aria-label="View posts tagged &#34;python&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;python&#34;</a><a href="/blog/tag/&#34;extraction&#34;" aria-label="View posts tagged &#34;extraction&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;extraction&#34;</a><a href="/blog/tag/&#34;api&#34;" aria-label="View posts tagged &#34;api&#34;" class="bg-primary-50 text-primary-600 px-2 py-0.5 rounded-full text-xs hover:bg-primary-100 transition-colors">&#34;api&#34;</a></div></article></div><nav aria-label="Blog pagination" class="mt-12 flex items-center justify-center gap-2"><span class="px-3 py-2 text-sm font-medium bg-primary-600 text-white rounded-lg">1</span> <a href="/blog?page=2" class="px-3 py-2 text-sm text-document-500 hover:text-primary-600 transition-colors">2</a> <a href="/blog?page=3" class="px-3 py-2 text-sm text-document-500 hover:text-primary-600 transition-colors">3</a> <a href="/blog?page=4" class="px-3 py-2 text-sm text-document-500 hover:text-primary-600 transition-colors">4</a> <a href="/blog?page=5" class="px-3 py-2 text-sm text-document-500 hover:text-primary-600 transition-colors">5</a> <a href="/blog?page=2" class="px-3 py-2 text-sm text-document-600 hover:text-primary-600 transition-colors">Next &rarr;</a></nav></div></div></main><footer class="border-t border-document-200 mt-auto bg-white"><div class="max-w-7xl mx-auto py-10 px-4 sm:px-6 lg:px-8">
12<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-8 mb-8"><!-- Product --><div><h4 class="text-sm font-semibold text-document-800 mb-3">Product</h4><ul class="space-y-2"><li><a href="/docs" class="text-sm text-document-500 hover:text-document-900 transition-colors">Documentation</a></li><li><a href="/pricing" class="text-sm text-document-500 hover:text-document-900 transition-colors">Pricing</a></li><li><a href="/marketplace" class="text-sm text-document-500 hover:text-document-900 transition-colors">Templates</a></li><li><a href="/blog" class="text-sm text-document-500 hover:text-document-900 transition-colors">Blog</a></li></ul></div><!-- Developers --><div><h4 class="text-sm font-semibold text-document-800 mb-3">Developers</h4><ul class="space-y-2"><li><a href="/docs/generate-pdf" class="text-sm text-document-500 hover:text-document-900 transition-colors">API Reference</a></li><li><a href="/docs/getting-started" class="text-sm text-document-500 hover:text-document-900 transition-colors">Quickstart</a></li><li><a href="/auth/register" class="text-sm text-document-500 hover:text-document-900 transition-colors">Get API Key</a></li><li><a href="https://status.lightningpdf.dev" target="_blank" rel="noopener noreferrer" class="text-sm text-document-500 hover:text-document-900 transition-colors">Status</a></li></ul></div><!-- Company --><div><h4 class="text-sm font-semibold text-document-800 mb-3">Company</h4><ul class="space-y-2"><li><a href="/privacy" class="text-sm text-document-500 hover:text-document-900 transition-colors">Privacy</a></li><li><a href="/terms" class="text-sm text-document-500 hover:text-document-900 transition-colors">Terms</a></li></ul></div><!-- Connect --><div><h4 class="text-sm font-semibold text-document-800 mb-3">Connect</h4><ul class="space-y-2"><li><a href="/support" class="text-sm text-document-500 hover:text-document-900 transition-colors">Contact Support</a></li><li><a href="https://t.me/+ITaWB8ePvT00N2E0" target="_blank" rel="noopener noreferrer" class="inline-flex items-center gap-1.5 text-sm text-document-500 hover:text-document-900 transition-colors"><svg class="w-4 h-4" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"></path></svg> Telegram community</a></li></ul></div><!-- Family --><div><h4 class="text-sm font-semibold text-document-800 mb-3">Family</h4><p class="text-xs text-document-500 mb-3">Sibling tools from the same maker.</p><ul class="space-y-2"><li><a href="https://thunderhooks.com" target="_blank" rel="noopener noreferrer" class="text-sm text-document-500 hover:text-document-900 transition-colors inline-flex items-center gap-1">Thunderhooks <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg></a></li><li><a href="https://devformat.tools" target="_blank" rel="noopener noreferrer" class="text-sm text-document-500 hover:text-document-900 transition-colors inline-flex items-center gap-1">DevFormat <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg></a></li></ul></div></div><div class="border-t border-document-200 pt-6 flex flex-col sm:flex-row items-center justify-between gap-4"><div class="flex items-center gap-2"><div class="w-6 h-6 bg-gradient-to-br from-primary-500 to-primary-700 rounded-lg flex items-center justify-center"><svg class="w-3.5 h-3.5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
12<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"></path></svg></div><span class="text-sm font-semibold text-document-700">LightningPDF</span></div><p class="text-xs text-document-500">&copy; 2026 LightningPDF. All rights reserved.</p></div></div></footer><!-- Toast Container --><div id="toast-container" class="fixed bottom-4 right-4 space-y-2 z-50"></div><!-- Enhanced JavaScript -->
12<script>
13				// Configure HTMX to send CSRF token with all requests
14				document.addEventListener('htmx:configRequest', function(evt) {
15					const csrfCookie = document.cookie.split('; ').find(row => row.startsWith('_csrf='));
16					if (csrfCookie) {
17						const csrfToken = decodeURIComponent(csrfCookie.split('=')[1]);
18						evt.detail.headers['X-CSRF-Token'] = csrfToken;
19					} else {
20						console.warn('No CSRF cookie found');
21					}
22				});
23			</script>
23<script>
24				// Toast system (vanilla JS, no jQuery needed)
25				function showToast(message, type) {
26					type = type || 'info';
27					var icons = { success: '\u{1F338}', error: '\u{1F344}', warning: '\u26A0\uFE0F', info: '\u2728' };
28					var bgColors = {
29						success: 'bg-nature-50 border-nature-200',
30						error: 'bg-red-50 border-red-200',
31						warning: 'bg-warning-50 border-warning-200',
32						info: 'bg-primary-50 border-primary-200'
33					};
34					var container = document.getElementById('toast-container');
35					if (!container) return;
36					var toast = document.createElement('div');
37					toast.className = 'toast ' + type + ' animate-fade-in border rounded-xl p-4 shadow-lg ' + (bgColors[type] || bgColors.info);
38					toast.innerHTML = '<div class="flex items-center justify-between"><div class="flex items-center"><div class="text-lg mr-3">' + (icons[type] || icons.info) + '</div><div class="text-sm font-medium text-document-800">' + message + '</div></div><button class="ml-4 text-document-400 hover:text-document-600 p-1 rounded-lg hover:bg-document-100 transition-colors" onclick="this.closest(\'.toast\').remove()"><svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg></button></div>';
39					container.appendChild(toast);
40					var dismissTime = type === 'error' ? 8000 : type === 'warning' ? 6000 : 4000;
41					setTimeout(function() {
42						toast.style.opacity = '0';
43						toast.style.transform = 'translateY(-10px)';
44						setTimeout(function() { toast.remove(); }, 300);
45					}, dismissTime);
46				}
47				window.showToast = showToast;
48
49				// App initialization (only runs when HTMX is loaded)
50				document.addEventListener('DOMContentLoaded', function() {
51					if (typeof htmx === 'undefined') return;
52
53					// Handle HX-Trigger showToast events from server responses
54					document.body.addEventListener('showToast', function(evt) {
55						var d = evt.detail || {};
56						showToast(d.message || 'Done', d.type || 'info');
57					});
58
59					document.body.addEventListener('htmx:afterRequest', function(evt) {
60						var detail = evt.detail;
61						var xhr = detail.xhr;
62						var path = detail.pathInfo ? detail.pathInfo.requestPath : '';
63						if (xhr && xhr.status === 200 && path.includes('/save')) {
64							showToast('Template saved successfully!', 'success');
65						}
66						if (xhr && xhr.status >= 400) {
67							var errorMsg = 'Request failed';
68							try {
69								if (xhr.responseText) {
70									try {
71										var json = JSON.parse(xhr.responseText);
72										errorMsg = (json.error && json.error.message) || json.message || errorMsg;
73									} catch (_) {
74										var s = xhr.status;
75										if (s === 400) errorMsg = 'Invalid request. Please check your input.';
76										else if (s === 401) errorMsg = 'Session expired. Please log in again.';
77										else if (s === 403) errorMsg = 'Permission denied.';
78										else if (s === 404) errorMsg = 'Resource not found.';
79										else if (s === 429) errorMsg = 'Too many requests. Please slow down.';
80										else if (s >= 500) errorMsg = 'Server error. Please try again later.';
81									}
82								}
83							} catch (e) { console.error('Error parsing response:', e); }
84							showToast(errorMsg, 'error');
85						}
86						if (path.includes('/preview')) {
87							var pc = document.getElementById('preview-content');
88							if (pc) { pc.style.opacity = '1'; pc.style.transform = 'scale(1)'; }
89						}
90					});
91
92					document.body.addEventListener('htmx:beforeRequest', function(evt) {
93						var path = evt.detail.pathInfo ? evt.detail.pathInfo.requestPath : '';
94						if (path.includes('/preview')) {
95							var pc = document.getElementById('preview-content');
96							if (pc) { pc.style.opacity = '0.6'; pc.style.transform = 'scale(0.98)'; pc.style.transition = 'all 0.3s ease'; }
97						}
98					});
99
100					document.body.addEventListener('htmx:responseError', function(evt) {
101						console.error('HTMX Error:', evt.detail);
102						showToast('Request failed', 'error');
103					});
104
105					document.addEventListener('keydown', function(e) {
106						if (e.ctrlKey && e.key === 's') {
107							e.preventDefault();
108							var saveBtn = document.querySelector('[hx-post="/designer/save"]');
109							if (saveBtn) { htmx.trigger(saveBtn, 'click'); showToast('Saving...', 'info'); }
110						}
111						if (e.ctrlKey && e.key === 'g') {
112							e.preventDefault();
113							if (typeof generatePDF === 'function') generatePDF();
114						}
115					});
116
117					// Auto-resize textareas
118					function autoResize(ta) { ta.style.height = 'auto'; ta.style.height = Math.min(ta.scrollHeight, 400) + 'px'; }
119					document.querySelectorAll('textarea:not([name="content"])').forEach(function(ta) {
120						autoResize(ta);
121						ta.addEventListener('input', function() { autoResize(ta); });
122					});
123				});
124			</script>
124</body></html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.