Skip to content

Commit 452a770

Browse files
committed
docs: add Fumadocs documentation site and content
1 parent e9fdbb6 commit 452a770

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+10402
-28
lines changed

.agents/plans/036-documentation.md

Lines changed: 656 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 158 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,170 @@
1-
# @libpdf/core
1+
# LibPDF
22

3-
A modern PDF library for TypeScript — parsing and generation.
3+
A modern PDF library for TypeScript. Parse, modify, and generate PDFs with a clean, intuitive API.
44

5-
## Why?
5+
> **Beta Software**: LibPDF is under active development. APIs may change between minor versions. Not yet recommended for production use.
66
7-
The JavaScript ecosystem's PDF landscape is fragmented:
8-
- **pdf.js** (Mozilla) - excellent parsing/rendering, but focused on browser viewing, not manipulation
9-
- **pdf-lib** - great for generation and basic manipulation, but parsing is limited
10-
- **pdfkit** - generation only, no parsing
7+
## Why LibPDF?
118

12-
There's no single, comprehensive library that handles both robust parsing *and* generation with a clean, modern API.
9+
LibPDF was born from frustration. At [Documenso](https://documenso.com), we found ourselves wrestling with the JavaScript PDF ecosystem:
1310

14-
**@libpdf/core** aims to fill that gap.
11+
- **PDF.js** is excellent for rendering, but it's read-only
12+
- **pdf-lib** has a great API, but chokes on slightly malformed documents
13+
- **pdfkit** only generates, no parsing at all
1514

16-
## Goals
15+
We kept adding workarounds. A patch here for a malformed xref table. A hack there for an encrypted document. Eventually, we decided to build what we actually needed:
1716

18-
- **Full PDF parsing** - extract text, images, metadata, structure
19-
- **Full PDF generation** - create documents from scratch
20-
- **PDF manipulation** - modify existing documents
21-
- **Modern TypeScript** - strong typing, tree-shakeable, no legacy baggage
22-
- **Runtime flexible** - Node.js, Bun, and browsers
17+
- **Lenient like PDFBox and PDF.js**: opens documents other libraries reject
18+
- **Intuitive like pdf-lib**: clean, TypeScript-first API
19+
- **Complete**: encryption, digital signatures, incremental saves, form filling
2320

24-
## Known Limitations
21+
## Features
2522

26-
- **Predefined CJK CMaps**: Only Identity-H and Identity-V CMaps are supported. Legacy CJK PDFs using predefined CMaps (UniGB-UCS2-H, UniJIS-UCS2-H, etc.) without ToUnicode maps may not extract text correctly. Modern PDFs include ToUnicode maps which work correctly.
23+
| Feature | Status | Notes |
24+
|---------|--------|-------|
25+
| Parse any PDF | Yes | Graceful fallback for malformed documents |
26+
| Create PDFs | Yes | From scratch or modify existing |
27+
| Encryption | Yes | RC4, AES-128, AES-256 (R2-R6) |
28+
| Digital Signatures | Yes | PAdES B-B, B-T, B-LT, B-LTA |
29+
| Form Filling | Yes | Text, checkbox, radio, dropdown, signature |
30+
| Form Flattening | Yes | Bake fields into page content |
31+
| Merge & Split | Yes | Combine or extract pages |
32+
| Attachments | Yes | Embed and extract files |
33+
| Text Extraction | Yes | With position information |
34+
| Font Embedding | Yes | TTF/OpenType with subsetting |
35+
| Images | Yes | JPEG, PNG (with alpha) |
36+
| Incremental Saves | Yes | Append changes, preserve signatures |
2737

28-
## Development
38+
## Installation
2939

3040
```bash
41+
npm install @libpdf/core
42+
# or
43+
bun add @libpdf/core
44+
```
45+
46+
## Quick Start
47+
48+
### Parse an existing PDF
49+
50+
```typescript
51+
import { PDF } from "@libpdf/core";
52+
53+
const pdf = await PDF.load(bytes);
54+
const pages = await pdf.getPages();
55+
56+
console.log(`${pages.length} pages`);
57+
```
58+
59+
### Open an encrypted PDF
60+
61+
```typescript
62+
const pdf = await PDF.load(bytes, { credentials: "password" });
63+
```
64+
65+
### Fill a form
66+
67+
```typescript
68+
const pdf = await PDF.load(bytes);
69+
const form = await pdf.getForm();
70+
71+
form.fill({
72+
name: "Jane Doe",
73+
email: "jane@example.com",
74+
agreed: true,
75+
});
76+
77+
const filled = await pdf.save();
78+
```
79+
80+
### Sign a document
81+
82+
```typescript
83+
import { PDF, P12Signer } from "@libpdf/core";
84+
85+
const pdf = await PDF.load(bytes);
86+
const signer = await P12Signer.create(p12Bytes, "password");
87+
88+
const signed = await pdf.sign({
89+
signer,
90+
reason: "I approve this document",
91+
});
92+
```
93+
94+
### Merge PDFs
95+
96+
```typescript
97+
const merged = await PDF.merge([pdf1Bytes, pdf2Bytes, pdf3Bytes]);
98+
```
99+
100+
### Draw on a page
101+
102+
```typescript
103+
import { PDF, rgb } from "@libpdf/core";
104+
105+
const pdf = PDF.create();
106+
const page = pdf.addPage({ size: "letter" });
107+
108+
page.drawText("Hello, World!", {
109+
x: 50,
110+
y: 700,
111+
fontSize: 24,
112+
color: rgb(0, 0, 0),
113+
});
114+
115+
page.drawRectangle({
116+
x: 50,
117+
y: 600,
118+
width: 200,
119+
height: 100,
120+
color: rgb(0.9, 0.9, 0.9),
121+
borderColor: rgb(0, 0, 0),
122+
borderWidth: 1,
123+
});
124+
125+
const output = await pdf.save();
126+
```
127+
128+
## Runtime Support
129+
130+
LibPDF runs everywhere:
131+
132+
- **Node.js** 18+
133+
- **Bun**
134+
- **Browsers** (modern, with Web Crypto)
135+
136+
## Philosophy
137+
138+
### Be lenient
139+
140+
Real-world PDFs are messy. Export a document through three different tools and you'll get three slightly different interpretations of the spec. LibPDF prioritizes *opening your document* over strict compliance. When standard parsing fails, we fall back to brute-force recovery, scanning the entire file to rebuild the structure.
141+
142+
### Two API layers
143+
144+
- **High-level**: `PDF`, `PDFPage`, `PDFForm` for common tasks
145+
- **Low-level**: `PdfDict`, `PdfArray`, `PdfStream` for full control
146+
147+
## Documentation
148+
149+
Full documentation at [libpdf.dev](https://libpdf.dev)
150+
151+
## Sponsors
152+
153+
LibPDF is developed by [Documenso](https://documenso.com), the open-source DocuSign alternative.
154+
155+
<a href="https://documenso.com">
156+
<img src="apps/docs/public/sponsors/documenso.png" alt="Documenso" height="24">
157+
</a>
158+
159+
## Contributing
160+
161+
We welcome contributions! See our [contributing guide](CONTRIBUTING.md) for details.
162+
163+
```bash
164+
# Clone the repo
165+
git clone https://github.com/libpdf/core.git
166+
cd libpdf
167+
31168
# Install dependencies
32169
bun install
33170

@@ -36,19 +173,12 @@ bun run test
36173

37174
# Type check
38175
bun run typecheck
39-
40-
# Lint and format
41-
bun run lint:fix
42176
```
43177

44-
## Reference Libraries
178+
## License
45179

46-
This project cross-references these excellent PDF libraries:
180+
[MIT](LICENSE)
47181

48-
- [Mozilla pdf.js](https://github.com/mozilla/pdf.js) - `checkouts/pdfjs`
49-
- [pdf-lib](https://github.com/Hopding/pdf-lib) - `checkouts/pdf-lib`
50-
- [Apache PDFBox](https://github.com/apache/pdfbox) - `checkouts/pdfbox`
182+
The `src/fontbox/` directory is licensed under [Apache-2.0](src/fontbox/LICENSE) as it is derived from [Apache PDFBox](https://pdfbox.apache.org/).
51183

52-
## License
53184

54-
MIT

apps/docs/.gitignore

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# deps
2+
/node_modules
3+
4+
# generated content
5+
.source
6+
7+
# test & build
8+
/coverage
9+
/.next/
10+
/out/
11+
/build
12+
*.tsbuildinfo
13+
14+
# misc
15+
.DS_Store
16+
*.pem
17+
/.pnp
18+
.pnp.js
19+
npm-debug.log*
20+
yarn-debug.log*
21+
yarn-error.log*
22+
23+
# others
24+
.env*.local
25+
.vercel
26+
next-env.d.ts

apps/docs/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# @libpdf/core Documentation
2+
3+
This is the documentation site for @libpdf/core, built with [Fumadocs](https://fumadocs.dev) and [Next.js](https://nextjs.org).
4+
5+
## Structure
6+
7+
- `content/docs/` - Documentation content in MDX format
8+
- `app/docs/` - Documentation layout and pages
9+
- `app/(home)/` - Landing page
10+
11+
## Development
12+
13+
```bash
14+
bun dev
15+
```
16+
17+
Open http://localhost:3000 to view the docs.
18+
19+
## Building
20+
21+
```bash
22+
bun run build
23+
```
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use client';
2+
3+
import { useState } from 'react';
4+
import { Copy, Check } from 'lucide-react';
5+
6+
export function CopyButton({ text }: { text: string }) {
7+
const [copied, setCopied] = useState(false);
8+
9+
const handleCopy = async () => {
10+
await navigator.clipboard.writeText(text);
11+
setCopied(true);
12+
setTimeout(() => setCopied(false), 2000);
13+
};
14+
15+
return (
16+
<button
17+
onClick={handleCopy}
18+
className="p-1.5 rounded-md hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
19+
aria-label="Copy to clipboard"
20+
>
21+
{copied ? (
22+
<Check className="w-4 h-4 text-green-500" />
23+
) : (
24+
<Copy className="w-4 h-4" />
25+
)}
26+
</button>
27+
);
28+
}

apps/docs/app/(home)/layout.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { HomeLayout } from 'fumadocs-ui/layouts/home';
2+
import { baseOptions } from '@/lib/layout.shared';
3+
4+
export default function Layout({ children }: LayoutProps<'/'>) {
5+
return <HomeLayout {...baseOptions()}
6+
nav={{
7+
title: <div>LibPDF <span className="text-xs text-muted-foreground font-normal">by Documenso</span></div>
8+
}}
9+
links={[
10+
{
11+
type: "main",
12+
text: 'Docs',
13+
url: '/docs',
14+
},
15+
{
16+
type: "main",
17+
text: 'API Reference',
18+
url: '/docs/api',
19+
},
20+
]}
21+
>{children}</HomeLayout>;
22+
}

0 commit comments

Comments
 (0)