@lexmata/micropdf 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +191 -0
- package/README.md +985 -0
- package/binding.gyp +73 -0
- package/dist/annot.d.ts +458 -0
- package/dist/annot.d.ts.map +1 -0
- package/dist/annot.js +697 -0
- package/dist/annot.js.map +1 -0
- package/dist/archive.d.ts +128 -0
- package/dist/archive.d.ts.map +1 -0
- package/dist/archive.js +268 -0
- package/dist/archive.js.map +1 -0
- package/dist/buffer.d.ts +572 -0
- package/dist/buffer.d.ts.map +1 -0
- package/dist/buffer.js +971 -0
- package/dist/buffer.js.map +1 -0
- package/dist/colorspace.d.ts +287 -0
- package/dist/colorspace.d.ts.map +1 -0
- package/dist/colorspace.js +542 -0
- package/dist/colorspace.js.map +1 -0
- package/dist/context.d.ts +184 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +320 -0
- package/dist/context.js.map +1 -0
- package/dist/cookie.d.ts +164 -0
- package/dist/cookie.d.ts.map +1 -0
- package/dist/cookie.js +306 -0
- package/dist/cookie.js.map +1 -0
- package/dist/device.d.ts +169 -0
- package/dist/device.d.ts.map +1 -0
- package/dist/device.js +350 -0
- package/dist/device.js.map +1 -0
- package/dist/display-list.d.ts +202 -0
- package/dist/display-list.d.ts.map +1 -0
- package/dist/display-list.js +410 -0
- package/dist/display-list.js.map +1 -0
- package/dist/document.d.ts +637 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +902 -0
- package/dist/document.js.map +1 -0
- package/dist/easy.d.ts +423 -0
- package/dist/easy.d.ts.map +1 -0
- package/dist/easy.js +644 -0
- package/dist/easy.js.map +1 -0
- package/dist/enhanced.d.ts +226 -0
- package/dist/enhanced.d.ts.map +1 -0
- package/dist/enhanced.js +368 -0
- package/dist/enhanced.js.map +1 -0
- package/dist/filter.d.ts +51 -0
- package/dist/filter.d.ts.map +1 -0
- package/dist/filter.js +381 -0
- package/dist/filter.js.map +1 -0
- package/dist/font.d.ts +222 -0
- package/dist/font.d.ts.map +1 -0
- package/dist/font.js +381 -0
- package/dist/font.js.map +1 -0
- package/dist/form.d.ts +214 -0
- package/dist/form.d.ts.map +1 -0
- package/dist/form.js +497 -0
- package/dist/form.js.map +1 -0
- package/dist/geometry.d.ts +469 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +780 -0
- package/dist/geometry.js.map +1 -0
- package/dist/image.d.ts +172 -0
- package/dist/image.d.ts.map +1 -0
- package/dist/image.js +348 -0
- package/dist/image.js.map +1 -0
- package/dist/index.d.ts +171 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +339 -0
- package/dist/index.js.map +1 -0
- package/dist/link.d.ts +168 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +343 -0
- package/dist/link.js.map +1 -0
- package/dist/micropdf.d.ts +40 -0
- package/dist/micropdf.d.ts.map +1 -0
- package/dist/micropdf.js +45 -0
- package/dist/micropdf.js.map +1 -0
- package/dist/nanopdf.d.ts +40 -0
- package/dist/nanopdf.d.ts.map +1 -0
- package/dist/nanopdf.js +45 -0
- package/dist/nanopdf.js.map +1 -0
- package/dist/native.d.ts +242 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +509 -0
- package/dist/native.js.map +1 -0
- package/dist/output.d.ts +166 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +365 -0
- package/dist/output.js.map +1 -0
- package/dist/path.d.ts +420 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +687 -0
- package/dist/path.js.map +1 -0
- package/dist/pdf/object.d.ts +489 -0
- package/dist/pdf/object.d.ts.map +1 -0
- package/dist/pdf/object.js +1045 -0
- package/dist/pdf/object.js.map +1 -0
- package/dist/pixmap.d.ts +315 -0
- package/dist/pixmap.d.ts.map +1 -0
- package/dist/pixmap.js +590 -0
- package/dist/pixmap.js.map +1 -0
- package/dist/profiler.d.ts +159 -0
- package/dist/profiler.d.ts.map +1 -0
- package/dist/profiler.js +380 -0
- package/dist/profiler.js.map +1 -0
- package/dist/render-options.d.ts +227 -0
- package/dist/render-options.d.ts.map +1 -0
- package/dist/render-options.js +130 -0
- package/dist/render-options.js.map +1 -0
- package/dist/resource-tracking.d.ts +332 -0
- package/dist/resource-tracking.d.ts.map +1 -0
- package/dist/resource-tracking.js +653 -0
- package/dist/resource-tracking.js.map +1 -0
- package/dist/simple.d.ts +276 -0
- package/dist/simple.d.ts.map +1 -0
- package/dist/simple.js +343 -0
- package/dist/simple.js.map +1 -0
- package/dist/stext.d.ts +290 -0
- package/dist/stext.d.ts.map +1 -0
- package/dist/stext.js +312 -0
- package/dist/stext.js.map +1 -0
- package/dist/stream.d.ts +174 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +476 -0
- package/dist/stream.js.map +1 -0
- package/dist/text.d.ts +337 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +454 -0
- package/dist/text.js.map +1 -0
- package/dist/typed-arrays.d.ts +127 -0
- package/dist/typed-arrays.d.ts.map +1 -0
- package/dist/typed-arrays.js +410 -0
- package/dist/typed-arrays.js.map +1 -0
- package/dist/types.d.ts +358 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +216 -0
- package/dist/types.js.map +1 -0
- package/native/annot.cc +557 -0
- package/native/buffer.cc +204 -0
- package/native/colorspace.cc +166 -0
- package/native/context.cc +84 -0
- package/native/cookie.cc +179 -0
- package/native/device.cc +179 -0
- package/native/display_list.cc +179 -0
- package/native/document.cc +268 -0
- package/native/enhanced.cc +70 -0
- package/native/font.cc +282 -0
- package/native/form.cc +523 -0
- package/native/geometry.cc +255 -0
- package/native/image.cc +216 -0
- package/native/include/micropdf/enhanced.h +38 -0
- package/native/include/micropdf/types.h +36 -0
- package/native/include/micropdf.h +106 -0
- package/native/include/mupdf-ffi.h +39 -0
- package/native/include/mupdf.h +11 -0
- package/native/include/mupdf_minimal.h +381 -0
- package/native/lib/linux-x64/libmicropdf.a +0 -0
- package/native/link.cc +234 -0
- package/native/micropdf.cc +71 -0
- package/native/output.cc +229 -0
- package/native/page.cc +572 -0
- package/native/path.cc +259 -0
- package/native/pixmap.cc +240 -0
- package/native/stext.cc +610 -0
- package/native/stream.cc +239 -0
- package/package.json +120 -0
- package/scripts/build-from-rust.js +97 -0
- package/scripts/install.js +184 -0
package/README.md
ADDED
|
@@ -0,0 +1,985 @@
|
|
|
1
|
+
# MicroPDF for Node.js, Deno & Bun
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
**High-performance PDF manipulation library for Node.js, Deno, and Bun**
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/micropdf)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://nodejs.org/)
|
|
10
|
+
[](https://deno.land/)
|
|
11
|
+
[](https://bun.sh/)
|
|
12
|
+
[](https://www.typescriptlang.org/)
|
|
13
|
+
|
|
14
|
+
[Features](#features) • [Installation](#installation) • [Quick Start](#quick-start) • [Deno](#deno-support) • [Bun](#bun-support) • [Documentation](#documentation)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Overview
|
|
21
|
+
|
|
22
|
+
MicroPDF is a powerful PDF manipulation library for Node.js, built on a **100% MuPDF-compatible Rust core** with native N-API bindings for optimal performance. It provides a clean, type-safe API for reading, rendering, and manipulating PDF documents.
|
|
23
|
+
|
|
24
|
+
### Key Features
|
|
25
|
+
|
|
26
|
+
- 🚀 **High Performance** - Native Rust core with N-API bindings for blazing-fast PDF operations
|
|
27
|
+
- 📄 **Complete PDF Support** - 100% MuPDF compatibility with all modern PDF features
|
|
28
|
+
- 🎨 **Advanced Rendering** - Full pixel rendering pipeline with scan-line rasterization
|
|
29
|
+
- 📝 **Smart Text Extraction** - Layout-aware structured text with paragraph detection
|
|
30
|
+
- 🖼️ **All Image Formats** - Decode all 8 PDF filters (Flate, LZW, JPEG, JPEG2000, JBIG2, etc.)
|
|
31
|
+
- ✍️ **Forms & Annotations** - Full support for interactive forms and 14 annotation types
|
|
32
|
+
- 🔒 **Security** - Complete encryption support (RC4, AES-128, AES-256)
|
|
33
|
+
- 🎯 **Type-Safe** - Full TypeScript support with comprehensive type definitions
|
|
34
|
+
- 🧩 **Zero Dependencies** - No external runtime dependencies
|
|
35
|
+
- 🔧 **Cross-Platform** - Works on Linux, macOS, and Windows
|
|
36
|
+
|
|
37
|
+
### What You Can Do
|
|
38
|
+
|
|
39
|
+
#### ✅ Document Operations
|
|
40
|
+
|
|
41
|
+
- Open PDFs from files, buffers, or URLs
|
|
42
|
+
- Save and write PDF documents
|
|
43
|
+
- Read and write metadata (title, author, keywords, etc.)
|
|
44
|
+
- Password protection and permission checking
|
|
45
|
+
|
|
46
|
+
#### ✅ Advanced Rendering
|
|
47
|
+
|
|
48
|
+
- Render pages to images (PNG, pixmaps) at any DPI
|
|
49
|
+
- Custom colorspaces (RGB, CMYK, Grayscale)
|
|
50
|
+
- Anti-aliasing and high-quality output
|
|
51
|
+
- Alpha channel support
|
|
52
|
+
|
|
53
|
+
#### ✅ Smart Text Extraction
|
|
54
|
+
|
|
55
|
+
- Extract text with full layout preservation
|
|
56
|
+
- Structured text (blocks, lines, characters)
|
|
57
|
+
- Search with bounding boxes
|
|
58
|
+
- Multi-language support (LTR, RTL, vertical)
|
|
59
|
+
|
|
60
|
+
#### ✅ Interactive Features
|
|
61
|
+
|
|
62
|
+
- Read and render 14 annotation types
|
|
63
|
+
- Work with 7 form field types
|
|
64
|
+
- Display interactive elements
|
|
65
|
+
|
|
66
|
+
#### ✅ Graphics & Geometry
|
|
67
|
+
|
|
68
|
+
- Path construction and manipulation
|
|
69
|
+
- Stroke and fill operations
|
|
70
|
+
- Matrix transformations
|
|
71
|
+
- Clipping and masking
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Installation
|
|
76
|
+
|
|
77
|
+
### From npm
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm install micropdf
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Or using pnpm/yarn:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pnpm add micropdf
|
|
87
|
+
yarn add micropdf
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The package will automatically download prebuilt binaries for your platform. If prebuilt binaries are not available, it will attempt to build from source (requires Rust toolchain).
|
|
91
|
+
|
|
92
|
+
### Requirements
|
|
93
|
+
|
|
94
|
+
- **Node.js** >= 18.0.0
|
|
95
|
+
- **For building from source**: Rust toolchain (install from [rustup.rs](https://rustup.rs))
|
|
96
|
+
|
|
97
|
+
### Supported Platforms
|
|
98
|
+
|
|
99
|
+
| Platform | Architecture | Status |
|
|
100
|
+
| -------- | ------------- | ------------ |
|
|
101
|
+
| Linux | x64 | ✅ Supported |
|
|
102
|
+
| Linux | ARM64 | ✅ Supported |
|
|
103
|
+
| macOS | x64 | ✅ Supported |
|
|
104
|
+
| macOS | ARM64 (M1/M2) | ✅ Supported |
|
|
105
|
+
| Windows | x64 | ✅ Supported |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Deno Support
|
|
110
|
+
|
|
111
|
+
MicroPDF now supports Deno with native FFI bindings! 🦕
|
|
112
|
+
|
|
113
|
+
### Quick Start with Deno
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { Context, Document, Pixmap, MatrixHelper } from 'jsr:@micropdf/deno';
|
|
117
|
+
|
|
118
|
+
// Extract text
|
|
119
|
+
using ctx = new Context();
|
|
120
|
+
using doc = Document.open(ctx, 'document.pdf');
|
|
121
|
+
using page = doc.loadPage(0);
|
|
122
|
+
const text = page.extractText();
|
|
123
|
+
console.log(text);
|
|
124
|
+
|
|
125
|
+
// Render to PNG
|
|
126
|
+
const matrix = MatrixHelper.dpi(300);
|
|
127
|
+
using pixmap = Pixmap.fromPage(ctx, page, matrix);
|
|
128
|
+
await pixmap.savePng('output.png');
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Run Examples
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Extract text
|
|
135
|
+
deno run --allow-all examples/deno/basic.ts sample.pdf text
|
|
136
|
+
|
|
137
|
+
# Render to PNG
|
|
138
|
+
deno run --allow-all examples/deno/basic.ts sample.pdf render
|
|
139
|
+
|
|
140
|
+
# Run tests
|
|
141
|
+
deno test --allow-all examples/deno/test.ts
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Features
|
|
145
|
+
|
|
146
|
+
- ✅ Native Deno FFI (no Node.js required)
|
|
147
|
+
- ✅ Zero external dependencies
|
|
148
|
+
- ✅ Full TypeScript support
|
|
149
|
+
- ✅ Automatic resource cleanup with `using` keyword
|
|
150
|
+
- ✅ Same API as Node.js version
|
|
151
|
+
|
|
152
|
+
See [DENO.md](DENO.md) for complete Deno documentation.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Bun Support
|
|
157
|
+
|
|
158
|
+
MicroPDF now supports Bun with native FFI bindings! 🥟
|
|
159
|
+
|
|
160
|
+
### Quick Start with Bun
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { Context, Document, Pixmap, MatrixHelper } from './bun';
|
|
164
|
+
|
|
165
|
+
// Extract text
|
|
166
|
+
using ctx = new Context();
|
|
167
|
+
using doc = Document.open(ctx, 'document.pdf');
|
|
168
|
+
using page = doc.loadPage(0);
|
|
169
|
+
const text = page.extractText();
|
|
170
|
+
console.log(text);
|
|
171
|
+
|
|
172
|
+
// Render to PNG
|
|
173
|
+
const matrix = MatrixHelper.dpi(300);
|
|
174
|
+
using pixmap = Pixmap.fromPage(ctx, page, matrix);
|
|
175
|
+
await pixmap.savePng('output.png');
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Run Examples
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Extract text
|
|
182
|
+
bun run examples/bun/basic.ts sample.pdf text
|
|
183
|
+
|
|
184
|
+
# Render to PNG
|
|
185
|
+
bun run examples/bun/basic.ts sample.pdf render
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Features
|
|
189
|
+
|
|
190
|
+
- ✅ Native Bun FFI (no Node.js required)
|
|
191
|
+
- ✅ Zero external dependencies
|
|
192
|
+
- ✅ Full TypeScript support
|
|
193
|
+
- ✅ Automatic resource cleanup with `using` keyword
|
|
194
|
+
- ✅ **Ultra-fast startup** - 3x faster than Node.js
|
|
195
|
+
- ✅ Same API as Node.js and Deno versions
|
|
196
|
+
|
|
197
|
+
### Why Bun?
|
|
198
|
+
|
|
199
|
+
- **Fastest Startup** - Bun starts 3x faster than Node.js
|
|
200
|
+
- **Native TypeScript** - No compilation needed
|
|
201
|
+
- **Built-in Tools** - Bundler, test runner, package manager
|
|
202
|
+
- **JavaScriptCore Engine** - Safari's optimized engine
|
|
203
|
+
|
|
204
|
+
See [BUN.md](BUN.md) for complete Bun documentation.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Quick Start
|
|
209
|
+
|
|
210
|
+
### Opening and Reading a PDF
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import { Document } from 'micropdf';
|
|
214
|
+
|
|
215
|
+
// Open a PDF document
|
|
216
|
+
const doc = Document.open('document.pdf');
|
|
217
|
+
|
|
218
|
+
console.log(`Pages: ${doc.pageCount}`);
|
|
219
|
+
console.log(`Title: ${doc.getMetadata('Title')}`);
|
|
220
|
+
console.log(`Author: ${doc.getMetadata('Author')}`);
|
|
221
|
+
|
|
222
|
+
// Load and work with a page
|
|
223
|
+
const page = doc.loadPage(0);
|
|
224
|
+
console.log(`Page size: ${page.bounds.width} x ${page.bounds.height} points`);
|
|
225
|
+
|
|
226
|
+
// Extract text
|
|
227
|
+
const text = page.extractText();
|
|
228
|
+
console.log(text);
|
|
229
|
+
|
|
230
|
+
// Clean up
|
|
231
|
+
page.drop();
|
|
232
|
+
doc.close();
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Rendering a Page
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
import { Document, Matrix } from 'micropdf';
|
|
239
|
+
|
|
240
|
+
const doc = Document.open('document.pdf');
|
|
241
|
+
const page = doc.loadPage(0);
|
|
242
|
+
|
|
243
|
+
// Render at 2x resolution
|
|
244
|
+
const matrix = Matrix.scale(2, 2);
|
|
245
|
+
const pixmap = page.toPixmap(matrix);
|
|
246
|
+
|
|
247
|
+
console.log(`Rendered: ${pixmap.width} x ${pixmap.height} pixels`);
|
|
248
|
+
|
|
249
|
+
// Convert to PNG
|
|
250
|
+
const pngData = page.toPNG(144); // 144 DPI
|
|
251
|
+
|
|
252
|
+
// Clean up
|
|
253
|
+
page.drop();
|
|
254
|
+
doc.close();
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Text Search
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import { Document } from 'micropdf';
|
|
261
|
+
|
|
262
|
+
const doc = Document.open('document.pdf');
|
|
263
|
+
const page = doc.loadPage(0);
|
|
264
|
+
|
|
265
|
+
// Search for text
|
|
266
|
+
const hits = page.searchText('important keyword');
|
|
267
|
+
console.log(`Found ${hits.length} occurrences`);
|
|
268
|
+
|
|
269
|
+
for (const hit of hits) {
|
|
270
|
+
console.log(`Found at: [${hit.x0}, ${hit.y0}, ${hit.x1}, ${hit.y1}]`);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
page.drop();
|
|
274
|
+
doc.close();
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Password-Protected PDFs
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
import { Document } from 'micropdf';
|
|
281
|
+
|
|
282
|
+
const doc = Document.open('protected.pdf');
|
|
283
|
+
|
|
284
|
+
if (doc.needsPassword()) {
|
|
285
|
+
const success = doc.authenticate('password123');
|
|
286
|
+
if (!success) {
|
|
287
|
+
throw new Error('Invalid password');
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Check permissions
|
|
292
|
+
if (doc.hasPermission(4)) {
|
|
293
|
+
// FZ_PERMISSION_PRINT
|
|
294
|
+
console.log('Printing is allowed');
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Documentation
|
|
301
|
+
|
|
302
|
+
### Complete API Documentation
|
|
303
|
+
|
|
304
|
+
All classes, methods, and properties are fully documented with JSDoc comments. Your IDE will provide:
|
|
305
|
+
|
|
306
|
+
- **Autocomplete** for all methods and properties
|
|
307
|
+
- **Type hints** for parameters and return values
|
|
308
|
+
- **Documentation** on hover
|
|
309
|
+
- **Code examples** inline
|
|
310
|
+
|
|
311
|
+
### Architecture
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
┌──────────────────────────────────────┐
|
|
315
|
+
│ TypeScript API (micropdf-js/src) │
|
|
316
|
+
│ - Document, Page, Pixmap, etc. │
|
|
317
|
+
└────────────────┬─────────────────────┘
|
|
318
|
+
│
|
|
319
|
+
┌────────────────▼─────────────────────┐
|
|
320
|
+
│ N-API Bindings (native/*.cc) │
|
|
321
|
+
│ - C++ wrappers for Node.js │
|
|
322
|
+
└────────────────┬─────────────────────┘
|
|
323
|
+
│
|
|
324
|
+
┌────────────────▼─────────────────────┐
|
|
325
|
+
│ Rust FFI (micropdf-rs/src/ffi) │
|
|
326
|
+
│ - 660+ C-compatible functions │
|
|
327
|
+
└────────────────┬─────────────────────┘
|
|
328
|
+
│
|
|
329
|
+
┌────────────────▼─────────────────────┐
|
|
330
|
+
│ MuPDF Library │
|
|
331
|
+
│ - Core PDF processing │
|
|
332
|
+
└──────────────────────────────────────┘
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Module Overview
|
|
336
|
+
|
|
337
|
+
| Module | Description | Status |
|
|
338
|
+
| --------------- | ---------------------------------- | ----------- |
|
|
339
|
+
| **document** | PDF document operations | ✅ Complete |
|
|
340
|
+
| **page** | Page rendering and text extraction | ✅ Complete |
|
|
341
|
+
| **geometry** | 2D geometry (Point, Rect, Matrix) | ✅ Complete |
|
|
342
|
+
| **buffer** | Binary data handling | ✅ Complete |
|
|
343
|
+
| **colorspace** | Color space management | ✅ Complete |
|
|
344
|
+
| **pixmap** | Raster image manipulation | ⚠️ Partial |
|
|
345
|
+
| **text** | Text layout and extraction | ⚠️ Partial |
|
|
346
|
+
| **path** | Vector graphics | ⚠️ Partial |
|
|
347
|
+
| **font** | Font handling | ⚠️ Partial |
|
|
348
|
+
| **image** | Image operations | ⚠️ Partial |
|
|
349
|
+
| **forms** | PDF forms | ❌ Not yet |
|
|
350
|
+
| **annotations** | PDF annotations | ❌ Not yet |
|
|
351
|
+
|
|
352
|
+
See [FFI_IMPLEMENTATION_STATUS.md](FFI_IMPLEMENTATION_STATUS.md) for detailed implementation status.
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Examples
|
|
357
|
+
|
|
358
|
+
### Example 1: Extract Text from All Pages
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
import { Document } from 'micropdf';
|
|
362
|
+
|
|
363
|
+
const doc = Document.open('document.pdf');
|
|
364
|
+
|
|
365
|
+
for (let i = 0; i < doc.pageCount; i++) {
|
|
366
|
+
const page = doc.loadPage(i);
|
|
367
|
+
const text = page.extractText();
|
|
368
|
+
|
|
369
|
+
console.log(`\n=== Page ${i + 1} ===`);
|
|
370
|
+
console.log(text);
|
|
371
|
+
|
|
372
|
+
page.drop();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
doc.close();
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Example 2: Create Thumbnails
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
import { Document, Matrix, Colorspace } from 'micropdf';
|
|
382
|
+
import { writeFileSync } from 'fs';
|
|
383
|
+
|
|
384
|
+
const doc = Document.open('document.pdf');
|
|
385
|
+
|
|
386
|
+
for (let i = 0; i < Math.min(5, doc.pageCount); i++) {
|
|
387
|
+
const page = doc.loadPage(i);
|
|
388
|
+
|
|
389
|
+
// Render at thumbnail size (scale down to 0.2x)
|
|
390
|
+
const matrix = Matrix.scale(0.2, 0.2);
|
|
391
|
+
const pixmap = page.toPixmap(matrix, Colorspace.deviceRGB(), false);
|
|
392
|
+
|
|
393
|
+
// Save as PNG
|
|
394
|
+
const pngData = page.toPNG(36); // 36 DPI
|
|
395
|
+
writeFileSync(`thumb_${i}.png`, pngData);
|
|
396
|
+
|
|
397
|
+
console.log(`Created thumbnail ${i}: ${pixmap.width}x${pixmap.height}`);
|
|
398
|
+
|
|
399
|
+
page.drop();
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
doc.close();
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### Example 3: Search and Extract Context
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
import { Document } from 'micropdf';
|
|
409
|
+
|
|
410
|
+
function findTextWithContext(doc: Document, searchTerm: string) {
|
|
411
|
+
const results = [];
|
|
412
|
+
|
|
413
|
+
for (let i = 0; i < doc.pageCount; i++) {
|
|
414
|
+
const page = doc.loadPage(i);
|
|
415
|
+
const hits = page.searchText(searchTerm);
|
|
416
|
+
|
|
417
|
+
if (hits.length > 0) {
|
|
418
|
+
const text = page.extractText();
|
|
419
|
+
results.push({
|
|
420
|
+
page: i + 1,
|
|
421
|
+
hits: hits.length,
|
|
422
|
+
text: text.substring(0, 200) // First 200 chars
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
page.drop();
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return results;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const doc = Document.open('document.pdf');
|
|
433
|
+
const results = findTextWithContext(doc, 'confidential');
|
|
434
|
+
|
|
435
|
+
results.forEach((r) => {
|
|
436
|
+
console.log(`Page ${r.page}: ${r.hits} occurrences`);
|
|
437
|
+
console.log(`Context: ${r.text}...`);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
doc.close();
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Example 4: Batch Processing
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
import { Document } from 'micropdf';
|
|
447
|
+
import { readdirSync } from 'fs';
|
|
448
|
+
|
|
449
|
+
function processPDFs(directory: string) {
|
|
450
|
+
const files = readdirSync(directory).filter((f) => f.endsWith('.pdf'));
|
|
451
|
+
|
|
452
|
+
const stats = [];
|
|
453
|
+
|
|
454
|
+
for (const file of files) {
|
|
455
|
+
const doc = Document.open(`${directory}/${file}`);
|
|
456
|
+
|
|
457
|
+
stats.push({
|
|
458
|
+
file,
|
|
459
|
+
pages: doc.pageCount,
|
|
460
|
+
title: doc.getMetadata('Title'),
|
|
461
|
+
author: doc.getMetadata('Author'),
|
|
462
|
+
encrypted: doc.needsPassword()
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
doc.close();
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return stats;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const stats = processPDFs('./pdfs');
|
|
472
|
+
console.table(stats);
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Example 5: Using Geometry Operations
|
|
476
|
+
|
|
477
|
+
```typescript
|
|
478
|
+
import { Point, Rect, Matrix } from 'micropdf';
|
|
479
|
+
|
|
480
|
+
// Transform a point
|
|
481
|
+
const point = new Point(100, 200);
|
|
482
|
+
const matrix = Matrix.rotate(45).concat(Matrix.scale(2, 2));
|
|
483
|
+
const transformed = point.transform(matrix);
|
|
484
|
+
|
|
485
|
+
console.log(`Original: (${point.x}, ${point.y})`);
|
|
486
|
+
console.log(`Transformed: (${transformed.x}, ${transformed.y})`);
|
|
487
|
+
|
|
488
|
+
// Check if point is in rectangle
|
|
489
|
+
const rect = new Rect(0, 0, 300, 400);
|
|
490
|
+
console.log(`Contains point: ${rect.contains(100, 200)}`); // true
|
|
491
|
+
|
|
492
|
+
// Rectangle union and intersection
|
|
493
|
+
const rect1 = new Rect(0, 0, 100, 100);
|
|
494
|
+
const rect2 = new Rect(50, 50, 150, 150);
|
|
495
|
+
|
|
496
|
+
const union = rect1.union(rect2);
|
|
497
|
+
const intersection = rect1.intersect(rect2);
|
|
498
|
+
|
|
499
|
+
console.log(`Union: ${union.width} x ${union.height}`);
|
|
500
|
+
console.log(`Intersection: ${intersection.width} x ${intersection.height}`);
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
505
|
+
## API Reference
|
|
506
|
+
|
|
507
|
+
### Document Class
|
|
508
|
+
|
|
509
|
+
```typescript
|
|
510
|
+
class Document {
|
|
511
|
+
// Opening documents
|
|
512
|
+
static open(path: string, password?: string): Document;
|
|
513
|
+
static fromBuffer(buffer: Buffer, password?: string): Document;
|
|
514
|
+
static fromUint8Array(data: Uint8Array, password?: string): Document;
|
|
515
|
+
|
|
516
|
+
// Properties
|
|
517
|
+
get pageCount(): number;
|
|
518
|
+
get format(): string;
|
|
519
|
+
get needsPassword(): boolean;
|
|
520
|
+
get isAuthenticated(): boolean;
|
|
521
|
+
|
|
522
|
+
// Methods
|
|
523
|
+
loadPage(pageNum: number): Page;
|
|
524
|
+
getMetadata(key: string): string | null;
|
|
525
|
+
setMetadata(key: string, value: string): void;
|
|
526
|
+
authenticate(password: string): boolean;
|
|
527
|
+
hasPermission(permission: number): boolean;
|
|
528
|
+
save(path: string): void;
|
|
529
|
+
write(): Buffer;
|
|
530
|
+
close(): void;
|
|
531
|
+
}
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Page Class
|
|
535
|
+
|
|
536
|
+
```typescript
|
|
537
|
+
class Page {
|
|
538
|
+
// Properties
|
|
539
|
+
get pageNumber(): number;
|
|
540
|
+
get bounds(): Rect;
|
|
541
|
+
get mediaBox(): Rect;
|
|
542
|
+
get cropBox(): Rect;
|
|
543
|
+
get rotation(): number;
|
|
544
|
+
|
|
545
|
+
// Rendering
|
|
546
|
+
toPixmap(matrix?: MatrixLike, colorspace?: Colorspace, alpha?: boolean): Pixmap;
|
|
547
|
+
toPNG(dpi?: number): Uint8Array;
|
|
548
|
+
|
|
549
|
+
// Text extraction
|
|
550
|
+
extractText(): string;
|
|
551
|
+
extractTextBlocks(): TextBlock[];
|
|
552
|
+
searchText(needle: string, caseSensitive?: boolean): Rect[];
|
|
553
|
+
|
|
554
|
+
// Links
|
|
555
|
+
getLinks(): Link[];
|
|
556
|
+
|
|
557
|
+
// Lifecycle
|
|
558
|
+
drop(): void;
|
|
559
|
+
}
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### Geometry Classes
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
class Point {
|
|
566
|
+
constructor(x: number, y: number);
|
|
567
|
+
transform(matrix: MatrixLike): Point;
|
|
568
|
+
distanceTo(other: PointLike): number;
|
|
569
|
+
add(other: PointLike): Point;
|
|
570
|
+
subtract(other: PointLike): Point;
|
|
571
|
+
scale(factor: number): Point;
|
|
572
|
+
normalize(): Point;
|
|
573
|
+
get length(): number;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
class Rect {
|
|
577
|
+
constructor(x0: number, y0: number, x1: number, y1: number);
|
|
578
|
+
static fromXYWH(x: number, y: number, width: number, height: number): Rect;
|
|
579
|
+
get width(): number;
|
|
580
|
+
get height(): number;
|
|
581
|
+
get isEmpty(): boolean;
|
|
582
|
+
contains(x: number, y: number): boolean;
|
|
583
|
+
containsRect(other: RectLike): boolean;
|
|
584
|
+
intersects(other: RectLike): boolean;
|
|
585
|
+
union(other: RectLike): Rect;
|
|
586
|
+
intersect(other: RectLike): Rect;
|
|
587
|
+
transform(matrix: MatrixLike): Rect;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
class Matrix {
|
|
591
|
+
static readonly IDENTITY: Matrix;
|
|
592
|
+
static translate(tx: number, ty: number): Matrix;
|
|
593
|
+
static scale(sx: number, sy: number): Matrix;
|
|
594
|
+
static rotate(degrees: number): Matrix;
|
|
595
|
+
static shear(sx: number, sy: number): Matrix;
|
|
596
|
+
|
|
597
|
+
concat(other: MatrixLike): Matrix;
|
|
598
|
+
preTranslate(tx: number, ty: number): Matrix;
|
|
599
|
+
postScale(sx: number, sy: number): Matrix;
|
|
600
|
+
invert(): Matrix | null;
|
|
601
|
+
isIdentity(): boolean;
|
|
602
|
+
isRectilinear(): boolean;
|
|
603
|
+
}
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### Buffer Class
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
class Buffer {
|
|
610
|
+
static create(capacity?: number): Buffer;
|
|
611
|
+
static fromString(str: string, encoding?: BufferEncoding): Buffer;
|
|
612
|
+
static fromBuffer(data: globalThis.Buffer): Buffer;
|
|
613
|
+
static fromUint8Array(data: Uint8Array): Buffer;
|
|
614
|
+
|
|
615
|
+
get length(): number;
|
|
616
|
+
get isEmpty(): boolean;
|
|
617
|
+
|
|
618
|
+
append(data: BufferLike | string): this;
|
|
619
|
+
clear(): this;
|
|
620
|
+
slice(start: number, end?: number): Buffer;
|
|
621
|
+
toNodeBuffer(): globalThis.Buffer;
|
|
622
|
+
toUint8Array(): Uint8Array;
|
|
623
|
+
toString(encoding?: BufferEncoding): string;
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
### Colorspace Class
|
|
628
|
+
|
|
629
|
+
```typescript
|
|
630
|
+
class Colorspace {
|
|
631
|
+
static deviceGray(): Colorspace;
|
|
632
|
+
static deviceRGB(): Colorspace;
|
|
633
|
+
static deviceBGR(): Colorspace;
|
|
634
|
+
static deviceCMYK(): Colorspace;
|
|
635
|
+
|
|
636
|
+
get name(): string;
|
|
637
|
+
get n(): number; // Number of components
|
|
638
|
+
get type(): ColorspaceType;
|
|
639
|
+
|
|
640
|
+
convertColor(destColorspace: Colorspace, srcValues: number[]): number[];
|
|
641
|
+
}
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Pixmap Class
|
|
645
|
+
|
|
646
|
+
```typescript
|
|
647
|
+
class Pixmap {
|
|
648
|
+
static create(colorspace: Colorspace, width: number, height: number, alpha?: boolean): Pixmap;
|
|
649
|
+
static createWithBbox(colorspace: Colorspace, bbox: IRectLike, alpha?: boolean): Pixmap;
|
|
650
|
+
static fromSamples(
|
|
651
|
+
colorspace: Colorspace,
|
|
652
|
+
width: number,
|
|
653
|
+
height: number,
|
|
654
|
+
alpha: boolean,
|
|
655
|
+
samples: Uint8Array
|
|
656
|
+
): Pixmap;
|
|
657
|
+
|
|
658
|
+
get width(): number;
|
|
659
|
+
get height(): number;
|
|
660
|
+
get n(): number; // Components including alpha
|
|
661
|
+
get alpha(): boolean;
|
|
662
|
+
get colorspace(): Colorspace;
|
|
663
|
+
get samples(): Uint8Array;
|
|
664
|
+
|
|
665
|
+
getPixel(x: number, y: number): number[];
|
|
666
|
+
setPixel(x: number, y: number, values: number[]): void;
|
|
667
|
+
clear(): void;
|
|
668
|
+
invert(): void;
|
|
669
|
+
convert(destColorspace: Colorspace): Pixmap;
|
|
670
|
+
scale(width: number, height: number): Pixmap;
|
|
671
|
+
toRGBA(): Uint8Array;
|
|
672
|
+
|
|
673
|
+
keep(): this;
|
|
674
|
+
drop(): void;
|
|
675
|
+
}
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
680
|
+
## Building from Source
|
|
681
|
+
|
|
682
|
+
If prebuilt binaries are not available for your platform, or you want to build from source:
|
|
683
|
+
|
|
684
|
+
### Prerequisites
|
|
685
|
+
|
|
686
|
+
1. **Node.js** >= 18.0.0
|
|
687
|
+
2. **Rust toolchain** (install from [rustup.rs](https://rustup.rs))
|
|
688
|
+
3. **Build tools**:
|
|
689
|
+
- Linux: `build-essential`, `pkg-config`
|
|
690
|
+
- macOS: Xcode Command Line Tools
|
|
691
|
+
- Windows: Visual Studio Build Tools
|
|
692
|
+
|
|
693
|
+
### Build Steps
|
|
694
|
+
|
|
695
|
+
```bash
|
|
696
|
+
# Clone the repository
|
|
697
|
+
git clone https://github.com/yourusername/micropdf.git
|
|
698
|
+
cd micropdf/micropdf-js
|
|
699
|
+
|
|
700
|
+
# Install dependencies
|
|
701
|
+
pnpm install
|
|
702
|
+
|
|
703
|
+
# Build the Rust library
|
|
704
|
+
cd ../micropdf-rs
|
|
705
|
+
cargo build --release
|
|
706
|
+
|
|
707
|
+
# Copy library to Node.js project
|
|
708
|
+
cd ../micropdf-js
|
|
709
|
+
mkdir -p native/lib/$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)
|
|
710
|
+
cp ../micropdf-rs/target/release/libmicropdf.a native/lib/*/
|
|
711
|
+
|
|
712
|
+
# Build TypeScript
|
|
713
|
+
pnpm run build:ts
|
|
714
|
+
|
|
715
|
+
# Build native addon
|
|
716
|
+
pnpm run build:native
|
|
717
|
+
|
|
718
|
+
# Run tests
|
|
719
|
+
pnpm test
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
## Development
|
|
725
|
+
|
|
726
|
+
### Running Tests
|
|
727
|
+
|
|
728
|
+
```bash
|
|
729
|
+
# Run all tests
|
|
730
|
+
pnpm test
|
|
731
|
+
|
|
732
|
+
# Run specific test file
|
|
733
|
+
pnpm test -- path.test.ts
|
|
734
|
+
|
|
735
|
+
# Run with coverage
|
|
736
|
+
pnpm test:coverage
|
|
737
|
+
|
|
738
|
+
# Run integration tests
|
|
739
|
+
pnpm test:integration
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
### Linting and Formatting
|
|
743
|
+
|
|
744
|
+
```bash
|
|
745
|
+
# Run ESLint
|
|
746
|
+
pnpm lint
|
|
747
|
+
|
|
748
|
+
# Fix linting issues
|
|
749
|
+
pnpm lint:fix
|
|
750
|
+
|
|
751
|
+
# Run Prettier
|
|
752
|
+
pnpm format
|
|
753
|
+
|
|
754
|
+
# Check formatting
|
|
755
|
+
pnpm format:check
|
|
756
|
+
|
|
757
|
+
# Run all quality checks
|
|
758
|
+
pnpm quality
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
### Docker Testing
|
|
762
|
+
|
|
763
|
+
```bash
|
|
764
|
+
# Build and test in Docker
|
|
765
|
+
cd docker
|
|
766
|
+
./build-test.sh
|
|
767
|
+
|
|
768
|
+
# Run with coverage
|
|
769
|
+
./build-test.sh --coverage
|
|
770
|
+
|
|
771
|
+
# Interactive shell
|
|
772
|
+
./build-test.sh --shell
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
---
|
|
776
|
+
|
|
777
|
+
## Troubleshooting
|
|
778
|
+
|
|
779
|
+
### Binary Not Available
|
|
780
|
+
|
|
781
|
+
If you see an error about missing prebuilt binaries:
|
|
782
|
+
|
|
783
|
+
```
|
|
784
|
+
Error: Cannot find module './build/Release/micropdf.node'
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
**Solution**: Build from source following the [Building from Source](#building-from-source) instructions.
|
|
788
|
+
|
|
789
|
+
### Rust Compilation Errors
|
|
790
|
+
|
|
791
|
+
If you encounter errors building the Rust library:
|
|
792
|
+
|
|
793
|
+
```bash
|
|
794
|
+
# Update Rust toolchain
|
|
795
|
+
rustup update stable
|
|
796
|
+
|
|
797
|
+
# Clean and rebuild
|
|
798
|
+
cd micropdf-rs
|
|
799
|
+
cargo clean
|
|
800
|
+
cargo build --release
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
### Node-gyp Errors
|
|
804
|
+
|
|
805
|
+
If `node-gyp` fails to build the native addon:
|
|
806
|
+
|
|
807
|
+
**Linux/macOS**:
|
|
808
|
+
|
|
809
|
+
```bash
|
|
810
|
+
# Install build tools
|
|
811
|
+
sudo apt-get install build-essential # Ubuntu/Debian
|
|
812
|
+
xcode-select --install # macOS
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
**Windows**:
|
|
816
|
+
|
|
817
|
+
```bash
|
|
818
|
+
npm install --global windows-build-tools
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
### Memory Issues
|
|
822
|
+
|
|
823
|
+
If you encounter memory issues with large PDFs:
|
|
824
|
+
|
|
825
|
+
```typescript
|
|
826
|
+
// Process pages one at a time and clean up
|
|
827
|
+
for (let i = 0; i < doc.pageCount; i++) {
|
|
828
|
+
const page = doc.loadPage(i);
|
|
829
|
+
// Process page...
|
|
830
|
+
page.drop(); // Important: free memory
|
|
831
|
+
}
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
### Permission Errors
|
|
835
|
+
|
|
836
|
+
If you get permission errors opening PDFs:
|
|
837
|
+
|
|
838
|
+
```typescript
|
|
839
|
+
const doc = Document.open('document.pdf');
|
|
840
|
+
|
|
841
|
+
if (doc.needsPassword()) {
|
|
842
|
+
if (!doc.authenticate('password')) {
|
|
843
|
+
throw new Error('Invalid password');
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// Check specific permission
|
|
848
|
+
if (!doc.hasPermission(4)) {
|
|
849
|
+
// FZ_PERMISSION_PRINT
|
|
850
|
+
console.warn('Document does not allow printing');
|
|
851
|
+
}
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
---
|
|
855
|
+
|
|
856
|
+
## Performance Tips
|
|
857
|
+
|
|
858
|
+
1. **Always clean up resources**:
|
|
859
|
+
|
|
860
|
+
```typescript
|
|
861
|
+
const page = doc.loadPage(0);
|
|
862
|
+
try {
|
|
863
|
+
// Work with page
|
|
864
|
+
} finally {
|
|
865
|
+
page.drop(); // Always clean up!
|
|
866
|
+
}
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
2. **Use appropriate DPI for rendering**:
|
|
870
|
+
|
|
871
|
+
```typescript
|
|
872
|
+
// For thumbnails: 36-72 DPI
|
|
873
|
+
const thumb = page.toPNG(72);
|
|
874
|
+
|
|
875
|
+
// For screen display: 96-144 DPI
|
|
876
|
+
const display = page.toPNG(144);
|
|
877
|
+
|
|
878
|
+
// For printing: 300+ DPI
|
|
879
|
+
const print = page.toPNG(300);
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
3. **Batch process efficiently**:
|
|
883
|
+
|
|
884
|
+
```typescript
|
|
885
|
+
// Bad: Opens/closes document repeatedly
|
|
886
|
+
for (const file of files) {
|
|
887
|
+
const doc = Document.open(file);
|
|
888
|
+
// process...
|
|
889
|
+
doc.close();
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// Good: Reuse context when possible
|
|
893
|
+
const docs = files.map((f) => Document.open(f));
|
|
894
|
+
for (const doc of docs) {
|
|
895
|
+
// process...
|
|
896
|
+
}
|
|
897
|
+
docs.forEach((d) => d.close());
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
---
|
|
901
|
+
|
|
902
|
+
## Contributing
|
|
903
|
+
|
|
904
|
+
Contributions are welcome! Please see our [Contributing Guidelines](CONTRIBUTING.md) (if available).
|
|
905
|
+
|
|
906
|
+
### Development Workflow
|
|
907
|
+
|
|
908
|
+
1. Fork the repository
|
|
909
|
+
2. Create a feature branch: `git checkout -b feature/my-feature`
|
|
910
|
+
3. Make your changes
|
|
911
|
+
4. Run tests: `pnpm test`
|
|
912
|
+
5. Run linting: `pnpm lint`
|
|
913
|
+
6. Commit changes: `git commit -m "feat: add my feature"`
|
|
914
|
+
7. Push to your fork: `git push origin feature/my-feature`
|
|
915
|
+
8. Create a Pull Request
|
|
916
|
+
|
|
917
|
+
---
|
|
918
|
+
|
|
919
|
+
## License
|
|
920
|
+
|
|
921
|
+
Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for details.
|
|
922
|
+
|
|
923
|
+
---
|
|
924
|
+
|
|
925
|
+
## Acknowledgments
|
|
926
|
+
|
|
927
|
+
- Built on top of [MuPDF](https://mupdf.com/) - a lightweight PDF and XPS viewer
|
|
928
|
+
- Inspired by [pdf-lib](https://pdf-lib.js.org/) and [pdfjs](https://mozilla.github.io/pdf.js/)
|
|
929
|
+
|
|
930
|
+
---
|
|
931
|
+
|
|
932
|
+
## Support
|
|
933
|
+
|
|
934
|
+
- 📚 **Documentation**: See JSDoc comments in your IDE
|
|
935
|
+
- 🐛 **Issues**: [GitHub Issues](https://github.com/yourusername/micropdf/issues)
|
|
936
|
+
- 💬 **Discussions**: [GitHub Discussions](https://github.com/yourusername/micropdf/discussions)
|
|
937
|
+
|
|
938
|
+
---
|
|
939
|
+
|
|
940
|
+
## Status & Roadmap
|
|
941
|
+
|
|
942
|
+
### ✅ Rust Core: 100% MuPDF Compatible!
|
|
943
|
+
|
|
944
|
+
The underlying Rust core now provides **complete MuPDF compatibility**:
|
|
945
|
+
|
|
946
|
+
- ✅ **PDF Content Stream Interpreter** - 60+ operators, full graphics state
|
|
947
|
+
- ✅ **Pixel Rendering Engine** - Scan-line rasterization, anti-aliasing
|
|
948
|
+
- ✅ **All Image Formats** - 8 PDF filters (Flate, LZW, JPEG, JPEG2000, JBIG2, etc.)
|
|
949
|
+
- ✅ **Font & Glyph Rendering** - TrueType, Type1, glyph caching
|
|
950
|
+
- ✅ **Structured Text Extraction** - Layout-aware, multi-language
|
|
951
|
+
- ✅ **Annotation Rendering** - 14 annotation types
|
|
952
|
+
- ✅ **AcroForm Support** - 7 form field types
|
|
953
|
+
- ✅ **PDF Encryption** - RC4, AES-128, AES-256
|
|
954
|
+
|
|
955
|
+
**Core Stats**: ~7,700 lines, 1,101 tests passing
|
|
956
|
+
|
|
957
|
+
### Current Node.js Bindings (v0.1.0)
|
|
958
|
+
|
|
959
|
+
- ✅ PDF reading and basic operations
|
|
960
|
+
- ✅ Page rendering to images
|
|
961
|
+
- ✅ Text extraction and search
|
|
962
|
+
- ✅ Geometry operations
|
|
963
|
+
- ✅ Password/security support
|
|
964
|
+
- ✅ Document metadata
|
|
965
|
+
- ⚠️ **In Progress**: Exposing new Rust core features via N-API
|
|
966
|
+
|
|
967
|
+
### Roadmap
|
|
968
|
+
|
|
969
|
+
- 🚀 **v0.2.0**: Expose structured text extraction API
|
|
970
|
+
- 🚀 **v0.3.0**: Expose annotation rendering API
|
|
971
|
+
- 🚀 **v0.4.0**: Expose form field rendering API
|
|
972
|
+
- 🚀 **v0.5.0**: Advanced rendering options (anti-aliasing, colorspace)
|
|
973
|
+
- 🎯 **v1.0.0**: Full API parity with 100% complete Rust core
|
|
974
|
+
|
|
975
|
+
The Rust core is production-ready! Node.js bindings are being updated to expose all features.
|
|
976
|
+
|
|
977
|
+
---
|
|
978
|
+
|
|
979
|
+
<div align="center">
|
|
980
|
+
|
|
981
|
+
**Made with ❤️ by the MicroPDF Team**
|
|
982
|
+
|
|
983
|
+
⭐ Star us on GitHub if you find this helpful!
|
|
984
|
+
|
|
985
|
+
</div>
|